tjx
2025-10-30 325437ff8509c8ae19da9e060272e1e12f2ab228
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package com.gs.xiaomi.service;
 
import cn.hutool.crypto.digest.DigestUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gs.xiaomi.config.DataAcquisitionConfiguration;
import com.gs.xiaomi.dto.BCS101Request;
import com.gs.xiaomi.dto.X5Header;
import com.gs.xiaomi.dto.X5Request;
import com.gs.xiaomi.dto.X5Response;
import com.gs.xiaomi.util.X5StringUtils;
import okhttp3.*;
import org.springframework.stereotype.Service;
 
import java.io.IOException;
import java.net.URLEncoder;
import java.util.concurrent.TimeUnit;
 
@Service
public class BCS101ApiService {
 
    private final OkHttpClient client;
    private final ObjectMapper objectMapper;
 
    public BCS101ApiService() {
        this.client = new OkHttpClient.Builder()
                .connectTimeout(3000, TimeUnit.SECONDS)
                .readTimeout(90, TimeUnit.SECONDS)
                .build();
        this.objectMapper = new ObjectMapper();
    }
 
    /**
     * 获取BCS101数据 - 严格按照C# X5协议实现
     * <p>
     * 基于C# Helper102.POSTResponseData方法的Java实现
     * X5协议流程:
     * 1. 序列化Body为JSON字符串
     * 2. MD5签名: MD5(appid+bodyStr+appkey)
     * 3. 构建X5Request {header: {appid, sign}, body: bodyStr}
     * 4. Base64编码整个X5Request
     * 5. URL编码
     * 6. 发送 data=url编码(base64编码)的数据
     *
     * @param request BCS101请求参数
     * @return API响应
     * @throws IOException 网络异常
     */
    public String getBCS101Data(BCS101Request request) throws IOException {
        try {
            System.out.println("=== BCS101 X5协议实现 (基于C#代码) ===");
 
            // 1. 序列化Body为JSON字符串
            String bodyStr = objectMapper.writeValueAsString(request);
            //System.out.println("1. Body JSON: " + bodyStr);
 
            // 2. MD5签名: sign = MD5(appid + bodyStr + appkey)
            String appId = DataAcquisitionConfiguration.BCS_APP_ID;
            String appKey = DataAcquisitionConfiguration.BCS_APP_Key;
            String signString = appId + bodyStr + appKey;
            String sign = DigestUtil.md5Hex(signString).toUpperCase();
            //System.out.println("2. 签名字符串: " + signString);
            //System.out.println("3. MD5签名: " + sign);
 
            // 3. 构建X5Header
            X5Header header = new X5Header(appId, sign);
 
            // 4. 构建X5Request
            X5Request x5Request = new X5Request(header, bodyStr);
            String x5RequestJson = objectMapper.writeValueAsString(x5Request);
            //System.out.println("4. X5Request JSON: " + x5RequestJson);
 
            // 5. Base64编码整个X5Request
            String base64Data = X5StringUtils.encodeBase64(x5RequestJson);
            //System.out.println("5. Base64编码: " + base64Data);
 
            // 6. URL编码
            String urlEncodedData = URLEncoder.encode(base64Data, "UTF-8");
           // System.out.println("6. URL编码: " + urlEncodedData);
 
            // 7. 构建form表单数据: data=url编码(base64编码)的数据
            String formData = "data=" + urlEncodedData;
            //System.out.println("7. Form数据: " + formData);
 
            // 8. Basic Auth认证
            String credentials = DataAcquisitionConfiguration.BCS_USER_NAME + ":" + DataAcquisitionConfiguration.BCS_PWD;
            String auth = X5StringUtils.encodeBase64(credentials);
           // System.out.println("8. Basic Auth: Basic " + auth);
 
            // 9. 构建HTTP请求 - 严格按照C#代码的请求格式
            RequestBody body = RequestBody.create(formData, MediaType.parse("application/x-www-form-urlencoded"));
            Request httpRequest = new Request.Builder()
                    .url(DataAcquisitionConfiguration.BCS_101_URL)
                    .method("POST", body)
                    .addHeader("Content-Type", "application/x-www-form-urlencoded")
                    .addHeader("Authorization", "Basic " + auth)
                    .addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
                    .addHeader("Cache-Control", "no-cache")
                    .addHeader("Pragma", "no-cache")
                    .build();
 
            //System.out.println("9. 发送X5协议请求到: " + DataAcquisitionConfiguration.BCS_101_URL);
 
            // 10. 执行请求
            try (Response response = client.newCall(httpRequest).execute()) {
               //System.out.println("10. HTTP状态码: " + response.code());
               //System.out.println("11. 响应头: " + response.headers());
 
                if (response.body() != null) {
                    String responseBody = response.body().string();
                    //System.out.println("12. 原始响应: " + responseBody);
 
                    // 11. 尝试解析为X5Response格式
                    try {
                        X5Response x5Response = objectMapper.readValue(responseBody, X5Response.class);
                        //System.out.println("13. X5响应解析成功: " + x5Response);
 
                        // 检查响应状态
                        if (x5Response.getHeader() != null && "200".equals(x5Response.getHeader().getCode())) {
                            //System.out.println("14. X5协议调用成功");
                        } else {
                            //System.out.println("14. X5协议调用失败: " +
                            //        (x5Response.getHeader() != null ? x5Response.getHeader().getDesc() : "未知错误"));
                        }
                    } catch (Exception e) {
                        //System.out.println("13. 非X5格式响应,直接返回原始内容");
                    }
 
                    return responseBody;
                }
 
                throw new IOException("Empty response body");
            }
 
        } catch (Exception ex) {
            System.err.println("BCS101 X5协议调用异常: " + ex.getMessage());
            ex.printStackTrace();
            throw new IOException("BCS101 X5协议调用失败", ex);
        }
    }
 
}