|
|
@@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory;
|
|
|
import org.xml.sax.Attributes;
|
|
|
import org.xml.sax.SAXException;
|
|
|
import org.xml.sax.helpers.DefaultHandler;
|
|
|
+import okhttp3.*;
|
|
|
|
|
|
import javax.servlet.ServletInputStream;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
@@ -23,7 +24,12 @@ import java.net.URL;
|
|
|
import java.security.MessageDigest;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.Comparator;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import java.util.stream.Collectors;
|
|
|
+import java.io.ByteArrayOutputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.util.Base64;
|
|
|
|
|
|
/**
|
|
|
* 公众平台通用接口工具类
|
|
|
@@ -39,6 +45,15 @@ public class WeixinUtil {
|
|
|
// 获取access_token的接口地址(GET) 限200(次/天),可以在配置文件中修改
|
|
|
public static String access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
|
|
|
|
|
|
+ private static final String MINI_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=";
|
|
|
+
|
|
|
+ // OkHttp客户端(全局单例)
|
|
|
+ private static final OkHttpClient OK_HTTP_CLIENT = new OkHttpClient.Builder()
|
|
|
+ .connectTimeout(10, TimeUnit.SECONDS)
|
|
|
+ .readTimeout(10, TimeUnit.SECONDS)
|
|
|
+ .writeTimeout(10, TimeUnit.SECONDS)
|
|
|
+ .build();
|
|
|
+
|
|
|
//获取微信的code
|
|
|
public static String code = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect";
|
|
|
public static String getCodeRequest(String appid, String url,String scope){
|
|
|
@@ -472,6 +487,79 @@ public class WeixinUtil {
|
|
|
return phone;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+ public static String generateMiniProgramCode(String pagePath,String scene ,int width,String accessToken) throws IOException {
|
|
|
+
|
|
|
+ // 关键1:page参数格式校验(强制修正常见错误)
|
|
|
+ if (pagePath == null || pagePath.isEmpty()) {
|
|
|
+ throw new IllegalArgumentException("page参数不能为空");
|
|
|
+ }
|
|
|
+ // 移除开头的/
|
|
|
+ pagePath = pagePath.startsWith("/") ? pagePath.substring(1) : pagePath;
|
|
|
+ // 移除.html后缀
|
|
|
+ pagePath = pagePath.endsWith(".html") ? pagePath.replace(".html", "") : pagePath;
|
|
|
+ // 校验是否包含pages开头(最低要求)
|
|
|
+ if (!pagePath.startsWith("pages/")) {
|
|
|
+ throw new IllegalArgumentException("page参数必须以pages/开头,正确格式如:pages/index/index");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 2. 构建请求参数(JSON格式)
|
|
|
+ com.alibaba.fastjson.JSONObject params = new com.alibaba.fastjson.JSONObject();
|
|
|
+ params.put("scene", scene); // 场景值(非必填,可传递自定义参数)
|
|
|
+ params.put("page", pagePath); // 小程序页面路径(必填)
|
|
|
+ params.put("width", width); // 小程序码宽度
|
|
|
+ params.put("auto_color", false); // 是否自动配置颜色
|
|
|
+ params.put("line_color", new com.alibaba.fastjson.JSONObject().fluentPut("r", 0).fluentPut("g", 0).fluentPut("b", 0)); // 线条颜色(黑色)
|
|
|
+ params.put("is_hyaline", false); // 是否透明
|
|
|
+
|
|
|
+ // 3. 发送POST请求
|
|
|
+ MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
|
|
|
+ RequestBody requestBody = RequestBody.create(mediaType,params.toJSONString());
|
|
|
+ Request request = new Request.Builder()
|
|
|
+ .url(MINI_CODE_URL + accessToken)
|
|
|
+ .post(requestBody)
|
|
|
+ .build();
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ try (Response response = OK_HTTP_CLIENT.newCall(request).execute()) {
|
|
|
+ if (!response.isSuccessful()) {
|
|
|
+ throw new IOException("生成小程序码失败:" + response);
|
|
|
+ }
|
|
|
+
|
|
|
+ //通过body()方法获取响应体,而非Body属性
|
|
|
+ ResponseBody body = response.body();
|
|
|
+ if (body == null) {
|
|
|
+ throw new IOException("小程序码接口返回空响应体");
|
|
|
+ }
|
|
|
+
|
|
|
+ String s = body.contentType().type();
|
|
|
+ if (body.contentType().type().equals("image")) {
|
|
|
+ // 响应是图片流,保存为文件
|
|
|
+ byte[] imageBytes;
|
|
|
+ try (InputStream inputStream = body.byteStream();
|
|
|
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
|
|
+ byte[] buffer = new byte[1024];
|
|
|
+ int len;
|
|
|
+ while ((len = inputStream.read(buffer)) != -1) {
|
|
|
+ outputStream.write(buffer, 0, len);
|
|
|
+ }
|
|
|
+ imageBytes = outputStream.toByteArray();
|
|
|
+ }
|
|
|
+
|
|
|
+ return Base64.getEncoder().encodeToString(imageBytes);
|
|
|
+ } else {
|
|
|
+ // 响应是JSON,说明有错误
|
|
|
+ String errorMsg = body.string();
|
|
|
+ throw new IOException("生成小程序码失败:" + errorMsg);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public static void main(String[] args) {
|
|
|
JSONObject sendData = JSONObject.fromObject("{\"first\":{\"value\":\"尊敬的用户,本次充电已结束!\",\"color\":\"#173177\"},\"keyword1\":{\"value\":\"地下停车场充电桩\",\"color\":\"#173177\"},\"keyword2\":{\"value\":\"2022-03-08 17:37:50至2022-03-08 17:44:41\",\"color\":\"#173177\"},\"keyword3\":{\"value\":\"6分钟\"},\"keyword4\":{\"value\":\"0.25元(账户余额:98.5元)\"}}");
|
|
|
|