From 61cfdecaf6b76acb27478e5901eb0908244e3875 Mon Sep 17 00:00:00 2001
From: sinake <sinake1@qq.com>
Date: 星期四, 15 十月 2026 16:36:54 +0800
Subject: [PATCH] 发票识别

---
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/HttpUtils.java          |  312 ++++++++++++++++++++++++
 ruoyi-admin/src/main/resources/application-druid.yml                            |   12 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java             |  288 ++++++++++++++++++++++
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java |  133 +++++++++
 ruoyi-admin/src/main/resources/application.yml                                  |    1 
 5 files changed, 736 insertions(+), 10 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
index 005f510..e6364fc 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@@ -1,26 +1,31 @@
 package com.ruoyi.web.controller.common;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.ruoyi.common.config.RuoYiConfig;
 import com.ruoyi.common.constant.Constants;
 import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.ChineseUtils;
 import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.file.FileUploadUtils;
 import com.ruoyi.common.utils.file.FileUtils;
 import com.ruoyi.framework.config.ServerConfig;
+import com.ruoyi.web.controller.tool.HttpUtils;
 import io.swagger.annotations.ApiOperation;
 import org.apache.catalina.connector.Connector;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.coyote.AbstractProtocol;
+import org.apache.http.HttpResponse;
+import org.apache.http.util.EntityUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.MediaType;
 import org.springframework.mock.web.MockMultipartFile;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.management.*;
@@ -28,7 +33,11 @@
 import javax.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.lang.management.ManagementFactory;
-import java.util.Set;
+import java.math.BigDecimal;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
 
 /**
  * 閫氱敤璇锋眰澶勭悊
@@ -42,6 +51,8 @@
     @Autowired
     private ServerConfig serverConfig;
 
+    @Value("${appcode}")
+    private String  appcode;
 
     /**
      * 閫氱敤涓嬭浇璇锋眰
@@ -120,6 +131,120 @@
         }
     }
 
+    public String aliOCR(String base64) {
+        String host = "https://mixedmulti.market.alicloudapi.com";
+        String path = "/ocrservice/mixedMultiInvoice";
+        String method = "POST";
+        Map<String, String> headers = new HashMap<String, String>();
+        //鏈�鍚庡湪header涓殑鏍煎紡(涓棿鏄嫳鏂囩┖鏍�)涓篈uthorization:APPCODE 83359fd73fe94948385f570e3c139105
+        headers.put("Authorization", "APPCODE " + appcode);
+        //鏍规嵁API鐨勮姹傦紝瀹氫箟鐩稿搴旂殑Content-Type
+        headers.put("Content-Type", "application/json; charset=UTF-8");
+        Map<String, String> querys = new HashMap<String, String>();
+        String bodys = "{\"img\":\""+base64+"\"}";
+
+
+        try {
+
+            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
+            System.out.println(response.toString());
+            //鑾峰彇response鐨刡ody
+            String content=EntityUtils.toString(response.getEntity());
+            JSONObject jsonContent=JSONObject.parseObject(content);
+            JSONArray subMsgs=jsonContent.getJSONArray("subMsgs");
+            List<Map<String,Object>> lists=new ArrayList<>();
+            for(Object row: subMsgs){
+                Map<String,Object> tempList=new HashMap<>();
+                JSONObject rowObject=(JSONObject)row;
+                tempList.put("鍙戠エ鍒嗙被",rowObject.getString("type"));
+                JSONObject result=((JSONObject)rowObject.get("result")).getJSONObject("data");
+                for(Map.Entry<String, Object> entry : result.entrySet()){
+                    tempList.put(entry.getKey(),entry.getValue());
+                }
+                if(rowObject.getString("type").equals("閾惰鎵垮厬姹囩エ")){
+                    BigDecimal totalAmount= ChineseUtils.chineseToNumber(result.getString("绁ㄦ嵁閲戦澶у啓"));
+                    tempList.put("鍙戠エ閲戦",totalAmount);
+                }
+                if(rowObject.getString("type").equals("鐏溅绁�")){
+                    tempList.put("鍙戠エ閲戦",result.getString("绁ㄤ环"));
+                }
+
+                lists.add(tempList);
+            }
+            System.out.println(content);
+            return JSON.toJSONString(lists);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "{}";
+        }
+    }
+
+    /**
+     * 閫氱敤涓婁紶璇锋眰
+     */
+    @ApiOperation("testOCR")
+    @PostMapping("/common/testOCR")
+    public AjaxResult testOCR(@RequestBody String fileName) throws Exception {
+        Path filePath= Paths.get(fileName);
+        String base64= Base64.getEncoder().encodeToString( Files.readAllBytes(filePath));
+
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("OCRList", aliOCR(base64));
+        return ajax;
+    }
+
+    /**
+     * 閫氱敤涓婁紶璇锋眰
+     */
+    @PostMapping("/common/uploadOCR")
+    public AjaxResult uploadOCR(MultipartFile file) throws Exception {
+
+        try {
+            // 涓婁紶鏂囦欢璺緞
+            String filePath = RuoYiConfig.getUploadPath();
+
+            //鍒ゆ柇鏂囦欢鏄惁瀛樺湪
+            String filename = file.getOriginalFilename().trim();
+            String felinamePath = FileUploadUtils.extractFilename(file);
+//            String pathFileName = FileUploadUtils.getPathFileName(filePath, s);
+            for (int i=1;i<500;i++) {
+                File file1 = new File(filePath + "/" + felinamePath);
+                boolean exists = file1.exists();
+                if (exists) {
+                    int index = filename.lastIndexOf(".");
+                    String startStr = filename.substring(0, index);
+                    String endStr = filename.substring(index, filename.length());
+
+                    String newFilename = startStr + "-" + i + endStr; // your new filename
+                    felinamePath = DateUtils.datePath() + "/" + newFilename;
+                    String contentType = file.getContentType();
+                    byte[] bytes = file.getBytes();
+                    file = new MockMultipartFile(newFilename, newFilename, contentType, bytes);
+                }else{
+                    break;
+                }
+            }
+            // 涓婁紶骞惰繑鍥炴柊鏂囦欢鍚嶇О
+            String fileName = FileUploadUtils.upload(filePath, file);
+            String url1 = serverConfig.getUrl();
+            log.info("url1鐨勫�紀ld :{}", url1);
+            if (url1.contains("8032")) {
+                //杩欓噷鐨�8032涓嶆槸tomcat鐨勶紝鎵�浠ヨ杞垚tomcat鐨�
+                url1 = url1.replace("8032", "8032/prod-api");
+            }
+            String base64= Base64.getEncoder().encodeToString(file.getBytes());
+
+            log.info("url1鐨勫�糿ew :{}", url1);
+            String url = url1 + fileName;
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put("fileName", fileName);
+            ajax.put("url", url);
+            ajax.put("OCRList", aliOCR(base64));
+            return ajax;
+        } catch (Exception e) {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
 
 //    private static void parseUTF(int[] bits) {
 //        int index = 0;//杩欎釜鎸囬拡鎸囧悜姣忎竴琛屽惊鐜椂鍒椾笅鏍囩殑浣嶇疆锛屼笅涓�琛屽紑濮嬫椂閲嶆柊缃綅0
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/HttpUtils.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/HttpUtils.java
new file mode 100644
index 0000000..55abda0
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/HttpUtils.java
@@ -0,0 +1,312 @@
+package com.ruoyi.web.controller.tool;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpDelete;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+
+public class HttpUtils {
+
+    /**
+     * get
+     *
+     * @param host
+     * @param path
+     * @param method
+     * @param headers
+     * @param querys
+     * @return
+     * @throws Exception
+     */
+    public static HttpResponse doGet(String host, String path, String method,
+                                     Map<String, String> headers,
+                                     Map<String, String> querys)
+            throws Exception {
+        HttpClient httpClient = wrapClient(host);
+
+        HttpGet request = new HttpGet(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+            request.addHeader(e.getKey(), e.getValue());
+        }
+
+        return httpClient.execute(request);
+    }
+
+    /**
+     * post form
+     *
+     * @param host
+     * @param path
+     * @param method
+     * @param headers
+     * @param querys
+     * @param bodys
+     * @return
+     * @throws Exception
+     */
+    public static HttpResponse doPost(String host, String path, String method,
+                                      Map<String, String> headers,
+                                      Map<String, String> querys,
+                                      Map<String, String> bodys)
+            throws Exception {
+        HttpClient httpClient = wrapClient(host);
+
+        HttpPost request = new HttpPost(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+            request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (bodys != null) {
+            List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();
+
+            for (String key : bodys.keySet()) {
+                nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));
+            }
+            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
+            formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
+            request.setEntity(formEntity);
+        }
+
+        return httpClient.execute(request);
+    }
+
+    /**
+     * Post String
+     *
+     * @param host
+     * @param path
+     * @param method
+     * @param headers
+     * @param querys
+     * @param body
+     * @return
+     * @throws Exception
+     */
+    public static HttpResponse doPost(String host, String path, String method,
+                                      Map<String, String> headers,
+                                      Map<String, String> querys,
+                                      String body)
+            throws Exception {
+        HttpClient httpClient = wrapClient(host);
+
+        HttpPost request = new HttpPost(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+            request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (StringUtils.isNotBlank(body)) {
+            request.setEntity(new StringEntity(body, "utf-8"));
+        }
+
+        return httpClient.execute(request);
+    }
+
+    /**
+     * Post stream
+     *
+     * @param host
+     * @param path
+     * @param method
+     * @param headers
+     * @param querys
+     * @param body
+     * @return
+     * @throws Exception
+     */
+    public static HttpResponse doPost(String host, String path, String method,
+                                      Map<String, String> headers,
+                                      Map<String, String> querys,
+                                      byte[] body)
+            throws Exception {
+        HttpClient httpClient = wrapClient(host);
+
+        HttpPost request = new HttpPost(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+            request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (body != null) {
+            request.setEntity(new ByteArrayEntity(body));
+        }
+
+        return httpClient.execute(request);
+    }
+
+    /**
+     * Put String
+     * @param host
+     * @param path
+     * @param method
+     * @param headers
+     * @param querys
+     * @param body
+     * @return
+     * @throws Exception
+     */
+    public static HttpResponse doPut(String host, String path, String method,
+                                     Map<String, String> headers,
+                                     Map<String, String> querys,
+                                     String body)
+            throws Exception {
+        HttpClient httpClient = wrapClient(host);
+
+        HttpPut request = new HttpPut(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+            request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (StringUtils.isNotBlank(body)) {
+            request.setEntity(new StringEntity(body, "utf-8"));
+        }
+
+        return httpClient.execute(request);
+    }
+
+    /**
+     * Put stream
+     * @param host
+     * @param path
+     * @param method
+     * @param headers
+     * @param querys
+     * @param body
+     * @return
+     * @throws Exception
+     */
+    public static HttpResponse doPut(String host, String path, String method,
+                                     Map<String, String> headers,
+                                     Map<String, String> querys,
+                                     byte[] body)
+            throws Exception {
+        HttpClient httpClient = wrapClient(host);
+
+        HttpPut request = new HttpPut(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+            request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (body != null) {
+            request.setEntity(new ByteArrayEntity(body));
+        }
+
+        return httpClient.execute(request);
+    }
+
+    /**
+     * Delete
+     *
+     * @param host
+     * @param path
+     * @param method
+     * @param headers
+     * @param querys
+     * @return
+     * @throws Exception
+     */
+    public static HttpResponse doDelete(String host, String path, String method,
+                                        Map<String, String> headers,
+                                        Map<String, String> querys)
+            throws Exception {
+        HttpClient httpClient = wrapClient(host);
+
+        HttpDelete request = new HttpDelete(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+            request.addHeader(e.getKey(), e.getValue());
+        }
+
+        return httpClient.execute(request);
+    }
+
+    private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
+        StringBuilder sbUrl = new StringBuilder();
+        sbUrl.append(host);
+        if (!StringUtils.isBlank(path)) {
+            sbUrl.append(path);
+        }
+        if (null != querys) {
+            StringBuilder sbQuery = new StringBuilder();
+            for (Map.Entry<String, String> query : querys.entrySet()) {
+                if (0 < sbQuery.length()) {
+                    sbQuery.append("&");
+                }
+                if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
+                    sbQuery.append(query.getValue());
+                }
+                if (!StringUtils.isBlank(query.getKey())) {
+                    sbQuery.append(query.getKey());
+                    if (!StringUtils.isBlank(query.getValue())) {
+                        sbQuery.append("=");
+                        sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
+                    }
+                }
+            }
+            if (0 < sbQuery.length()) {
+                sbUrl.append("?").append(sbQuery);
+            }
+        }
+
+        return sbUrl.toString();
+    }
+
+    private static HttpClient wrapClient(String host) {
+        HttpClient httpClient = new DefaultHttpClient();
+        if (host.startsWith("https://")) {
+            sslClient(httpClient);
+        }
+
+        return httpClient;
+    }
+
+    private static void sslClient(HttpClient httpClient) {
+        try {
+            SSLContext ctx = SSLContext.getInstance("TLS");
+            X509TrustManager tm = new X509TrustManager() {
+                public X509Certificate[] getAcceptedIssuers() {
+                    return null;
+                }
+                public void checkClientTrusted(X509Certificate[] xcs, String str) {
+
+                }
+                public void checkServerTrusted(X509Certificate[] xcs, String str) {
+
+                }
+            };
+            ctx.init(null, new TrustManager[] { tm }, null);
+            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
+            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+            ClientConnectionManager ccm = httpClient.getConnectionManager();
+            SchemeRegistry registry = ccm.getSchemeRegistry();
+            registry.register(new Scheme("https", 443, ssf));
+        } catch (KeyManagementException ex) {
+            throw new RuntimeException(ex);
+        } catch (NoSuchAlgorithmException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
diff --git a/ruoyi-admin/src/main/resources/application-druid.yml b/ruoyi-admin/src/main/resources/application-druid.yml
index 80c4781..cf4f697 100644
--- a/ruoyi-admin/src/main/resources/application-druid.yml
+++ b/ruoyi-admin/src/main/resources/application-druid.yml
@@ -7,12 +7,12 @@
       # 涓诲簱鏁版嵁婧�
       master:
         # 寮�鍙戠幆澧�
-        url: jdbc:mysql://127.0.0.1:3306/opo?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
-        username: root
-        password: sendohill
-#        url: jdbc:mysql://haiershi.a1.luyouxia.net:23844/opo?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
-#        username: smartor
-#        password: Smartor.2023
+#        url: jdbc:mysql://127.0.0.1:3306/opo?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
+#        username: root
+#        password: sendohill
+        url: jdbc:mysql://haiershi.a1.luyouxia.net:23844/opo?allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8
+        username: smartor
+        password: Smartor.2023
 
       # 浠庡簱鏁版嵁婧�
       slave:
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index a27b896..bc808e3 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -132,6 +132,7 @@
 #涓庡崗鍙嬩氦浜掔殑鏂板姛鑳藉紑鍏� 1寮�   2鍏�
 newSwitch: 1
 
+appcode: 07b7e4f573a54d97865abdeb3fc3408e
 
 
 
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java
index cd1b79e..f43a4da 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ChineseUtils.java
@@ -1,6 +1,47 @@
 package com.ruoyi.common.utils;
 
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Map;
+
 public class ChineseUtils {
+    private static final String[] CN_NUM = {
+            "闆�", "澹�", "璐�", "鍙�", "鑲�", "浼�", "闄�", "鏌�", "鎹�", "鐜�"
+    };
+
+    private static final String[] CN_UNIT = {
+            "", "鎷�", "浣�", "浠�"
+    };
+
+    private static final String[] CN_BIG_UNIT = {
+            "", "涓�", "浜�", "鍏�"
+    };
+    private static final Map<Character, Integer> CN_NUM_MAP = new HashMap<>();
+    private static final Map<Character, Integer> CN_UNIT_MAP = new HashMap<>();
+
+    static {
+        for (int i = 0; i < CN_NUM.length; i++) {
+            CN_NUM_MAP.put(CN_NUM[i].charAt(0), i);
+        }
+        CN_NUM_MAP.put('闆�', 0);
+        CN_NUM_MAP.put('涓�', 1);
+        CN_NUM_MAP.put('浜�', 2);
+        CN_NUM_MAP.put('涓�', 3);
+        CN_NUM_MAP.put('鍥�', 4);
+        CN_NUM_MAP.put('浜�', 5);
+        CN_NUM_MAP.put('鍏�', 6);
+        CN_NUM_MAP.put('涓�', 7);
+        CN_NUM_MAP.put('鍏�', 8);
+        CN_NUM_MAP.put('涔�', 9);
+        CN_NUM_MAP.put('涓�', 2);
+
+        CN_UNIT_MAP.put('鎷�', 10);
+        CN_UNIT_MAP.put('浣�', 100);
+        CN_UNIT_MAP.put('浠�', 1000);
+        CN_UNIT_MAP.put('鍗�', 10);
+        CN_UNIT_MAP.put('鐧�', 100);
+        CN_UNIT_MAP.put('鍗�', 1000);
+    }
 
     /**
      * 鏍¢獙鏄惁鏄腑鏂�
@@ -23,4 +64,251 @@
         return c >= 0x4E00 && c <= 0x9FA5;
     }
 
+    /**
+     * 鏁板瓧閲戦杞腑鏂囧ぇ鍐�
+     * 渚嬪锛�1234.56 -> 澹逛粺璐颁桨鍙佹嬀鑲嗗厓浼嶈闄嗗垎
+     */
+    public static String numberToChinese(BigDecimal amount) {
+        if (amount == null) {
+            throw new IllegalArgumentException("閲戦涓嶈兘涓虹┖");
+        }
+
+        boolean negative = amount.signum() < 0;
+        amount = amount.abs().setScale(2, BigDecimal.ROUND_HALF_UP);
+
+        long integerPart = amount.longValue();
+        int decimalPart = amount.subtract(new BigDecimal(integerPart))
+                .multiply(new BigDecimal(100))
+                .intValue();
+
+        int jiao = decimalPart / 10;
+        int fen = decimalPart % 10;
+
+        StringBuilder sb = new StringBuilder();
+
+        if (negative) {
+            sb.append("璐�");
+        }
+
+        if (integerPart == 0) {
+            sb.append("闆跺厓");
+        } else {
+            sb.append(integerToChinese(integerPart)).append("鍏�");
+        }
+
+        if (jiao == 0 && fen == 0) {
+            sb.append("鏁�");
+        } else {
+            if (jiao > 0) {
+                sb.append(CN_NUM[jiao]).append("瑙�");
+            } else if (fen > 0 && integerPart > 0) {
+                sb.append("闆�");
+            }
+
+            if (fen > 0) {
+                sb.append(CN_NUM[fen]).append("鍒�");
+            }
+        }
+
+        return sb.toString();
+    }
+
+    public static String numberToChinese(double amount) {
+        return numberToChinese(BigDecimal.valueOf(amount));
+    }
+
+    public static String numberToChinese(String amount) {
+        return numberToChinese(new BigDecimal(amount));
+    }
+
+    /**
+     * 鏁存暟閮ㄥ垎杞腑鏂囧ぇ鍐�
+     */
+    private static String integerToChinese(long num) {
+        if (num == 0) {
+            return "闆�";
+        }
+
+        StringBuilder sb = new StringBuilder();
+        int unitIndex = 0;
+        boolean needZero = false;
+
+        while (num > 0) {
+            int section = (int) (num % 10000);
+            if (section != 0) {
+                String sectionStr = sectionToChinese(section);
+                if (needZero || (section < 1000 && sb.length() > 0)) {
+                    sb.insert(0, "闆�");
+                }
+                sb.insert(0, sectionStr + CN_BIG_UNIT[unitIndex]);
+                needZero = section < 1000;
+            } else {
+                if (sb.length() > 0 && !sb.toString().startsWith("闆�")) {
+                    needZero = true;
+                }
+            }
+            num /= 10000;
+            unitIndex++;
+        }
+
+        String result = sb.toString();
+        result = result.replaceAll("闆�+", "闆�");
+        result = result.replaceAll("闆�$", "");
+        result = result.replaceAll("闆朵竾", "涓�");
+        result = result.replaceAll("闆朵嚎", "浜�");
+        return result;
+    }
+
+    /**
+     * 鍥涗綅浠ュ唴鏁板瓧杞腑鏂�
+     */
+    private static String sectionToChinese(int section) {
+        StringBuilder sb = new StringBuilder();
+        int unit = 1000;
+        boolean zeroFlag = false;
+
+        while (section > 0) {
+            int digit = section / unit;
+            if (digit == 0) {
+                if (sb.length() > 0 && !zeroFlag) {
+                    zeroFlag = true;
+                    sb.append("闆�");
+                }
+            } else {
+                zeroFlag = false;
+                sb.append(CN_NUM[digit]).append(CN_UNIT[getUnitIndex(unit)]);
+            }
+            section %= unit;
+            unit /= 10;
+        }
+
+        String result = sb.toString();
+        if (result.endsWith("闆�")) {
+            result = result.substring(0, result.length() - 1);
+        }
+        return result;
+    }
+
+    private static int getUnitIndex(int unit) {
+        switch (unit) {
+            case 1000: return 3;
+            case 100: return 2;
+            case 10: return 1;
+            default: return 0;
+        }
+    }
+
+    /**
+     * 涓枃澶у啓閲戦杞暟瀛�
+     * 渚嬪锛氬9浠熻窗浣板弫鎷捐倖鍏冧紞瑙掗檰鍒� -> 1234.56
+     */
+    public static BigDecimal chineseToNumber(String chinese) {
+        if (chinese == null || chinese.trim().isEmpty()) {
+            throw new IllegalArgumentException("涓枃閲戦涓嶈兘涓虹┖");
+        }
+
+        String str = chinese.trim()
+                .replace("鏁�", "")
+                .replace("姝�", "")
+                .replace("浜烘皯甯�", "");
+
+        boolean negative = str.startsWith("璐�");
+        if (negative) {
+            str = str.substring(1);
+        }
+
+        // 鍒嗙鍏冦�佽銆佸垎
+        String integerPartStr;
+        String decimalPartStr = "";
+
+        int yuanIndex = str.indexOf("鍏�");
+        if (yuanIndex >= 0) {
+            integerPartStr = str.substring(0, yuanIndex);
+            String rest = str.substring(yuanIndex + 1);
+
+            int jiaoIndex = rest.indexOf("瑙�");
+            int fenIndex = rest.indexOf("鍒�");
+
+            if (jiaoIndex >= 0) {
+                decimalPartStr += chineseDigitToNumber(rest.substring(0, jiaoIndex)) + "";
+            } else if (fenIndex > 0) {
+                decimalPartStr += "0";
+            }
+
+            if (fenIndex >= 0) {
+                String fenStr = rest.substring(jiaoIndex >= 0 ? jiaoIndex + 1 : 0, fenIndex);
+                decimalPartStr += chineseDigitToNumber(fenStr) + "";
+            } else {
+                if (decimalPartStr.length() == 1) {
+                    decimalPartStr += "0";
+                }
+            }
+        } else {
+            // 娌℃湁鈥滃厓鈥濓紝鎸夌函鏁板瓧涓枃澶勭悊
+            integerPartStr = str;
+        }
+
+        long integerPart = chineseIntegerToNumber(integerPartStr);
+
+        if (decimalPartStr.isEmpty()) {
+            decimalPartStr = "00";
+        } else if (decimalPartStr.length() == 1) {
+            decimalPartStr += "0";
+        }
+
+        BigDecimal result = new BigDecimal(integerPart + "." + decimalPartStr);
+        return negative ? result.negate() : result;
+    }
+    /**
+     * 涓枃鏁存暟杞� long
+     */
+    private static long chineseIntegerToNumber(String chinese) {
+        if (chinese == null || chinese.isEmpty() || chinese.equals("闆�")) {
+            return 0;
+        }
+
+        long result = 0;
+        long section = 0;
+        long number = 0;
+
+        for (int i = 0; i < chinese.length(); i++) {
+            char c = chinese.charAt(i);
+
+            if (CN_NUM_MAP.containsKey(c)) {
+                number = CN_NUM_MAP.get(c);
+            } else if (CN_UNIT_MAP.containsKey(c)) {
+                int unit = CN_UNIT_MAP.get(c);
+                if (number == 0) {
+                    number = 1;
+                }
+                section += number * unit;
+                number = 0;
+            } else if (c == '涓�') {
+                section += number;
+                result += section * 10000;
+                section = 0;
+                number = 0;
+            } else if (c == '浜�') {
+                section += number;
+                result += section * 100000000;
+                section = 0;
+                number = 0;
+            } else if (c == '鍏�') {
+                section += number;
+                result += section * 1000000000000L;
+                section = 0;
+                number = 0;
+            }
+        }
+
+        return result + section + number;
+    }
+
+    private static int chineseDigitToNumber(String chinese) {
+        if (chinese == null || chinese.isEmpty()) {
+            return 0;
+        }
+        char c = chinese.charAt(0);
+        return CN_NUM_MAP.getOrDefault(c, 0);
+    }
 }

--
Gitblit v1.9.3