202506161649
This commit is contained in:
parent
ac42772ffd
commit
4d768ea54e
7
pom.xml
7
pom.xml
|
|
@ -163,6 +163,13 @@
|
||||||
<version>${velocity.version}</version>
|
<version>${velocity.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- 云信引入的工具包 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.winnerlook</groupId>
|
||||||
|
<artifactId>voice-sdk</artifactId>
|
||||||
|
<version>1.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 阿里JSON解析器 -->
|
<!-- 阿里JSON解析器 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.fastjson2</groupId>
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,12 @@
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.winnerlook</groupId>
|
||||||
|
<artifactId>voice-sdk</artifactId>
|
||||||
|
<version>1.1.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 阿里JSON解析器 -->
|
<!-- 阿里JSON解析器 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.fastjson2</groupId>
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,11 +1,13 @@
|
||||||
package com.ruoyi.system.ControllerUtil;
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import com.ruoyi.system.domain.ServiceCate;
|
import com.ruoyi.system.domain.ServiceCate;
|
||||||
import com.ruoyi.system.domain.ServiceGoods;
|
import com.ruoyi.system.domain.ServiceGoods;
|
||||||
import com.ruoyi.system.domain.Users;
|
import com.ruoyi.system.domain.Users;
|
||||||
import com.ruoyi.system.service.IServiceGoodsService;
|
import com.ruoyi.system.service.IServiceGoodsService;
|
||||||
import com.ruoyi.system.service.IUsersService;
|
import com.ruoyi.system.service.IUsersService;
|
||||||
|
import com.github.pagehelper.PageInfo;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
@ -129,7 +131,24 @@ public class AppletControllerUtil {
|
||||||
result.put("data", new java.util.ArrayList<>());
|
result.put("data", new java.util.ArrayList<>());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 判断字符串是否能转换为 JSONArray
|
||||||
|
*
|
||||||
|
* @param str 需要判断的字符串
|
||||||
|
* @return 如果是合法的JSON数组字符串,返回 true;否则返回 false
|
||||||
|
*/
|
||||||
|
public static boolean canParseToJSONArray(String str) {
|
||||||
|
if (str == null || str.trim().isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Object obj = JSON.parse(str);
|
||||||
|
return obj instanceof JSONArray;
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 解析失败,不是合法的JSON数组
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 服务商品详情响应实体类
|
* 服务商品详情响应实体类
|
||||||
*
|
*
|
||||||
|
|
@ -2633,4 +2652,48 @@ public class AppletControllerUtil {
|
||||||
|
|
||||||
return goodsData;
|
return goodsData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建分页响应结构,适用于小程序worker相关接口
|
||||||
|
* @param pageInfo PageInfo对象
|
||||||
|
* @param dataList 数据列表
|
||||||
|
* @param baseUrl 分页url前缀
|
||||||
|
* @return Map分页结构
|
||||||
|
*/
|
||||||
|
public static Map<String, Object> buildPageResult(PageInfo<?> pageInfo, List<?> dataList, String baseUrl) {
|
||||||
|
Map<String, Object> dataPage = new HashMap<>();
|
||||||
|
dataPage.put("current_page", pageInfo.getPageNum());
|
||||||
|
dataPage.put("data", dataList);
|
||||||
|
dataPage.put("first_page_url", baseUrl + "?page=1");
|
||||||
|
dataPage.put("from", pageInfo.getStartRow());
|
||||||
|
dataPage.put("last_page", pageInfo.getPages());
|
||||||
|
dataPage.put("last_page_url", baseUrl + "?page=" + pageInfo.getPages());
|
||||||
|
// links
|
||||||
|
List<Map<String, Object>> links = new ArrayList<>();
|
||||||
|
Map<String, Object> prevLink = new HashMap<>();
|
||||||
|
prevLink.put("url", pageInfo.isHasPreviousPage() ? baseUrl + "?page=" + pageInfo.getPrePage() : null);
|
||||||
|
prevLink.put("label", "« Previous");
|
||||||
|
prevLink.put("active", false);
|
||||||
|
links.add(prevLink);
|
||||||
|
for (int i = 1; i <= pageInfo.getPages(); i++) {
|
||||||
|
Map<String, Object> link = new HashMap<>();
|
||||||
|
link.put("url", baseUrl + "?page=" + i);
|
||||||
|
link.put("label", String.valueOf(i));
|
||||||
|
link.put("active", i == pageInfo.getPageNum());
|
||||||
|
links.add(link);
|
||||||
|
}
|
||||||
|
Map<String, Object> nextLink = new HashMap<>();
|
||||||
|
nextLink.put("url", pageInfo.isHasNextPage() ? baseUrl + "?page=" + pageInfo.getNextPage() : null);
|
||||||
|
nextLink.put("label", "Next »");
|
||||||
|
nextLink.put("active", false);
|
||||||
|
links.add(nextLink);
|
||||||
|
dataPage.put("links", links);
|
||||||
|
dataPage.put("next_page_url", pageInfo.isHasNextPage() ? baseUrl + "?page=" + pageInfo.getNextPage() : null);
|
||||||
|
dataPage.put("path", baseUrl);
|
||||||
|
dataPage.put("per_page", pageInfo.getPageSize());
|
||||||
|
dataPage.put("prev_page_url", pageInfo.isHasPreviousPage() ? baseUrl + "?page=" + pageInfo.getPrePage() : null);
|
||||||
|
dataPage.put("to", pageInfo.getEndRow());
|
||||||
|
dataPage.put("total", pageInfo.getTotal());
|
||||||
|
return dataPage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
|
import com.winnerlook.service.https.MyVerifyHostname;
|
||||||
|
import com.winnerlook.service.https.MyX509TrustManager;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpPost;
|
||||||
|
import org.apache.http.entity.BufferedHttpEntity;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.entity.mime.MultipartEntityBuilder;
|
||||||
|
import org.apache.http.entity.mime.content.FileBody;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
|
||||||
|
public class HttpsService {
|
||||||
|
|
||||||
|
private SSLContext sslContext;
|
||||||
|
private X509TrustManager tm;
|
||||||
|
private CloseableHttpClient httpClient;
|
||||||
|
|
||||||
|
public HttpsService()
|
||||||
|
throws Exception {
|
||||||
|
sslContext = SSLContext.getInstance("TLS");
|
||||||
|
tm = new MyX509TrustManager();
|
||||||
|
sslContext.init(null, new TrustManager[]{tm},
|
||||||
|
new java.security.SecureRandom());
|
||||||
|
httpClient = HttpClients.custom()
|
||||||
|
.setSSLHostnameVerifier(new MyVerifyHostname())
|
||||||
|
.setSSLContext(sslContext).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public String doPost(String path, String headerStr,
|
||||||
|
String requestBody, String encoding) throws Exception {
|
||||||
|
String resultString = "";
|
||||||
|
CloseableHttpResponse response = null;
|
||||||
|
HttpPost httpPost = null;
|
||||||
|
try {
|
||||||
|
URI uri = new URI(path);
|
||||||
|
httpPost = new HttpPost(uri);
|
||||||
|
httpPost.setHeader("Content-type", "application/json; charset=utf-8");
|
||||||
|
|
||||||
|
/** 报文头中设置Authorization参数*/
|
||||||
|
httpPost.setHeader("Authorization", headerStr);
|
||||||
|
|
||||||
|
/** 设置请求报文体*/
|
||||||
|
httpPost.setEntity(new StringEntity(requestBody, encoding));
|
||||||
|
|
||||||
|
response = httpClient.execute(httpPost);
|
||||||
|
HttpEntity httpEntity = response.getEntity();
|
||||||
|
httpEntity = new BufferedHttpEntity(httpEntity);
|
||||||
|
resultString = EntityUtils.toString(httpEntity);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw e;
|
||||||
|
} finally { //释放连接
|
||||||
|
|
||||||
|
if (null != response)
|
||||||
|
response.close();
|
||||||
|
if (httpPost != null)
|
||||||
|
httpPost.releaseConnection();
|
||||||
|
|
||||||
|
}
|
||||||
|
return resultString;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -223,6 +223,7 @@ public class OrderLogHandler {
|
||||||
updateOrderAcceptInfo(order, orderLog);
|
updateOrderAcceptInfo(order, orderLog);
|
||||||
|
|
||||||
orderLog.setFirstWorkerId(orderLog.getWorkerId());
|
orderLog.setFirstWorkerId(orderLog.getWorkerId());
|
||||||
|
//orderLog.setWorkerId(order.getOrderLog().getWorkerId());
|
||||||
orderLog.setIsPause(1);
|
orderLog.setIsPause(1);
|
||||||
orderLog.setTitle(TITLE_3);
|
orderLog.setTitle(TITLE_3);
|
||||||
orderLog.setType(new BigDecimal("2.0"));
|
orderLog.setType(new BigDecimal("2.0"));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用第三方接口请求工具类
|
||||||
|
* 支持GET和POST请求,支持自定义Header、请求体、URL参数等
|
||||||
|
* 可扩展、可复用,适用于各种第三方接口调用场景
|
||||||
|
*/
|
||||||
|
public class PublicSendApiUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送GET请求
|
||||||
|
* @param urlStr 请求地址
|
||||||
|
* @param headers 请求头参数(可为null)
|
||||||
|
* @param params URL参数(可为null)
|
||||||
|
* @return 响应内容
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public static String sendGet(String urlStr, Map<String, String> headers, Map<String, String> params) throws Exception {
|
||||||
|
// 拼接URL参数
|
||||||
|
if (params != null && !params.isEmpty()) {
|
||||||
|
StringJoiner sj = new StringJoiner("&");
|
||||||
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
|
sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8"));
|
||||||
|
}
|
||||||
|
urlStr += urlStr.contains("?") ? "&" + sj.toString() : "?" + sj.toString();
|
||||||
|
}
|
||||||
|
URL url = new URL(urlStr);
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
|
conn.setRequestMethod("GET");
|
||||||
|
// 设置请求头
|
||||||
|
if (headers != null) {
|
||||||
|
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||||
|
conn.setRequestProperty(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.setDoInput(true);
|
||||||
|
// 读取响应
|
||||||
|
int code = conn.getResponseCode();
|
||||||
|
InputStream is = (code == 200) ? conn.getInputStream() : conn.getErrorStream();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int len;
|
||||||
|
while ((len = is.read(buf)) != -1) {
|
||||||
|
sb.append(new String(buf, 0, len, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送POST请求
|
||||||
|
* @param urlStr 请求地址
|
||||||
|
* @param headers 请求头参数(可为null)
|
||||||
|
* @param params URL参数(可为null)
|
||||||
|
* @param body 请求体内容(可为null,通常为JSON字符串或表单数据)
|
||||||
|
* @return 响应内容
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public static String sendPost(String urlStr, Map<String, String> headers, Map<String, String> params, String body) throws Exception {
|
||||||
|
// 拼接URL参数
|
||||||
|
if (params != null && !params.isEmpty()) {
|
||||||
|
StringJoiner sj = new StringJoiner("&");
|
||||||
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
|
sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" + URLEncoder.encode(entry.getValue(), "UTF-8"));
|
||||||
|
}
|
||||||
|
urlStr += urlStr.contains("?") ? "&" + sj.toString() : "?" + sj.toString();
|
||||||
|
}
|
||||||
|
URL url = new URL(urlStr);
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
|
conn.setRequestMethod("POST");
|
||||||
|
// 设置请求头
|
||||||
|
if (headers != null) {
|
||||||
|
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||||
|
conn.setRequestProperty(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
conn.setDoInput(true);
|
||||||
|
// 写入请求体
|
||||||
|
if (body != null) {
|
||||||
|
try (OutputStream os = conn.getOutputStream()) {
|
||||||
|
os.write(body.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(conn);
|
||||||
|
|
||||||
|
// 读取响应
|
||||||
|
int code = conn.getResponseCode();
|
||||||
|
InputStream is = (code == 000000) ? conn.getInputStream() : conn.getErrorStream();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int len;
|
||||||
|
while ((len = is.read(buf)) != -1) {
|
||||||
|
sb.append(new String(buf, 0, len, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 示例:如何使用该工具类发送GET和POST请求
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// GET请求示例
|
||||||
|
Map<String, String> headers = new HashMap<>();
|
||||||
|
headers.put("Accept", "application/json");
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put("q", "test");
|
||||||
|
String getResult = sendGet("https://httpbin.org/get", headers, params);
|
||||||
|
System.out.println("GET结果:" + getResult);
|
||||||
|
|
||||||
|
// POST请求示例
|
||||||
|
headers.put("Content-Type", "application/json");
|
||||||
|
String postBody = "{\"name\":\"张三\"}";
|
||||||
|
String postResult = sendPost("https://httpbin.org/post", headers, null, postBody);
|
||||||
|
System.out.println("POST结果:" + postResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信小程序通知消息推送工具类
|
||||||
|
* 支持获取access_token、发送订阅消息等功能
|
||||||
|
* 适用于Controller、Service等各层直接调用
|
||||||
|
*/
|
||||||
|
public class WXsendMsgUtil {
|
||||||
|
|
||||||
|
// 微信小程序的AppID和AppSecret(请替换为你自己的)
|
||||||
|
private static final String APPID = "YOUR_APPID";
|
||||||
|
private static final String APPSECRET = "YOUR_APPSECRET";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取微信小程序全局唯一后台接口调用凭据 access_token
|
||||||
|
* @return access_token字符串
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public static String getAccessToken() throws Exception {
|
||||||
|
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APPID + "&secret=" + APPSECRET;
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||||
|
conn.setRequestMethod("GET");
|
||||||
|
conn.setDoInput(true);
|
||||||
|
InputStream is = conn.getInputStream();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int len;
|
||||||
|
while ((len = is.read(buf)) != -1) {
|
||||||
|
sb.append(new String(buf, 0, len, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
JSONObject json = JSONObject.parseObject(sb.toString());
|
||||||
|
return json.getString("access_token");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送微信小程序订阅消息
|
||||||
|
* @param accessToken access_token
|
||||||
|
* @param touser 接收者openid
|
||||||
|
* @param templateId 模板ID
|
||||||
|
* @param page 跳转页面(可选)
|
||||||
|
* @param data 模板内容(Map<String, Object>,如{"thing1":{"value":"内容"}})
|
||||||
|
* @return 微信接口响应
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public static String sendSubscribeMsg(String accessToken, String touser, String templateId, String page, Map<String, Object> data) throws Exception {
|
||||||
|
String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken;
|
||||||
|
Map<String, Object> param = new HashMap<>();
|
||||||
|
param.put("touser", touser);
|
||||||
|
param.put("template_id", templateId);
|
||||||
|
if (page != null && !page.isEmpty()) {
|
||||||
|
param.put("page", page);
|
||||||
|
}
|
||||||
|
param.put("data", data);
|
||||||
|
String body = JSON.toJSONString(param);
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||||
|
conn.setRequestMethod("POST");
|
||||||
|
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
try (OutputStream os = conn.getOutputStream()) {
|
||||||
|
os.write(body.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
InputStream is = conn.getInputStream();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int len;
|
||||||
|
while ((len = is.read(buf)) != -1) {
|
||||||
|
sb.append(new String(buf, 0, len, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 示例:如何推送微信小程序订阅消息
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// 1. 获取access_token
|
||||||
|
String accessToken = getAccessToken();
|
||||||
|
// 2. 组装消息内容
|
||||||
|
Map<String, Object> data = new HashMap<>();
|
||||||
|
Map<String, String> thing1 = new HashMap<>();
|
||||||
|
thing1.put("value", "测试内容");
|
||||||
|
data.put("thing1", thing1);
|
||||||
|
// 3. 发送消息
|
||||||
|
String result = sendSubscribeMsg(accessToken, "OPENID", "TEMPLATE_ID", "pages/index/index", data);
|
||||||
|
System.out.println("推送结果:" + result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,187 @@
|
||||||
|
package com.ruoyi.system.ControllerUtil;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.winnerlook.model.*;
|
||||||
|
import com.winnerlook.util.Base64;
|
||||||
|
import com.winnerlook.util.MD5Util;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 云信小号相关API工具类
|
||||||
|
* <p>
|
||||||
|
* 封装了云信小号的AX、AXB绑定、解绑、语音通知等接口的调用方法。
|
||||||
|
* 统一了签名、鉴权、请求体组装等流程,便于业务系统直接调用。
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 依赖:
|
||||||
|
* - fastjson2 用于JSON序列化/反序列化
|
||||||
|
* - com.winnerlook.model.* 需包含请求/响应体相关POJO
|
||||||
|
* - com.winnerlook.util.Base64、MD5Util 用于加密
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* 使用前请确保相关依赖和配置已正确引入。
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class YunXinPhoneUtilAPI {
|
||||||
|
|
||||||
|
private static final String APP_ID = "256339";
|
||||||
|
private static final String TOKEN = "ecf5ae04c52b4d85a0e4255d7d0ebb71";
|
||||||
|
|
||||||
|
// 云信接口地址常量
|
||||||
|
private static final String UNBIND_URL = "https://101.37.133.245:11008/voice/1.0.0/middleNumberUnbind";
|
||||||
|
private static final String NOTIFY_URL = "https://101.37.133.245:11008/voice/1.0.0/notify";
|
||||||
|
private static final String AXB_URL = "https://101.37.133.245:11008/voice/1.0.0/middleNumberAXB";
|
||||||
|
|
||||||
|
// 回调地址常量(可通过set方法动态设置)
|
||||||
|
private static String AXB_CALLBACK_URL = "";
|
||||||
|
private static String NOTIFY_CALLBACK_URL = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置AXB绑定的回调URL
|
||||||
|
*/
|
||||||
|
public static void setAxbCallbackUrl(String callbackUrl) {
|
||||||
|
AXB_CALLBACK_URL = callbackUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置语音通知的回调URL
|
||||||
|
*/
|
||||||
|
public static void setNotifyCallbackUrl(String callbackUrl) {
|
||||||
|
NOTIFY_CALLBACK_URL = callbackUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音通知接口调用
|
||||||
|
* @param phone 通知目标手机号
|
||||||
|
* @param templateID 语音通知模板ID
|
||||||
|
* @return VoiceResponseResult 结果对象
|
||||||
|
* @throws Exception 异常
|
||||||
|
* <p>回调地址使用 NOTIFY_CALLBACK_URL 常量,如需动态设置请调用 setNotifyCallbackUrl 方法</p>
|
||||||
|
*/
|
||||||
|
public static VoiceResponseResult httpsAxbTransfer(String phone, String templateID) throws Exception {
|
||||||
|
VoiceResponseResult resultObj = new VoiceResponseResult();
|
||||||
|
String url = NOTIFY_URL;
|
||||||
|
try {
|
||||||
|
// 组装请求体
|
||||||
|
VoiceNotifyBody transfer = new VoiceNotifyBody();
|
||||||
|
transfer.setCalleeNumber(phone);
|
||||||
|
transfer.setTemplateId(templateID);
|
||||||
|
transfer.setTemplateArgs(new LinkedHashMap<String, String>()); // 可根据需要传递参数
|
||||||
|
transfer.setCallbackUrl(NOTIFY_CALLBACK_URL);
|
||||||
|
|
||||||
|
// 获取当前时间戳
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
// 生成鉴权参数
|
||||||
|
String authorization = Base64.encodeBase64(APP_ID + ":" + timestamp);
|
||||||
|
String sig = MD5Util.getMD5(APP_ID + TOKEN + timestamp);
|
||||||
|
// 拼接最终URL
|
||||||
|
url = url + "/" + APP_ID + "/" + sig;
|
||||||
|
String body = JSON.toJSONString(transfer);
|
||||||
|
|
||||||
|
// 调用HTTPS服务
|
||||||
|
HttpsService httpsService = new HttpsService();
|
||||||
|
String result = httpsService.doPost(url, authorization, body, "UTF-8");
|
||||||
|
JSONObject rjson = JSONObject.parseObject(result);
|
||||||
|
resultObj.setCallId(rjson.getString("callId"));
|
||||||
|
resultObj.setResult(rjson.getString("result"));
|
||||||
|
resultObj.setMessage(rjson.getString("message"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("[YunXinPhoneUtilAPI] 语音通知异常: " + e.getMessage());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return resultObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AXB绑定接口调用
|
||||||
|
* 提前绑定小号号码、号码A、号码B的关系,A、B呼叫小号即可互相通话。
|
||||||
|
* @param minphone 隐私小号(X号)
|
||||||
|
* @param phoneA 号码A
|
||||||
|
* @param phoneB 号码B
|
||||||
|
* @return VoiceResponseResult 结果对象
|
||||||
|
* @throws Exception 异常
|
||||||
|
* <p>回调地址使用 AXB_CALLBACK_URL 常量,如需动态设置请调用 setAxbCallbackUrl 方法</p>
|
||||||
|
*/
|
||||||
|
public static VoiceResponseResult httpsPrivacyBindAxb(String minphone, String phoneA, String phoneB) throws Exception {
|
||||||
|
String url = AXB_URL;
|
||||||
|
VoiceResponseResult resultObj = new VoiceResponseResult();
|
||||||
|
try {
|
||||||
|
PrivacyBindBodyAxb bindBodyAxb = new PrivacyBindBodyAxb();
|
||||||
|
// 组装请求体
|
||||||
|
bindBodyAxb.setMiddleNumber(minphone);
|
||||||
|
bindBodyAxb.setBindNumberA(phoneA);
|
||||||
|
bindBodyAxb.setBindNumberB(phoneB);
|
||||||
|
bindBodyAxb.setCallRec(0); // 1:开启录音,0:关闭
|
||||||
|
bindBodyAxb.setMaxBindingTime(3600); // 有效时长(秒),为空表示永久
|
||||||
|
bindBodyAxb.setPassthroughCallerToA(0); // 0:不透传; 1:透传
|
||||||
|
bindBodyAxb.setPassthroughCallerToB(0); // 0:不透传; 1:透传
|
||||||
|
bindBodyAxb.setCallbackUrl(AXB_CALLBACK_URL);
|
||||||
|
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
String authorization = Base64.encodeBase64(APP_ID + ":" + timestamp);
|
||||||
|
String sig = MD5Util.getMD5(APP_ID + TOKEN + timestamp);
|
||||||
|
url = url + "/" + APP_ID + "/" + sig;
|
||||||
|
String body = JSON.toJSONString(bindBodyAxb);
|
||||||
|
|
||||||
|
HttpsService httpsService = new HttpsService();
|
||||||
|
String result = httpsService.doPost(url, authorization, body, "UTF-8");
|
||||||
|
JSONObject rjson = JSONObject.parseObject(result);
|
||||||
|
resultObj.setCallId(rjson.getString("callId"));
|
||||||
|
resultObj.setResult(rjson.getString("result"));
|
||||||
|
resultObj.setMessage(rjson.getString("message"));
|
||||||
|
System.out.println(result);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("[YunXinPhoneUtilAPI] AXB绑定异常: " + e.getMessage());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return resultObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解绑接口调用
|
||||||
|
* 解绑指定小号与A、B号码的绑定关系
|
||||||
|
* @param phoneA 号码A
|
||||||
|
* @param phoneB 号码B
|
||||||
|
* @param phone 隐私小号(X号)
|
||||||
|
* @return VoiceResponseResult 结果对象
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
public static VoiceResponseResult httpsPrivacyUnbind(String phoneA, String phoneB, String phone) throws Exception {
|
||||||
|
VoiceResponseResult resultObj = new VoiceResponseResult();
|
||||||
|
String url = UNBIND_URL;
|
||||||
|
try {
|
||||||
|
PrivacyUnbindBody unbindBody = new PrivacyUnbindBody();
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
unbindBody.setMiddleNumber(phone);
|
||||||
|
unbindBody.setBindNumberA(phoneA);
|
||||||
|
unbindBody.setBindNumberB(phoneB);
|
||||||
|
String authorization = Base64.encodeBase64(APP_ID + ":" + timestamp);
|
||||||
|
String sig = MD5Util.getMD5(APP_ID + TOKEN + timestamp);
|
||||||
|
url = url + "/" + APP_ID + "/" + sig;
|
||||||
|
String body = JSON.toJSONString(unbindBody);
|
||||||
|
HttpsService httpsService = new HttpsService();
|
||||||
|
String result = httpsService.doPost(url, authorization, body, "UTF-8");
|
||||||
|
JSONObject rjson = JSONObject.parseObject(result);
|
||||||
|
resultObj.setResult(rjson.getString("result"));
|
||||||
|
resultObj.setMessage(rjson.getString("message"));
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("[YunXinPhoneUtilAPI] 解绑异常: " + e.getMessage());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
return resultObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main方法示例:解绑操作
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// 设置回调地址(如有需要)
|
||||||
|
setAxbCallbackUrl("http://your-callback-url.com/axb");
|
||||||
|
setNotifyCallbackUrl("http://your-callback-url.com/notify");
|
||||||
|
// 示例:解绑操作
|
||||||
|
VoiceResponseResult res = httpsPrivacyUnbind("18339212639", "15270824290", "15695650664");
|
||||||
|
System.out.println("解绑结果:" + JSON.toJSONString(res));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -84,7 +84,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
|
||||||
|
|
||||||
<select id="selectOrderLogByOrderId" parameterType="String" resultMap="OrderLogResult">
|
<select id="selectOrderLogByOrderId" parameterType="String" resultMap="OrderLogResult">
|
||||||
select * from order_log where order_id = #{orderId}
|
select * from order_log where order_id = #{orderId} order by id DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<insert id="insertOrderLog" parameterType="OrderLog" useGeneratedKeys="true" keyProperty="id">
|
<insert id="insertOrderLog" parameterType="OrderLog" useGeneratedKeys="true" keyProperty="id">
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
<if test="goodId != null and goodId != ''"> and good_id like concat('%', #{goodId}, '%')</if>
|
<if test="goodId != null and goodId != ''"> and good_id like concat('%', #{goodId}, '%')</if>
|
||||||
|
|
||||||
<if test="typeId != null and typeId != ''">
|
<if test="typeId != null and typeId != ''">
|
||||||
and type_id in (select b.id from quote_material_type b where b.title like concat('%', #{typeId}, '%') ) </if>
|
and type_id like concat('%', #{typeId}, '%') </if>
|
||||||
|
|
||||||
<if test="title != null and title != ''"> and title like concat('%', #{title}, '%')</if>
|
<if test="title != null and title != ''"> and title like concat('%', #{title}, '%')</if>
|
||||||
<if test="priceMin != null and priceMax != null">
|
<if test="priceMin != null and priceMax != null">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue