|
@@ -0,0 +1,383 @@
|
|
|
+package com.ylx.web.controller.massage;
|
|
|
+
|
|
|
+import cn.hutool.core.io.FileUtil;
|
|
|
+import cn.hutool.extra.qrcode.QrCodeUtil;
|
|
|
+import cn.hutool.extra.qrcode.QrConfig;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
+import com.ylx.common.annotation.Log;
|
|
|
+import com.ylx.common.config.RuoYiConfig;
|
|
|
+import com.ylx.common.constant.Constants;
|
|
|
+import com.ylx.common.core.controller.BaseController;
|
|
|
+import com.ylx.common.core.domain.AjaxResult;
|
|
|
+import com.ylx.common.core.domain.model.WxLoginUser;
|
|
|
+import com.ylx.common.enums.BusinessType;
|
|
|
+import com.ylx.common.utils.MessageUtils;
|
|
|
+import com.ylx.common.utils.file.FileUploadUtils;
|
|
|
+import com.ylx.framework.manager.AsyncManager;
|
|
|
+import com.ylx.framework.manager.factory.AsyncFactory;
|
|
|
+import com.ylx.framework.web.service.WxTokenService;
|
|
|
+import com.ylx.massage.domain.CouponReceive;
|
|
|
+import com.ylx.massage.domain.TWxUser;
|
|
|
+import com.ylx.massage.service.CouponReceiveService;
|
|
|
+import com.ylx.massage.service.TWxUserService;
|
|
|
+import com.ylx.massage.service.TbFileService;
|
|
|
+import com.ylx.massage.utils.StringUtilsMassage;
|
|
|
+import com.ylx.massage.utils.WeChatUtil;
|
|
|
+import io.swagger.annotations.Api;
|
|
|
+import io.swagger.annotations.ApiOperation;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.BeanUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
|
+import org.springframework.stereotype.Controller;
|
|
|
+import org.springframework.web.bind.annotation.*;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.File;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.io.InputStreamReader;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+import static com.ylx.massage.utils.OtherUtil.verification;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author b16mt
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Controller
|
|
|
+@Api(tags = {"微信公众号sq"})
|
|
|
+@RequestMapping("/sq")
|
|
|
+public class WeSqController extends BaseController {
|
|
|
+
|
|
|
+ private final static String TOKEN = "abcd1234";
|
|
|
+ private final static String ENCODING = "UTF-8";
|
|
|
+ private final static String ACCESS_TOKEN = "access_token";
|
|
|
+ private final static String REFRESH_TOKEN = "refresh_token";
|
|
|
+ private final static String OPEN_ID = "openid";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 二维码保存路径
|
|
|
+ */
|
|
|
+ private String IMG_PATH = "D:\\Users\\";
|
|
|
+
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private WeChatUtil weChatUtil;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private TWxUserService wxUserService;
|
|
|
+
|
|
|
+ @Resource(name = "commonAsyncExecutor")
|
|
|
+ private ThreadPoolTaskExecutor threadPoolTaskExecutor;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private CouponReceiveService couponReceiveService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private WxTokenService wxTokenService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TbFileService tbFileService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信Token验证
|
|
|
+ *
|
|
|
+ * @param signature 微信加密签名
|
|
|
+ * @param timestamp 时间戳
|
|
|
+ * @param nonce 随机数
|
|
|
+ * @param echostr 随机字符串
|
|
|
+ * @param response HTTP响应对象
|
|
|
+ * @throws Exception 如果处理过程中出现错误
|
|
|
+ */
|
|
|
+ @GetMapping("/verifyToken")
|
|
|
+ @Log(title = "公众号pverifyToken", businessType = BusinessType.OTHER)
|
|
|
+ public void verifyToken(@RequestParam(value = "signature") String signature,
|
|
|
+ @RequestParam(value = "timestamp") String timestamp,
|
|
|
+ @RequestParam(value = "nonce") String nonce,
|
|
|
+ @RequestParam(value = "echostr") String echostr, HttpServletResponse response) throws Exception {
|
|
|
+
|
|
|
+ log.info("微信Token验证 入参: signature:{},timestamp:{},nonce:{},echostr:{},", signature, timestamp, nonce, echostr);
|
|
|
+ // 参数排序
|
|
|
+ String[] params = new String[]{timestamp, nonce, TOKEN};
|
|
|
+ Arrays.sort(params);
|
|
|
+
|
|
|
+ // 校验成功则响应 echostr,失败则不响应
|
|
|
+ if (verification(params, signature) && echostr != null) {
|
|
|
+ response.setCharacterEncoding(ENCODING);
|
|
|
+ response.getWriter().write(echostr);
|
|
|
+ response.getWriter().flush();
|
|
|
+ response.getWriter().close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @GetMapping("/setMenu")
|
|
|
+ @Log(title = "公众号pverifyToken", businessType = BusinessType.OTHER)
|
|
|
+ public Map<?,?> setMenu() {
|
|
|
+
|
|
|
+ //获取access_token
|
|
|
+ String token = weChatUtil.getToken();
|
|
|
+ //获取的二维码ticket
|
|
|
+ return weChatUtil.menuUtil(token);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+// @PostMapping("/verifyToken")
|
|
|
+// @Log(title = "公众号pverifyToken", businessType = BusinessType.OTHER)
|
|
|
+// public void pverifyToken(@RequestParam(value = "signature") String signature,
|
|
|
+// @RequestParam(value = "timestamp") String timestamp,
|
|
|
+// @RequestParam(value = "nonce") String nonce) {
|
|
|
+//
|
|
|
+// log.info("11111111111111111111111111111111111111111111");
|
|
|
+// // 参数排序
|
|
|
+// String[] params = new String[]{timestamp, nonce, TOKEN};
|
|
|
+// Arrays.sort(params);
|
|
|
+//
|
|
|
+//// {
|
|
|
+//// "signature": "63c8f3e1fb23d0d18f6d7ddf8019dc8a8737a04b",
|
|
|
+//// "openid": "oPYgb6qoOUXYIQLbB7f6zOF40kwk",
|
|
|
+//// "nonce": "1376426761",
|
|
|
+//// "timestamp": "1717569593"
|
|
|
+//// }
|
|
|
+//
|
|
|
+// }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理微信公众号请求信息
|
|
|
+ *
|
|
|
+ * @param request
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @RequestMapping("/verifyToken")
|
|
|
+ @ResponseBody
|
|
|
+ @Log(title = "处理微信公众号请求信息", businessType = BusinessType.OTHER)
|
|
|
+ public String handlePublicMsg(HttpServletRequest request) throws Exception {
|
|
|
+ log.info("处理微信公众号请求信息:{}", request.toString());
|
|
|
+ // 获得微信端返回的xml数据
|
|
|
+ InputStream is = null;
|
|
|
+ InputStreamReader isr = null;
|
|
|
+ BufferedReader br = null;
|
|
|
+ try {
|
|
|
+ is = request.getInputStream();
|
|
|
+ isr = new InputStreamReader(is, "utf-8");
|
|
|
+ br = new BufferedReader(isr);
|
|
|
+ String str = null;
|
|
|
+ StringBuffer returnXml = new StringBuffer();
|
|
|
+ while ((str = br.readLine()) != null) {
|
|
|
+ //返回的是xml数据
|
|
|
+ returnXml.append(str);
|
|
|
+ }
|
|
|
+ log.info("微信端返回的xml数据:{}", returnXml);
|
|
|
+ Map<String, String> encryptMap = WeChatUtil.xmlToMap(returnXml.toString());
|
|
|
+ // 得到公众号传来的加密信息并解密,得到的是明文xml数据
|
|
|
+// String decryptXml = WXPublicUtils.decrypt(encryptMap.get("Encrypt"));
|
|
|
+ // 将xml数据转换为map
|
|
|
+// Map<String, String> decryptMap = WeChatUtil.xmlToMap(decryptXml);
|
|
|
+
|
|
|
+ // 区分消息类型
|
|
|
+ String msgType = encryptMap.get("MsgType");
|
|
|
+ // 普通消息
|
|
|
+ if ("text".equals(msgType)) { // 文本消息
|
|
|
+ // todo 处理文本消息
|
|
|
+ } else if ("image".equals(msgType)) { // 图片消息
|
|
|
+ // todo 处理图片消息
|
|
|
+ } else if ("voice".equals(msgType)) { //语音消息
|
|
|
+ // todo 处理语音消息
|
|
|
+ } else if ("video".equals(msgType)) { // 视频消息
|
|
|
+ // todo 处理视频消息
|
|
|
+ } else if ("shortvideo".equals(msgType)) { // 小视频消息
|
|
|
+ // todo 处理小视频消息
|
|
|
+ } else if ("location".equals(msgType)) { // 地理位置消息
|
|
|
+ // todo 处理地理位置消息
|
|
|
+ } else if ("link".equals(msgType)) { // 链接消息
|
|
|
+ // todo 处理链接消息
|
|
|
+ }
|
|
|
+ // 事件推送
|
|
|
+ else if ("event".equals(msgType)) { // 事件消息
|
|
|
+ // 区分事件推送
|
|
|
+ String event = encryptMap.get("Event");
|
|
|
+ if ("subscribe".equals(event)) { // 订阅事件 或 未关注扫描二维码事件
|
|
|
+ return getString(encryptMap);
|
|
|
+ } else if ("unsubscribe".equals(event)) { // 取消订阅事件
|
|
|
+ // todo 处理取消订阅事件
|
|
|
+ } else if ("SCAN".equals(event)) { // 已关注扫描二维码事件
|
|
|
+ return getString(encryptMap);
|
|
|
+ } else if ("LOCATION".equals(event)) { // 上报地理位置事件
|
|
|
+ // todo 处理上报地理位置事件
|
|
|
+ } else if ("CLICK".equals(event)) { // 点击菜单拉取消息时的事件推送事件
|
|
|
+ // todo 处理点击菜单拉取消息时的事件推送事件
|
|
|
+ } else if ("VIEW".equals(event)) { // 点击菜单跳转链接时的事件推送
|
|
|
+ // todo 处理点击菜单跳转链接时的事件推送
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("处理微信公众号请求信息,失败", e);
|
|
|
+ } finally {
|
|
|
+ if (null != is) {
|
|
|
+ is.close();
|
|
|
+ }
|
|
|
+ if (null != isr) {
|
|
|
+ isr.close();
|
|
|
+ }
|
|
|
+ if (null != br) {
|
|
|
+ br.close();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String getString(Map<String, String> encryptMap) throws Exception {
|
|
|
+ // 返回消息时ToUserName的值与FromUserName的互换
|
|
|
+ Map<String, String> returnMap = new HashMap<>();
|
|
|
+
|
|
|
+ //添加新用户
|
|
|
+ TWxUser fromUserName = wxUserService.getByOpenId(encryptMap.get("FromUserName"));
|
|
|
+ if (fromUserName == null) {
|
|
|
+ fromUserName = new TWxUser();
|
|
|
+ }
|
|
|
+ fromUserName.setcOpenid(encryptMap.get("FromUserName"));
|
|
|
+ fromUserName.setcUpUser(StringUtilsMassage.afterString(encryptMap.get("EventKey"), "qrscene_"));
|
|
|
+ wxUserService.saveOrUpdate(fromUserName);
|
|
|
+
|
|
|
+ returnMap.put("ToUserName", encryptMap.get("FromUserName"));
|
|
|
+ returnMap.put("FromUserName", encryptMap.get("ToUserName"));
|
|
|
+ returnMap.put("CreateTime", new Date().getTime() + "");
|
|
|
+ returnMap.put("MsgType", "text");
|
|
|
+ returnMap.put("Content", "欢迎来到舒压乐园");
|
|
|
+ String encryptMsg = weChatUtil.mapToXml(returnMap).toString();
|
|
|
+ return encryptMsg;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 获取微信code
|
|
|
+ *
|
|
|
+ * @param state 状态参数
|
|
|
+ */
|
|
|
+ @ApiOperation("获取微信code")
|
|
|
+ @Log(title = "获取微信code", businessType = BusinessType.OTHER)
|
|
|
+ @GetMapping("/getCode")
|
|
|
+ public String weiXinLogin(String state) {
|
|
|
+// QrConfig config = new QrConfig(300, 300);
|
|
|
+ // 设置边距,即二维码和背景之间的边距
|
|
|
+// config.setMargin(1);
|
|
|
+ // 生成二维码到文件,也可以到流
|
|
|
+ String code = weChatUtil.getCode(state);
|
|
|
+ log.info("code:{}", code);
|
|
|
+// QrCodeUtil.generate(code, config,
|
|
|
+// FileUtil.file(IMG_PATH));
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取token和userInfo
|
|
|
+ *
|
|
|
+ * @param code 微信授权码
|
|
|
+ * @return 访问令牌
|
|
|
+ */
|
|
|
+ @GetMapping("/getAccessToken")
|
|
|
+ @Log(title = "公众号网页登录", businessType = BusinessType.OTHER)
|
|
|
+ public String getAccessToken(@RequestParam String code) {
|
|
|
+
|
|
|
+ // 发送get请求获取 AccessToken
|
|
|
+ Map<?, ?> result = weChatUtil.getAccessToken(code);
|
|
|
+ String accessToken = result.get(ACCESS_TOKEN).toString();
|
|
|
+ String refreshToken = result.get(REFRESH_TOKEN).toString();
|
|
|
+ String openid = result.get(OPEN_ID).toString();
|
|
|
+
|
|
|
+ // 如果用户是第一次进行微信公众号授权
|
|
|
+ // 进行这一步时用户应点击了同意授权按钮
|
|
|
+ String userInfoJsom = weChatUtil.getUserInfo(accessToken, openid);
|
|
|
+ // 解析JSON数据
|
|
|
+ JSONObject jsonObject = new JSONObject(userInfoJsom);
|
|
|
+ log.info("公众号网页登录,{}",jsonObject);
|
|
|
+ // 将用户信息保存到数据库中
|
|
|
+ LambdaQueryWrapper<TWxUser> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ objectLambdaQueryWrapper.eq(TWxUser::getcOpenid, openid);
|
|
|
+ TWxUser user = wxUserService.getOne(objectLambdaQueryWrapper);
|
|
|
+ if (user == null || user.getcNickName() == null) {
|
|
|
+ user = new TWxUser();
|
|
|
+ user.setcOpenid(openid);
|
|
|
+ user.setcNickName(jsonObject.get("nickname").toString());
|
|
|
+ user.setcIcon(jsonObject.get("headimgurl").toString());
|
|
|
+ user.setcSessionKey(refreshToken);
|
|
|
+// user.setcPhone(phoneNumber);
|
|
|
+ wxUserService.save(user);
|
|
|
+ //异步 添加新人优惠卷
|
|
|
+ TWxUser finalUser = user;
|
|
|
+ threadPoolTaskExecutor.submit(() -> couponReceiveService.submit(new CouponReceive().setOpenid(finalUser.getcOpenid()).setCouponId("1")));
|
|
|
+ user.setId(user.getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ WxLoginUser wxUser = new WxLoginUser();
|
|
|
+ BeanUtils.copyProperties(user, wxUser);
|
|
|
+ // 生成并返回令牌
|
|
|
+ String token = wxTokenService.createToken(wxUser);
|
|
|
+ if (token == null || token.isEmpty()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ wxUser.setToken(token);
|
|
|
+ // 返回用户信息
|
|
|
+ // 记录登录信息
|
|
|
+ AsyncManager.me().execute(AsyncFactory.recordLogininfor(wxUser.getCOpenid(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
|
|
|
+// return R.ok(wxUser);
|
|
|
+
|
|
|
+ return "redirect:" + "https://test.baoxianzhanggui.com/fragrance/#/pages/my/wxLogin" + "?openid=" + openid;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 刷新token,微信提供的token是有限时间的,但是对于财务报销系统仅需授权一次的情况下一般不需要进行更新
|
|
|
+ *
|
|
|
+ * @return accessToken
|
|
|
+ */
|
|
|
+ @GetMapping("/refreshToken")
|
|
|
+ public String refreshToken() {
|
|
|
+
|
|
|
+ WxLoginUser wxLoginUser = this.getWxLoginUser();
|
|
|
+ TWxUser user = wxUserService.getByOpenId(wxLoginUser.getCOpenid());
|
|
|
+ if (user == null) {
|
|
|
+ throw new RuntimeException("用户不存在");
|
|
|
+ }
|
|
|
+ // 发送get请求获取 RefreshToken
|
|
|
+ Map<?, ?> result = weChatUtil.refreshToken(user.getcSessionKey());
|
|
|
+ String accessToken = result.get(ACCESS_TOKEN).toString();
|
|
|
+ String refreshToken = result.get(REFRESH_TOKEN).toString();
|
|
|
+ // 更新用户信息
|
|
|
+ user.setcSessionKey(refreshToken);
|
|
|
+ // 存储数据库
|
|
|
+ wxUserService.updateById(user);
|
|
|
+ return accessToken;
|
|
|
+ }
|
|
|
+
|
|
|
+ @ApiOperation("获取公众号二维码")
|
|
|
+ @RequestMapping(value = "getwxQrCode", method = RequestMethod.GET)
|
|
|
+ public Map<?, ?> getWxQrCodeUtil(@RequestParam String openId) {
|
|
|
+
|
|
|
+ //获取access_token
|
|
|
+ String token = weChatUtil.getToken();
|
|
|
+ //获取的二维码ticket
|
|
|
+ return weChatUtil.getTicket(token, openId);
|
|
|
+ }
|
|
|
+
|
|
|
+ @ApiOperation("获取公众号网页二维码")
|
|
|
+ @GetMapping("/getweQrCode")
|
|
|
+ public AjaxResult weiXinLogin1(String openId) {
|
|
|
+ QrConfig config = new QrConfig(300, 300);
|
|
|
+ // 设置边距,即二维码和背景之间的边距
|
|
|
+ config.setMargin(1);
|
|
|
+ // 生成二维码到文件,也可以到流
|
|
|
+ String code = "https://www.baidu.com?openId=" + openId;
|
|
|
+ log.info("code:{}", code);
|
|
|
+ String str = IMG_PATH;
|
|
|
+ File generate = QrCodeUtil.generate(code, config, FileUtil.file(RuoYiConfig.getUploadPath() + "/code.png"));
|
|
|
+
|
|
|
+ MultipartFile multipartFile = FileUploadUtils.getMultipartFile(generate);
|
|
|
+ return tbFileService.uploadFile(multipartFile);
|
|
|
+ }
|
|
|
+}
|