Selaa lähdekoodia

Merge remote-tracking branch 'origin/sit-new-checkstand' into sit-new-checkstand

刘云鑫 1 viikko sitten
vanhempi
commit
ba81772a2a

+ 231 - 9
alien-store/src/main/java/shop/alien/store/service/impl/PrintService.java

@@ -7,12 +7,33 @@ import okhttp3.OkHttpClient;
 import okhttp3.Request;
 import okhttp3.RequestBody;
 import okhttp3.Response;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+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;
+import org.apache.http.util.EntityUtils;
 import org.springframework.stereotype.Service;
 import shop.alien.entity.store.PrinterDO;
 import shop.alien.store.util.Base64Util;
 import shop.alien.store.util.ShaUtil;
 
-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
@@ -30,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();
         }
     }
 
@@ -102,16 +123,113 @@ public class PrintService {
         return post("http://api.jhprt.com/api/print", req);
     }
 
-    // ==================== 商鹏打印实现 ====================
+    // ==================== 商鹏打印实现 (V1 官方签名版) ====================
     private boolean printShangPeng(PrinterDO p, String content) {
-        JSONObject req = new JSONObject();
-        req.put("sn", p.getSn());
-        req.put("token", p.getApiKey());
-        req.put("content", Base64Util.encode(content));
-        req.put("times", 1);
-        return post("https://api.spyun.net/api/print", req);
+        String sn = p.getSn();
+        String apiKey = p.getApiKey();
+        String appid = p.getUserId(); // 假设 userId 字段存储的是商鹏 appid
+
+        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; // 强制设置为一次只打印 1 份
+
+        HttpURLConnection conn = null;
+        try {
+            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");
+
+            // 构建请求参数
+            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(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))) {
+                    String line;
+                    while ((line = reader.readLine()) != null) result.append(line);
+                }
+                log.info("商鹏 V1 打印响应: {}", result);
+                return result.toString().contains("\"code\":0") || result.toString().contains("\"success\":true");
+            } else {
+                log.error("商鹏 V1 打印请求失败,HTTP 状态码: {}", code);
+                return false;
+            }
+        } catch (Exception e) {
+            log.error("商鹏 V1 打印异常: sn={}, error={}", sn, e.getMessage(), e);
+            return false;
+        } finally {
+            if (conn != null) conn.disconnect();
+        }
+    }
+
+    // 官方签名算法:字典序排序 + 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请求
      */
@@ -131,4 +249,108 @@ public class PrintService {
             return false;
         }
     }
+
+
+//    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);
+//    }
+
 }