1
This commit is contained in:
parent
6147418efe
commit
0b93959d61
@ -70,6 +70,11 @@
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-generator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-common</artifactId>
|
||||
<version>4.6.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
@ -2,22 +2,15 @@ package com.ruoyi.api;
|
||||
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.ruoyi.busi.utils.WeChatUtils;
|
||||
import com.ruoyi.common.annotation.Anonymous;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.model.GzhLoginBody;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.member.service.IMemberUserService;
|
||||
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -30,13 +23,12 @@ public class WxApi {
|
||||
private IMemberUserService memberUserService;
|
||||
|
||||
|
||||
|
||||
@GetMapping("/getCodeUrl")
|
||||
@Anonymous
|
||||
public Map<String, String> getCodeUrl(String userType,String url) {
|
||||
public Map<String, String> getCodeUrl(String userType, String url) {
|
||||
Map<String, String> res = new HashMap<>();
|
||||
res.put("codeUrl", weChatUtils.getCodeUrl("https://www.ddtg.site/#/"+url, userType));
|
||||
return res;
|
||||
res.put("codeUrl", weChatUtils.getCodeUrl("https://www.ddtg.site/#/" + url, userType));
|
||||
return res;
|
||||
}
|
||||
|
||||
@GetMapping("/getWebAccessTokenAndOpenid")
|
||||
@ -47,15 +39,13 @@ public class WxApi {
|
||||
|
||||
@PostMapping("/gzhLogin")
|
||||
@Anonymous
|
||||
public AjaxResult gzhLogin(@RequestBody GzhLoginBody gzhLoginBody)
|
||||
{
|
||||
public AjaxResult gzhLogin(@RequestBody GzhLoginBody gzhLoginBody) {
|
||||
JSONObject userInfo = weChatUtils.getUserInfo(gzhLoginBody.getAccess_token(), gzhLoginBody.getOpenid());
|
||||
//如果解析成功,获取token
|
||||
String token = memberUserService.gzhLogin(gzhLoginBody.getOpenid(),userInfo);
|
||||
String token = memberUserService.gzhLogin(gzhLoginBody.getOpenid(), userInfo);
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
ajax.put(Constants.TOKEN, token);
|
||||
return ajax;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
58
ruoyi-admin/src/main/java/com/ruoyi/api/WxMsgApi.java
Normal file
58
ruoyi-admin/src/main/java/com/ruoyi/api/WxMsgApi.java
Normal file
@ -0,0 +1,58 @@
|
||||
package com.ruoyi.api;
|
||||
|
||||
import com.ruoyi.api.domain.WeChatMessage;
|
||||
import com.ruoyi.api.service.IWeChatMessageService;
|
||||
import com.ruoyi.busi.utils.WeChatUtils;
|
||||
import com.ruoyi.common.annotation.Anonymous;
|
||||
import com.wechat.pay.java.core.http.HttpMethod;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/wxMsgApi")
|
||||
public class WxMsgApi {
|
||||
@Autowired
|
||||
private WeChatUtils weChatUtils;
|
||||
@Resource
|
||||
private IWeChatMessageService weChatMessageService;
|
||||
|
||||
/**
|
||||
* 校验签名
|
||||
*
|
||||
* @param message {@link WeChatMessage}
|
||||
* @param request {@link HttpServletRequest}
|
||||
* @return java.lang.Object
|
||||
* @author PQZ
|
||||
* @date 12:17 2025/4/25
|
||||
**/
|
||||
@RequestMapping("/message")
|
||||
@Anonymous
|
||||
public void register(WeChatMessage message, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
String method = request.getMethod();
|
||||
if (HttpMethod.GET.name().equalsIgnoreCase(method)) {
|
||||
String echostr = weChatMessageService.checkSignature(message);
|
||||
response.getOutputStream().write(echostr.getBytes());
|
||||
} else if (HttpMethod.POST.name().equalsIgnoreCase(method)) {
|
||||
// 进入POST聊天处理
|
||||
// 将请求、响应的编码均设置为UTF-8(防止中文乱码)
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
// 接收消息并返回消息
|
||||
String result = weChatMessageService.acceptMessage(request, response);
|
||||
// 响应消息
|
||||
PrintWriter out = response.getWriter();
|
||||
out.print(result);
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.ruoyi.api.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class WeChatMessage {
|
||||
|
||||
|
||||
/**
|
||||
* 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数
|
||||
*/
|
||||
private String signature;
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
private String timestamp;
|
||||
|
||||
/**
|
||||
* 随机数
|
||||
*/
|
||||
private String nonce;
|
||||
|
||||
/**
|
||||
* 随机字符串
|
||||
*/
|
||||
private String echostr;
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
package com.ruoyi.api.service;
|
||||
|
||||
import com.ruoyi.api.domain.WeChatMessage;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 微信消息自动回复Service
|
||||
*
|
||||
* @author vinjor-m
|
||||
* @date 2025-03-17
|
||||
*/
|
||||
public interface IWeChatMessageService {
|
||||
/**
|
||||
* 校验签名
|
||||
*
|
||||
* @param message {@link WeChatMessage}
|
||||
* @return java.lang.String
|
||||
* @author PQZ
|
||||
* @date 12:08 2025/4/25
|
||||
**/
|
||||
String checkSignature(WeChatMessage message);
|
||||
|
||||
/**
|
||||
* 发送消息返回
|
||||
*
|
||||
* @param request {@link HttpServletRequest}
|
||||
* @param response {@link HttpServletResponse}
|
||||
* @return java.lang.String
|
||||
* @author PQZ
|
||||
* @date 12:52 2025/4/25
|
||||
**/
|
||||
String acceptMessage(HttpServletRequest request, HttpServletResponse response);
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
package com.ruoyi.api.service.impl;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.json.JSONArray;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.ruoyi.api.domain.WeChatMessage;
|
||||
import com.ruoyi.api.service.IWeChatMessageService;
|
||||
import com.ruoyi.api.util.HttpUtils;
|
||||
import com.ruoyi.api.util.MessageUtil;
|
||||
import com.ruoyi.base.domain.BaseConfig;
|
||||
import com.ruoyi.base.service.IBaseConfigService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 会员卡Service业务层处理
|
||||
*
|
||||
* @author vinjor-m
|
||||
* @date 2025-03-17
|
||||
*/
|
||||
@Service
|
||||
public class WeChatMessageServiceImpl implements IWeChatMessageService {
|
||||
|
||||
|
||||
@Value("${wx-app.appId}")
|
||||
private String appId;
|
||||
|
||||
@Value("${wx-app.appSecret}")
|
||||
private String appSecret;
|
||||
|
||||
@Value("${wx-app.token}")
|
||||
private String token;
|
||||
|
||||
@Resource
|
||||
private IBaseConfigService configService;
|
||||
|
||||
/**发送消息url*/
|
||||
private static String SEND_URL = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
|
||||
|
||||
/**获取accessTokenUrl*/
|
||||
private String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 校验签名
|
||||
*
|
||||
* @param message {@link WeChatMessage}
|
||||
* @return java.lang.String
|
||||
* @author PQZ
|
||||
* @date 12:08 2025/4/25
|
||||
**/
|
||||
@Override
|
||||
public String checkSignature(WeChatMessage message) {
|
||||
String signature = message.getSignature();
|
||||
String timestamp = message.getTimestamp();
|
||||
String nonce = message.getNonce();
|
||||
//必须与请求参数中的token一致
|
||||
List<String> list = new ArrayList<>();
|
||||
list.add(token);
|
||||
list.add(timestamp);
|
||||
list.add(nonce);
|
||||
// 排序跟使用hutool工具类 进行字典排序跟加密
|
||||
String str = list.stream().sorted().collect(Collectors.joining());
|
||||
String tmpStr = SecureUtil.sha1(str);
|
||||
if (signature.equals(tmpStr)) {
|
||||
return message.getEchostr();
|
||||
} else {
|
||||
return "shibai";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息返回
|
||||
*
|
||||
* @param request {@link HttpServletRequest}
|
||||
* @param response {@link HttpServletResponse}
|
||||
* @return java.lang.String
|
||||
* @author PQZ
|
||||
* @date 12:52 2025/4/25
|
||||
**/
|
||||
@Override
|
||||
public String acceptMessage(HttpServletRequest request, HttpServletResponse response) {
|
||||
//返回值
|
||||
String result = "success";
|
||||
try {
|
||||
request.setCharacterEncoding("UTF-8");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
Map<String, String> requestMap = MessageUtil.parseXml(request);
|
||||
// 发送者的openid
|
||||
String fromUserName = requestMap.get("FromUserName");
|
||||
// 小程序的原始ID
|
||||
String toUserName = requestMap.get("ToUserName");
|
||||
// 消息类型
|
||||
String msgType = requestMap.get("MsgType");
|
||||
// 文本消息内容
|
||||
String content = requestMap.get("Content");
|
||||
// 事件类型
|
||||
String event = requestMap.get("Event");
|
||||
StringBuilder contentMessage = new StringBuilder();
|
||||
String contentStr = "嗨,欢迎加入通告快捷,您想咨询那个问题,请点击选择";
|
||||
String jqHtml = "1111";
|
||||
String xsHtml = "1111";
|
||||
String tgzHtml = "https://www.ddtg.site/#/pages/mine/member/member-card?userType=01";
|
||||
String bzHtml = "https://www.ddtg.site/#/pages/mine/member/member-card?userType=02";
|
||||
String jqStr = "<a href=\""+jqHtml+"\">1、进群</a>";
|
||||
String xsStr = "<a href=\""+xsHtml+"\">2、新手教程</a>";
|
||||
String tgzStr = "<a href=\""+tgzHtml+"\">3、通告主卡</a>";
|
||||
String bzStr = "<a href=\""+bzHtml+"\">4、博主VIP</a>";
|
||||
contentMessage.append(contentStr).append("\n")
|
||||
.append(jqStr).append("\n")
|
||||
.append(xsStr).append("\n")
|
||||
.append(tgzStr).append("\n")
|
||||
.append(bzStr).append("\n");
|
||||
if (msgType.equals("event")) {
|
||||
sendCustomerTextMessage(fromUserName, contentMessage.toString(), getAccessToken());
|
||||
} else if (msgType.equals("text")) {
|
||||
if (content.equals("0")) {
|
||||
return switchCustomerService(fromUserName, toUserName);
|
||||
} else {
|
||||
sendCustomerTextMessage(fromUserName, contentMessage.toString(), getAccessToken());
|
||||
}
|
||||
} else {
|
||||
sendCustomerTextMessage(fromUserName, contentMessage.toString(), getAccessToken());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void sendCustomerTextMessage(String openid, String text, String accessToken) throws IOException {
|
||||
HashMap<String, Object> map_content = new HashMap<>();
|
||||
map_content.put("content", text);
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("touser", openid);
|
||||
map.put("msgtype", "text");
|
||||
map.put("text", map_content);
|
||||
String content = JSON.toJSONString(map);
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
HttpEntity httpEntity = new HttpEntity(map, headers);
|
||||
HttpUtils.sendPostRequest(SEND_URL + "?access_token=" + accessToken, HttpMethod.POST, httpEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 人工服务
|
||||
*
|
||||
* @param fromUserName
|
||||
* @param toUserName
|
||||
* @return
|
||||
*/
|
||||
public String switchCustomerService(String fromUserName, String toUserName) {
|
||||
return "<xml>\n" +
|
||||
" <ToUserName><![CDATA[" + fromUserName + "]]></ToUserName>\n" +
|
||||
" <FromUserName><![CDATA[" + toUserName + "]]></FromUserName>\n" +
|
||||
" <CreateTime>" + System.currentTimeMillis() / 1000 + "</CreateTime>\n" +
|
||||
" <MsgType><![CDATA[transfer_customer_service]]></MsgType>\n" +
|
||||
"</xml>";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取accessToken
|
||||
* @author PQZ
|
||||
* @date 16:12 2025/4/25
|
||||
* @return java.lang.String
|
||||
**/
|
||||
public String getAccessToken() {
|
||||
//拼接url【传入appId和secret】
|
||||
url = url.replace("APPID", appId).replace("APPSECRET", appSecret);
|
||||
String str = HttpUtils.sendGetRequest(url);
|
||||
JSONObject jsonObject = JSONObject.parseObject(str);
|
||||
return jsonObject.getString("access_token");
|
||||
}
|
||||
|
||||
|
||||
}
|
36
ruoyi-admin/src/main/java/com/ruoyi/api/util/HttpUtils.java
Normal file
36
ruoyi-admin/src/main/java/com/ruoyi/api/util/HttpUtils.java
Normal file
@ -0,0 +1,36 @@
|
||||
package com.ruoyi.api.util;
|
||||
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 客服功能 - 消息发送请求工具类
|
||||
* Created by Lance on 2020/10/10 17:52
|
||||
*/
|
||||
public class HttpUtils {
|
||||
|
||||
/**
|
||||
* Get 发送的请求
|
||||
* @param url
|
||||
* @return
|
||||
*/
|
||||
public static String sendGetRequest(String url) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
return restTemplate.getForObject(url, String.class);
|
||||
}
|
||||
|
||||
public static String sendPostRequest(String url, HttpMethod method, HttpEntity<Map<String, Object>> httpEntity) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, method, httpEntity, String.class);
|
||||
return response.getBody();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,49 @@
|
||||
package com.ruoyi.api.util;
|
||||
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MessageUtil {
|
||||
// 请求消息类型:文本
|
||||
public static final String REQ_MESSAGE_TYPE_TEXT = "text";
|
||||
/**
|
||||
* 解析微信发来的请求(XML)
|
||||
*
|
||||
* @param request
|
||||
* @return Map<String, String>
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
|
||||
// 将解析结果存储在HashMap中
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
|
||||
// 从request中取得输入流
|
||||
InputStream inputStream = request.getInputStream();
|
||||
// 读取输入流
|
||||
SAXReader reader = new SAXReader();
|
||||
Document document = reader.read(inputStream);
|
||||
// 得到xml根元素
|
||||
Element root = document.getRootElement();
|
||||
// 得到根元素的所有子节点
|
||||
List<Element> elementList = root.elements();
|
||||
|
||||
// 遍历所有子节点
|
||||
for (Element e : elementList){
|
||||
map.put(e.getName(), e.getText());
|
||||
}
|
||||
|
||||
// 释放资源
|
||||
inputStream.close();
|
||||
inputStream = null;
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.ruoyi.base.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
@ -8,11 +9,20 @@ import com.ruoyi.base.domain.BaseConfig;
|
||||
|
||||
/**
|
||||
* 基础配置-账户配置、小程序配置的内容Service接口
|
||||
*
|
||||
*
|
||||
* @author vinjor-m
|
||||
* @date 2025-03-17
|
||||
*/
|
||||
public interface IBaseConfigService extends IService<BaseConfig>
|
||||
{
|
||||
public interface IBaseConfigService extends IService<BaseConfig> {
|
||||
IPage<BaseConfig> queryListPage(BaseConfig pageReqVO, Page<BaseConfig> page);
|
||||
|
||||
/**
|
||||
* 通过code获取配置
|
||||
*
|
||||
* @param code code
|
||||
* @return java.util.List<com.ruoyi.base.domain.BaseConfig>
|
||||
* @author PQZ
|
||||
* @date 16:17 2025/4/25
|
||||
**/
|
||||
List<BaseConfig> queryConfigByCode(String code);
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package com.ruoyi.base.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.ruoyi.common.core.domain.DlBaseEntity;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@ -27,4 +30,20 @@ public class BaseConfigServiceImpl extends ServiceImpl<BaseConfigMapper,BaseConf
|
||||
public IPage<BaseConfig> queryListPage(BaseConfig pageReqVO, Page<BaseConfig> page) {
|
||||
return baseConfigMapper.queryListPage(pageReqVO, page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过code获取配置
|
||||
*
|
||||
* @param code code
|
||||
* @return java.util.List<com.ruoyi.base.domain.BaseConfig>
|
||||
* @author PQZ
|
||||
* @date 16:17 2025/4/25
|
||||
**/
|
||||
@Override
|
||||
public List<BaseConfig> queryConfigByCode(String code) {
|
||||
LambdaQueryWrapper<BaseConfig> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
lambdaQueryWrapper.eq(DlBaseEntity::getDelFlag,0)
|
||||
.eq(BaseConfig::getCode,code);
|
||||
return list(lambdaQueryWrapper);
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +147,9 @@ xss:
|
||||
wx-app:
|
||||
appId: wxd96fda6510adb6d3
|
||||
appSecret: 2d3bf7172d09966bd98e1611117c2cb0
|
||||
token: tgxcxtoken
|
||||
aesKey: afBZchk5wSFaldDkZB9DZ9Ib6JUV4NwMARaRThsRFqQ
|
||||
msgDataFormat: XML
|
||||
wxpay:
|
||||
#微信公众号appid
|
||||
appId: wx7d10b0fa4886a583
|
||||
|
Loading…
Reference in New Issue
Block a user