liudongzhi пре 1 недеља
родитељ
комит
2fb4167d0c
1 измењених фајлова са 171 додато и 117 уклоњено
  1. 171 117
      alien-store/src/main/java/shop/alien/store/service/impl/PrintService.java

+ 171 - 117
alien-store/src/main/java/shop/alien/store/service/impl/PrintService.java

@@ -14,6 +14,7 @@ import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.entity.UrlEncodedFormEntity;
 import org.apache.http.client.methods.*;
+import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.message.BasicNameValuePair;
@@ -23,18 +24,16 @@ import shop.alien.entity.store.PrinterDO;
 import shop.alien.store.util.Base64Util;
 import shop.alien.store.util.ShaUtil;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
 import java.io.BufferedReader;
+import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.util.*;
 
 @Slf4j
 @Service
@@ -52,7 +51,7 @@ public class PrintService {
     public void printAll(List<PrinterDO> list, String content) {
         for (PrinterDO p : list) {
             // 异步打印:不阻塞,多打印机同时打印
-            new Thread(() -> printWithRetry(p, content, 3)).start();
+            new Thread(() -> printWithRetry(p, content, 1)).start();
         }
     }
 
@@ -124,56 +123,63 @@ public class PrintService {
         return post("http://api.jhprt.com/api/print", req);
     }
 
-    // ==================== 商鹏打印实现 (V1) ====================
+    // ==================== 商鹏打印实现 (V1 官方签名版) ====================
     private boolean printShangPeng(PrinterDO p, String content) {
-        String printUrl = "https://open.spyun.net/v1/printer/print";
         String sn = p.getSn();
         String apiKey = p.getApiKey();
+        String appid = p.getUserId(); // 假设 userId 字段存储的是商鹏 appid
 
-        if (sn == null || apiKey == null || sn.trim().isEmpty() || apiKey.trim().isEmpty()) {
-            log.error("商鹏打印参数缺失: sn={}, apiKey={}", sn, apiKey);
+        if (sn == null || apiKey == null || appid == null || sn.trim().isEmpty() || apiKey.trim().isEmpty()) {
+            log.error("商鹏打印参数缺失: sn={}, appid={}, apiKey={}", sn, appid, apiKey);
             return false;
         }
 
         String base64Content = Base64Util.encode(content);
-        int times = 1;
+        int times = 1; // 强制设置为一次只打印 1 份
 
         HttpURLConnection conn = null;
         try {
-            URL url = new URL(printUrl);
-            conn = (HttpURLConnection) url.openConnection();
+            String url = "https://open.spyun.net/v1/printer/print";
+            conn = (HttpURLConnection) new URL(url).openConnection();
             conn.setRequestMethod("POST");
             conn.setDoOutput(true);
             conn.setConnectTimeout(5000);
             conn.setReadTimeout(10000);
             conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
 
-            StringBuilder params = new StringBuilder();
-            params.append("sn=").append(URLEncoder.encode(sn, StandardCharsets.UTF_8.name()));
-            // 注意:如果官方文档明确要求参数名为 token,请将 &apikey= 改为 &token=
-            params.append("&apikey=").append(URLEncoder.encode(apiKey, StandardCharsets.UTF_8.name()));
-            params.append("&content=").append(URLEncoder.encode(base64Content, StandardCharsets.UTF_8.name()));
-            params.append("&times=").append(times);
-
-            log.info("商鹏 V1 打印请求: sn={}, apiKey={}, times={}", sn, mask(apiKey), times);
+            // 构建请求参数
+            Map<String, String> params = new HashMap<>();
+            params.put("sn", sn);
+//            params.put("content", base64Content);
+            params.put("content", content);
+            params.put("times", "1");
+            params.put("appid", appid);
+            params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
+            
+            // 生成签名
+            params.put("sign", makeSign(params, apiKey));
+
+            // 拼接表单参数
+            StringBuilder paramsStr = new StringBuilder();
+            for (Map.Entry<String, String> entry : params.entrySet()) {
+                if (paramsStr.length() > 0) paramsStr.append("&");
+                paramsStr.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name()));
+            }
 
             try (OutputStream os = conn.getOutputStream()) {
-                os.write(params.toString().getBytes(StandardCharsets.UTF_8));
+                os.write(paramsStr.toString().getBytes(StandardCharsets.UTF_8));
                 os.flush();
             }
 
             int code = conn.getResponseCode();
             StringBuilder result = new StringBuilder();
             if (code == 200) {
-                try (BufferedReader reader = new BufferedReader(
-                        new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
+                try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
                     String line;
-                    while ((line = reader.readLine()) != null) {
-                        result.append(line);
-                    }
+                    while ((line = reader.readLine()) != null) result.append(line);
                 }
                 log.info("商鹏 V1 打印响应: {}", result);
-                return result.toString().contains("\"code\":200") || result.toString().contains("\"success\":true");
+                return result.toString().contains("\"code\":0") || result.toString().contains("\"success\":true");
             } else {
                 log.error("商鹏 V1 打印请求失败,HTTP 状态码: {}", code);
                 return false;
@@ -186,12 +192,44 @@ public class PrintService {
         }
     }
 
-    // 辅助方法:日志脱敏
-    private String mask(String key) {
-        if (key == null || key.length() <= 4) return "***";
-        return key.substring(0, 4) + "****" + key.substring(key.length() - 2);
+    // 官方签名算法:字典序排序 + MD5 大写
+    private String makeSign(Map<String, String> params, String appsecret) {
+        String[] keys = params.keySet().toArray(new String[0]);
+        Arrays.sort(keys);
+
+        StringBuilder sign = new StringBuilder();
+        for (int i = 0; i < keys.length; i++) {
+            String k = keys[i];
+            String v = params.get(k);
+            if (!k.equals("sign") && !k.equals("appsecret") && v != null && !v.isEmpty()) {
+                if (sign.length() > 0) sign.append("&");
+                sign.append(k).append("=").append(v);
+            }
+        }
+        sign.append("&appsecret=").append(appsecret);
+
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] digest = md.digest(sign.toString().getBytes(StandardCharsets.UTF_8));
+            StringBuilder hex = new StringBuilder();
+            for (byte b : digest) {
+                String h = Integer.toHexString(0xff & b);
+                if (h.length() == 1) hex.append('0');
+                hex.append(h);
+            }
+            return hex.toString().toUpperCase();
+        } catch (Exception e) {
+            log.error("MD5 签名失败", e);
+            return "";
+        }
     }
 
+    // 辅助方法:日志脱敏
+//    private String mask(String key) {
+//        if (key == null || key.length() <= 4) return "***";
+//        return key.substring(0, 4) + "****" + key.substring(key.length() - 2);
+//    }
+
     /**
      * 统一发送POST请求
      */
@@ -213,90 +251,106 @@ public class PrintService {
     }
 
 
-    public static final String baseUri = "https://open.spyun.net/v1/";
-    private String appid;
-
-    private String appsecret;
-
-    public void Api(String appid, String appsecret) {
-        this.appid = appid;
-        this.appsecret = appsecret;
-    }
-
-
-
-    // 辅助方法:生成签名
-    public String makeSign(ArrayList<NameValuePair> params) {
-        int size = params.size();
-        String[] keys = new String[params.size()];
-        HashMap<String, String> values = new HashMap<>();
-        for (int i = 0; i < size; i++) {
-            NameValuePair p = params.get(i);
-            keys[i] = p.getName();
-            values.put(p.getName(), p.getValue());
-        }
-        Arrays.sort(keys);
-
-        String sign = "";
-        for (int i = 0; i < keys.length; i++) {
-            String v = values.get(keys[i]);
-            if (!keys[i].equals("sign") && !keys[i].equals("appsecret") && !v.equals("")) {
-                if (i > 0) {
-                    sign += "&";
-                }
-                sign += keys[i] + "=" + v;
-            }
-        }
-        sign += "&appsecret=" + appsecret;
-
-        return DigestUtils.md5Hex(sign).toUpperCase();
-    }
-
-
-    public String print(String sn, String content, int times) throws IOException {
-        ArrayList<NameValuePair> params = new ArrayList<>();
-        params.add(new BasicNameValuePair("sn", sn));
-        params.add(new BasicNameValuePair("content", content));
-        params.add(new BasicNameValuePair("times", String.valueOf(times)));
-
-        return request("POST", "printer/print", params);
-    }
-
-    // 发送请求
-    private String request(String uri, String s, ArrayList<NameValuePair> params) throws IOException {
-        RequestConfig requestConfig = RequestConfig.custom()
-                .setSocketTimeout(4000)    //读取超时
-                .setConnectTimeout(1000)   //连接超时
-                .build();
-
-        CloseableHttpClient httpClient = HttpClients.custom()
-                .setDefaultRequestConfig(requestConfig)
-                .build();
-
-        // 公共请求参数
-        params.add(new BasicNameValuePair("appid", appid));
-        params.add(new BasicNameValuePair("timestamp", String.valueOf(System.currentTimeMillis() / 1000)));
-        params.add(new BasicNameValuePair("sign", makeSign(params)));
-
-        CloseableHttpResponse response = null;
-        String url = baseUri + uri;
-        HttpPost request = new HttpPost(url);
-        request.setEntity(new UrlEncodedFormEntity(params,"utf-8"));
-        response = httpClient.execute(request);
-
-        if (response == null) {
-            throw new ClientProtocolException();
-        }
-        HttpEntity httpEntity = response.getEntity();
-        if (httpEntity == null) {
-            throw new ClientProtocolException();
-        }
-
-        if (response.getStatusLine().getStatusCode() != 200) {
-            throw new ClientProtocolException(EntityUtils.toString(httpEntity));
-        }
-
-        return EntityUtils.toString(httpEntity);
-    }
+//    public static final String baseUri = "https://open.spyun.net/v1/";
+//    private String appid;
+//
+//    private String appsecret;
+//
+//    public void Api(String appid, String appsecret) {
+//        this.appid = appid;
+//        this.appsecret = appsecret;
+//    }
+//
+//
+//
+//    // 辅助方法:生成签名
+//    public String makeSign(ArrayList<NameValuePair> params) {
+//        int size = params.size();
+//        String[] keys = new String[params.size()];
+//        HashMap<String, String> values = new HashMap<>();
+//        for (int i = 0; i < size; i++) {
+//            NameValuePair p = params.get(i);
+//            keys[i] = p.getName();
+//            values.put(p.getName(), p.getValue());
+//        }
+//        Arrays.sort(keys);
+//
+//        String sign = "";
+//        for (int i = 0; i < keys.length; i++) {
+//            String v = values.get(keys[i]);
+//            if (!keys[i].equals("sign") && !keys[i].equals("appsecret") && !v.equals("")) {
+//                if (i > 0) {
+//                    sign += "&";
+//                }
+//                sign += keys[i] + "=" + v;
+//            }
+//        }
+//        sign += "&appsecret=" + appsecret;
+//
+//        return DigestUtils.md5Hex(sign).toUpperCase();
+//    }
+//
+//
+//    public String getPrintsOrders(String sn, String date) throws IOException {
+//        ArrayList<NameValuePair> params = new ArrayList<>();
+//        params.add(new BasicNameValuePair("sn", sn));
+//        params.add(new BasicNameValuePair("date", date));
+//
+//        return request("POST", "printer/order/number", params);
+//    }
+//
+//    // 发送请求
+//    private String request(String method, String uri, ArrayList<NameValuePair> params) throws IOException {
+//        RequestConfig requestConfig = RequestConfig.custom()
+//                .setSocketTimeout(4000)    //读取超时
+//                .setConnectTimeout(1000)   //连接超时
+//                .build();
+//
+//        CloseableHttpClient httpClient = HttpClients.custom()
+//                .setDefaultRequestConfig(requestConfig)
+//                .build();
+//
+//        // 公共请求参数
+//        params.add(new BasicNameValuePair("appid", appid));
+//        params.add(new BasicNameValuePair("timestamp", String.valueOf(System.currentTimeMillis() / 1000)));
+//        params.add(new BasicNameValuePair("sign", makeSign(params)));
+//
+//        CloseableHttpResponse response = null;
+//        String url = baseUri + uri;
+//        if (method.equals("GET")) {
+//            HttpGet request = new HttpGet(url + "?" + URLEncodedUtils.format(params, "utf-8"));
+//            response = httpClient.execute(request);
+//        } else if (method.equals("DELETE")) {
+//            HttpDelete request = new HttpDelete(url + "?" + URLEncodedUtils.format(params, "utf-8"));
+//            response = httpClient.execute(request);
+//        } else if (method.equals("POST")) {
+//            HttpPost request = new HttpPost(url);
+//            request.setEntity(new UrlEncodedFormEntity(params,"utf-8"));
+//            response = httpClient.execute(request);
+//        } else if (method.equals("PATCH")) {
+//            HttpPatch request = new HttpPatch(url);
+//            request.setEntity(new UrlEncodedFormEntity(params,"utf-8"));
+//            response = httpClient.execute(request);
+//        } else if (method.equals("PUT")) {
+//            HttpPut request = new HttpPut(url);
+//            request.setEntity(new UrlEncodedFormEntity(params,"utf-8"));
+//            response = httpClient.execute(request);
+//        }
+//
+//        if (response == null) {
+//            throw new ClientProtocolException();
+//        }
+//
+//        HttpEntity httpEntity = response.getEntity();
+//        if (httpEntity == null) {
+//            throw new ClientProtocolException();
+//        }
+//
+//        if (response.getStatusLine().getStatusCode() != 200) {
+//            throw new ClientProtocolException(EntityUtils.toString(httpEntity));
+//        }
+//
+//        return EntityUtils.toString(httpEntity);
+//    }
 
 }