diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/dto/request/CalculateCurrencyConversionRequestDTO.java b/mt-pay/src/main/java/com/mtkj/mtpay/dto/request/CalculateCurrencyConversionRequestDTO.java new file mode 100644 index 0000000..daeb8bb --- /dev/null +++ b/mt-pay/src/main/java/com/mtkj/mtpay/dto/request/CalculateCurrencyConversionRequestDTO.java @@ -0,0 +1,34 @@ +package com.mtkj.mtpay.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 计算货币转换请求DTO + */ +@Data +public class CalculateCurrencyConversionRequestDTO implements Serializable { + + /** + * 订单号 + */ + @NotBlank(message = "订单号不能为空") + private String orderNo; + + /** + * 原始货币代码 + */ + @NotBlank(message = "原始货币代码不能为空") + private String originalCurrency; + + /** + * 原始金额 + */ + @NotNull(message = "原始金额不能为空") + private BigDecimal originalAmount; +} + diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/dto/response/CreatePayPalOrderResponseDTO.java b/mt-pay/src/main/java/com/mtkj/mtpay/dto/response/CreatePayPalOrderResponseDTO.java new file mode 100644 index 0000000..57bfa04 --- /dev/null +++ b/mt-pay/src/main/java/com/mtkj/mtpay/dto/response/CreatePayPalOrderResponseDTO.java @@ -0,0 +1,29 @@ +package com.mtkj.mtpay.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * 创建PayPal订单响应DTO(包含货币转换信息) + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CreatePayPalOrderResponseDTO implements Serializable { + + /** + * PayPal订单信息 + */ + private PayPalOrderResponseDTO paypalOrder; + + /** + * 货币转换信息 + */ + private CurrencyConversionDTO currencyConversion; +} + diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/dto/response/CurrencyConversionDTO.java b/mt-pay/src/main/java/com/mtkj/mtpay/dto/response/CurrencyConversionDTO.java new file mode 100644 index 0000000..79812ac --- /dev/null +++ b/mt-pay/src/main/java/com/mtkj/mtpay/dto/response/CurrencyConversionDTO.java @@ -0,0 +1,61 @@ +package com.mtkj.mtpay.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 货币转换信息DTO + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CurrencyConversionDTO implements Serializable { + + /** + * 原始货币代码 + */ + private String originalCurrency; + + /** + * 原始金额 + */ + private BigDecimal originalAmount; + + /** + * 支付货币代码 + */ + private String paymentCurrency; + + /** + * 支付金额 + */ + private BigDecimal paymentAmount; + + /** + * 使用的汇率 + */ + private BigDecimal exchangeRate; + + /** + * 汇率锁定时间 + */ + private LocalDateTime rateLockedAt; + + /** + * 是否需要货币转换 + */ + private Boolean conversionRequired; + + /** + * 汇率说明文本 + */ + private String rateDescription; +} + diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/service/ExchangeRateService.java b/mt-pay/src/main/java/com/mtkj/mtpay/service/ExchangeRateService.java new file mode 100644 index 0000000..e3cd5fc --- /dev/null +++ b/mt-pay/src/main/java/com/mtkj/mtpay/service/ExchangeRateService.java @@ -0,0 +1,25 @@ +package com.mtkj.mtpay.service; + +/** + * 汇率服务接口 + */ +public interface ExchangeRateService { + + /** + * 获取汇率(从源货币转换为目标货币) + * @param fromCurrency 源货币代码 + * @param toCurrency 目标货币代码 + * @return 汇率(1单位源货币 = ?单位目标货币) + */ + Double getExchangeRate(String fromCurrency, String toCurrency); + + /** + * 转换货币金额 + * @param amount 原始金额 + * @param fromCurrency 源货币代码 + * @param toCurrency 目标货币代码 + * @return 转换后的金额 + */ + Double convertAmount(Double amount, String fromCurrency, String toCurrency); +} + diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/ExchangeRateServiceImpl.java b/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/ExchangeRateServiceImpl.java new file mode 100644 index 0000000..dbcb11c --- /dev/null +++ b/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/ExchangeRateServiceImpl.java @@ -0,0 +1,157 @@ +package com.mtkj.mtpay.service.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.mtkj.mtpay.service.ExchangeRateService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 汇率服务实现类 + * 使用 ExchangeRate-API 获取实时汇率 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class ExchangeRateServiceImpl implements ExchangeRateService { + + private static final String API_KEY = "f0a6cdaf139b53113ee2eb22"; + private static final String API_URL = "https://v6.exchangerate-api.com/v6/" + API_KEY + "/latest/USD"; + + // 汇率缓存(key: 货币代码, value: 相对于USD的汇率) + private final Map rateCache = new ConcurrentHashMap<>(); + private long cacheExpireTime = 0; + private static final long CACHE_DURATION = 24 * 60 * 60 * 1000L; // 24小时缓存 + + private final RestTemplate restTemplate = new RestTemplate(); + private final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 获取汇率(从源货币转换为目标货币) + */ + @Override + public Double getExchangeRate(String fromCurrency, String toCurrency) { + // 如果相同货币,返回1.0 + if (fromCurrency.equals(toCurrency)) { + return 1.0; + } + + // 刷新缓存(如果需要) + refreshCacheIfNeeded(); + + // 如果目标货币是USD,直接返回缓存中的汇率 + if ("USD".equals(toCurrency)) { + Double rate = rateCache.get(fromCurrency); + if (rate != null) { + return 1.0 / rate; // 转换为USD的汇率 + } + log.warn("货币 {} 的汇率未找到,使用默认汇率 1.0", fromCurrency); + return 1.0; + } + + // 如果源货币是USD,直接返回缓存中的汇率 + if ("USD".equals(fromCurrency)) { + Double rate = rateCache.get(toCurrency); + if (rate != null) { + return rate; // USD转换为目标货币的汇率 + } + log.warn("货币 {} 的汇率未找到,使用默认汇率 1.0", toCurrency); + return 1.0; + } + + // 其他情况:通过USD中转 + // fromCurrency -> USD -> toCurrency + Double fromRate = rateCache.get(fromCurrency); + Double toRate = rateCache.get(toCurrency); + + if (fromRate != null && toRate != null) { + return toRate / fromRate; // (1 USD / fromRate) * toRate = toRate / fromRate + } + + log.warn("货币 {} 或 {} 的汇率未找到,使用默认汇率 1.0", fromCurrency, toCurrency); + return 1.0; + } + + /** + * 转换货币金额 + */ + @Override + public Double convertAmount(Double amount, String fromCurrency, String toCurrency) { + Double rate = getExchangeRate(fromCurrency, toCurrency); + return amount * rate; + } + + /** + * 刷新汇率缓存 + */ + private void refreshCacheIfNeeded() { + long currentTime = System.currentTimeMillis(); + + // 如果缓存未过期,直接返回 + if (currentTime < cacheExpireTime && !rateCache.isEmpty()) { + return; + } + + log.info("刷新汇率缓存..."); + + try { + ResponseEntity response = restTemplate.getForEntity(API_URL, Map.class); + + if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) { + Map responseBody = response.getBody(); + + // 检查响应状态 + String result = (String) responseBody.get("result"); + if (!"success".equals(result)) { + log.error("汇率API返回失败: {}", responseBody); + return; + } + + // 获取汇率数据 + @SuppressWarnings("unchecked") + Map conversionRates = (Map) responseBody.get("conversion_rates"); + + if (conversionRates != null) { + // 清空旧缓存 + rateCache.clear(); + + // 填充新缓存 + conversionRates.forEach((currency, rate) -> { + if (rate instanceof Number) { + rateCache.put(currency, ((Number) rate).doubleValue()); + } + }); + + // 设置缓存过期时间(24小时后) + cacheExpireTime = currentTime + CACHE_DURATION; + + log.info("汇率缓存刷新成功,共 {} 种货币", rateCache.size()); + log.debug("示例汇率 - MYR: {}, CNY: {}, EUR: {}", + rateCache.get("MYR"), rateCache.get("CNY"), rateCache.get("EUR")); + } else { + log.error("汇率API响应中未找到conversion_rates字段"); + } + } else { + log.error("获取汇率失败,状态码: {}", response.getStatusCode()); + } + } catch (Exception e) { + log.error("刷新汇率缓存异常", e); + // 如果API调用失败,使用默认汇率(不更新缓存) + if (rateCache.isEmpty()) { + log.warn("汇率API调用失败,使用默认汇率"); + // 设置一些常用货币的默认汇率 + rateCache.put("MYR", 4.078); + rateCache.put("CNY", 7.0465); + rateCache.put("EUR", 0.851); + rateCache.put("GBP", 0.7434); + cacheExpireTime = currentTime + 60 * 60 * 1000L; // 1小时后重试 + } + } + } +} + diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/util/CountryAddressConfig.java b/mt-pay/src/main/java/com/mtkj/mtpay/util/CountryAddressConfig.java new file mode 100644 index 0000000..aa7bdaa --- /dev/null +++ b/mt-pay/src/main/java/com/mtkj/mtpay/util/CountryAddressConfig.java @@ -0,0 +1,195 @@ +package com.mtkj.mtpay.util; + +import lombok.Data; +import java.util.*; + +/** + * 国家地址配置工具类 + * 定义各国地址字段规则和邮编格式 + */ +public class CountryAddressConfig { + + /** + * 国家地址配置 + */ + @Data + public static class CountryConfig { + private String countryCode; // 国家代码 + private String countryName; // 国家名称 + private String countryNameEn; // 国家名称(英文) + private int postcodeLength; // 邮编长度 + private String postcodePattern; // 邮编格式(正则表达式) + private String phoneCode; // 国际区号(如 +65, +66) + private List requiredFields; // 必填字段列表 + private List specialFields; // 特殊字段列表 + private Map fieldLabels; // 字段标签(支持多语言) + private String addressFormat; // 地址格式说明 + } + + /** + * 获取国家配置 + */ + public static CountryConfig getCountryConfig(String countryCode) { + return COUNTRY_CONFIGS.getOrDefault(countryCode.toUpperCase(), DEFAULT_CONFIG); + } + + /** + * 获取所有支持的国家 + */ + public static Set getSupportedCountries() { + return COUNTRY_CONFIGS.keySet(); + } + + /** + * 验证邮编格式 + */ + public static boolean validatePostcode(String countryCode, String postcode) { + if (postcode == null || postcode.trim().isEmpty()) { + return false; + } + CountryConfig config = getCountryConfig(countryCode); + if (config.getPostcodePattern() == null) { + return postcode.length() == config.getPostcodeLength(); + } + return postcode.matches(config.getPostcodePattern()); + } + + /** + * 获取必填字段 + */ + public static List getRequiredFields(String countryCode) { + CountryConfig config = getCountryConfig(countryCode); + return config.getRequiredFields() != null ? new ArrayList<>(config.getRequiredFields()) : new ArrayList<>(); + } + + /** + * 获取特殊字段 + */ + public static List getSpecialFields(String countryCode) { + CountryConfig config = getCountryConfig(countryCode); + return config.getSpecialFields() != null ? new ArrayList<>(config.getSpecialFields()) : new ArrayList<>(); + } + + // 默认配置 + private static final CountryConfig DEFAULT_CONFIG = new CountryConfig(); + static { + DEFAULT_CONFIG.setCountryCode("DEFAULT"); + DEFAULT_CONFIG.setCountryName("默认"); + DEFAULT_CONFIG.setCountryNameEn("Default"); + DEFAULT_CONFIG.setPostcodeLength(6); + DEFAULT_CONFIG.setPostcodePattern(null); + DEFAULT_CONFIG.setPhoneCode("+86"); + DEFAULT_CONFIG.setRequiredFields(Arrays.asList("shippingName", "shippingPhone", "shippingCountry", + "shippingCity", "shippingAddressLine1")); + DEFAULT_CONFIG.setSpecialFields(new ArrayList<>()); + } + + // 国家配置映射 + private static final Map COUNTRY_CONFIGS = new HashMap<>(); + + static { + // 新加坡配置 + CountryConfig sg = new CountryConfig(); + sg.setCountryCode("SG"); + sg.setCountryName("新加坡"); + sg.setCountryNameEn("Singapore"); + sg.setPostcodeLength(6); + sg.setPostcodePattern("^\\d{6}$"); + sg.setPhoneCode("+65"); + sg.setRequiredFields(Arrays.asList("shippingName", "shippingPhone", "shippingCountry", + "shippingCity", "shippingAddressLine1", "shippingBlockNumber", "shippingUnitNumber", "shippingPostcode")); + sg.setSpecialFields(Arrays.asList("shippingBlockNumber", "shippingUnitNumber")); + Map sgLabels = new HashMap<>(); + sgLabels.put("shippingBlockNumber", "组屋号 (Block Number)"); + sgLabels.put("shippingUnitNumber", "单元号 (Unit Number)"); + sgLabels.put("shippingAddressLine1", "详细地址1 (Address Line 1)"); + sgLabels.put("shippingAddressLine2", "详细地址2 (Address Line 2)"); + sg.setFieldLabels(sgLabels); + sg.setAddressFormat("Blk 123 Jurong West St 41 #12-345, Singapore 640123"); + COUNTRY_CONFIGS.put("SG", sg); + + // 马来西亚配置 + CountryConfig my = new CountryConfig(); + my.setCountryCode("MY"); + my.setCountryName("马来西亚"); + my.setCountryNameEn("Malaysia"); + my.setPostcodeLength(5); + my.setPostcodePattern("^\\d{5}$"); + my.setPhoneCode("+60"); + my.setRequiredFields(Arrays.asList("shippingName", "shippingPhone", "shippingCountry", + "shippingCity", "shippingStateMalaysia", "shippingAddressLine1", "shippingPostcode")); + my.setSpecialFields(Arrays.asList("shippingStateMalaysia")); + Map myLabels = new HashMap<>(); + myLabels.put("shippingStateMalaysia", "州属 (State)"); + myLabels.put("shippingAddressLine1", "详细地址1 (Address Line 1)"); + myLabels.put("shippingAddressLine2", "详细地址2 (Address Line 2)"); + my.setFieldLabels(myLabels); + my.setAddressFormat("123 Jalan Abdullah, 05-01 Menara A, Kuala Lumpur, Selangor 50300"); + COUNTRY_CONFIGS.put("MY", my); + + // 菲律宾配置 + CountryConfig ph = new CountryConfig(); + ph.setCountryCode("PH"); + ph.setCountryName("菲律宾"); + ph.setCountryNameEn("Philippines"); + ph.setPostcodeLength(4); + ph.setPostcodePattern("^\\d{4}$"); + ph.setPhoneCode("+63"); + ph.setRequiredFields(Arrays.asList("shippingName", "shippingPhone", "shippingCountry", + "shippingCity", "shippingState", "shippingBarangay", "shippingAddressLine1", "shippingPostcode")); + ph.setSpecialFields(Arrays.asList("shippingBarangay")); + Map phLabels = new HashMap<>(); + phLabels.put("shippingBarangay", "Barangay(社区编号)"); + phLabels.put("shippingState", "省 (Province)"); + phLabels.put("shippingCity", "市 (City)"); + phLabels.put("shippingAddressLine1", "详细地址1 (Address Line 1)"); + phLabels.put("shippingAddressLine2", "详细地址2 (Address Line 2)"); + ph.setFieldLabels(phLabels); + ph.setAddressFormat("123 Main St, Barangay 12, Manila, Metro Manila 1000"); + COUNTRY_CONFIGS.put("PH", ph); + + // 泰国配置 + CountryConfig th = new CountryConfig(); + th.setCountryCode("TH"); + th.setCountryName("泰国"); + th.setCountryNameEn("Thailand"); + th.setPostcodeLength(5); + th.setPostcodePattern("^\\d{5}$"); + th.setPhoneCode("+66"); + th.setRequiredFields(Arrays.asList("shippingName", "shippingPhone", "shippingCountry", + "shippingCity", "shippingState", "shippingAddressLine1", "shippingPostcode")); + th.setSpecialFields(Arrays.asList("shippingAddressThai")); + Map thLabels = new HashMap<>(); + thLabels.put("shippingAddressThai", "泰文地址 (Thai Address)"); + thLabels.put("shippingAddressLine1", "英文地址 (English Address)"); + thLabels.put("shippingAddressLine2", "详细地址2 (Address Line 2)"); + thLabels.put("shippingState", "府 (Changwat)"); + thLabels.put("shippingCity", "县 (Amphoe)"); + thLabels.put("shippingAdministrativeArea", "区 (Tambon)"); + th.setFieldLabels(thLabels); + th.setAddressFormat("123 Soi Sukhumvit 101, Khlong Toei, Bangkok 10110"); + COUNTRY_CONFIGS.put("TH", th); + + // 越南配置 + CountryConfig vn = new CountryConfig(); + vn.setCountryCode("VN"); + vn.setCountryName("越南"); + vn.setCountryNameEn("Vietnam"); + vn.setPostcodeLength(5); + vn.setPostcodePattern("^\\d{5}$"); + vn.setPhoneCode("+84"); + vn.setRequiredFields(Arrays.asList("shippingName", "shippingPhone", "shippingCountry", + "shippingProvince", "shippingDistrict", "shippingWard", "shippingAddressLine1", "shippingPostcode")); + vn.setSpecialFields(Arrays.asList("shippingProvince", "shippingDistrict", "shippingWard")); + Map vnLabels = new HashMap<>(); + vnLabels.put("shippingProvince", "省 (Tỉnh)"); + vnLabels.put("shippingDistrict", "市/郡 (Thành phố/Huyện)"); + vnLabels.put("shippingWard", "区/坊 (Quận/Phường)"); + vnLabels.put("shippingAddressLine1", "详细地址1 (Địa chỉ chi tiết 1)"); + vnLabels.put("shippingAddressLine2", "详细地址2 (Địa chỉ chi tiết 2)"); + vn.setFieldLabels(vnLabels); + vn.setAddressFormat("123 Đường Nguyễn Huệ, Phường Bến Nghé, Quận 1, Thành phố Hồ Chí Minh 70000"); + COUNTRY_CONFIGS.put("VN", vn); + } +} + diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/util/HttpGet.java b/mt-pay/src/main/java/com/mtkj/mtpay/util/HttpGet.java new file mode 100644 index 0000000..dd6020f --- /dev/null +++ b/mt-pay/src/main/java/com/mtkj/mtpay/util/HttpGet.java @@ -0,0 +1,146 @@ +package com.mtkj.mtpay.util; + +import java.io.BufferedReader; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLEncoder; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Map; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +/** + * HTTP GET请求工具类 + */ +class HttpGet { + protected static final int SOCKET_TIMEOUT = 10000; + protected static final String GET = "GET"; + private static TrustManager myX509TrustManager = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + }; + + public static String get(String host, Map params) { + try { + SSLContext sslcontext = SSLContext.getInstance("TLS"); + sslcontext.init((KeyManager[])null, new TrustManager[]{myX509TrustManager}, (SecureRandom)null); + String sendUrl = getUrlWithQueryString(host, params); + URL uri = new URL(sendUrl); + HttpURLConnection conn = (HttpURLConnection)uri.openConnection(); + if (conn instanceof HttpsURLConnection) { + ((HttpsURLConnection)conn).setSSLSocketFactory(sslcontext.getSocketFactory()); + } + + conn.setConnectTimeout(10000); + conn.setRequestMethod("GET"); + int statusCode = conn.getResponseCode(); + if (statusCode != 200) { + System.out.println("Http错误码:" + statusCode); + } + + InputStream is = conn.getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + StringBuilder builder = new StringBuilder(); + String line = null; + + while((line = br.readLine()) != null) { + builder.append(line); + } + + String text = builder.toString(); + close(br); + close(is); + conn.disconnect(); + return text; + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (KeyManagementException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + + return null; + } + + public static String getUrlWithQueryString(String url, Map params) { + if (url == null || url.trim().isEmpty()) { + throw new IllegalArgumentException("URL cannot be null or empty"); + } + if (params == null) { + return url; + } else { + StringBuilder builder = new StringBuilder(url); + if (url.contains("?")) { + builder.append("&"); + } else { + builder.append("?"); + } + + int i = 0; + + for(String key : params.keySet()) { + String value = (String)params.get(key); + if (value != null) { + if (i != 0) { + builder.append('&'); + } + + builder.append(key); + builder.append('='); + builder.append(encode(value)); + ++i; + } + } + + return builder.toString(); + } + } + + protected static void close(Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } + + public static String encode(String input) { + if (input == null) { + return ""; + } else { + try { + return URLEncoder.encode(input, "utf-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return input; + } + } + } +} + diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/util/MD5.java b/mt-pay/src/main/java/com/mtkj/mtpay/util/MD5.java new file mode 100644 index 0000000..3eb4fc6 --- /dev/null +++ b/mt-pay/src/main/java/com/mtkj/mtpay/util/MD5.java @@ -0,0 +1,88 @@ +package com.mtkj.mtpay.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * MD5工具类 + */ +public class MD5 { + private static final char[] hexDigits = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + public static String md5(String input) { + if (input == null) { + return null; + } + try { + MessageDigest messageDigest = MessageDigest.getInstance("MD5"); + byte[] inputByteArray = input.getBytes(); + messageDigest.update(inputByteArray); + byte[] resultByteArray = messageDigest.digest(); + return byteArrayToHex(resultByteArray); + } catch (NoSuchAlgorithmException e) { + return null; + } + } + + public static String md5(File file) { + try { + if (!file.isFile()) { + System.err.println("文件" + file.getAbsolutePath() + "不存在或者不是文件"); + return null; + } + + FileInputStream in = new FileInputStream(file); + String result = md5((InputStream)in); + in.close(); + return result; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + public static String md5(InputStream in) { + try { + MessageDigest messagedigest = MessageDigest.getInstance("MD5"); + byte[] buffer = new byte[1024]; + int read = 0; + + while((read = in.read(buffer)) != -1) { + messagedigest.update(buffer, 0, read); + } + + in.close(); + String result = byteArrayToHex(messagedigest.digest()); + return result; + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + private static String byteArrayToHex(byte[] byteArray) { + char[] resultCharArray = new char[byteArray.length * 2]; + int index = 0; + + for(byte b : byteArray) { + resultCharArray[index++] = hexDigits[b >>> 4 & 15]; + resultCharArray[index++] = hexDigits[b & 15]; + } + + return new String(resultCharArray); + } +} +