123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- 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.R;
- import com.ylx.common.core.domain.model.WxLoginUser;
- import com.ylx.common.core.redis.RedisCache;
- import com.ylx.common.enums.BusinessType;
- import com.ylx.common.utils.MessageUtils;
- import com.ylx.common.utils.StringUtils;
- import com.ylx.common.utils.file.FileUploadUtils;
- import com.ylx.framework.config.ServerConfig;
- 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.DateTimeUtils;
- import com.ylx.massage.utils.JsSignUtil;
- 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.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 java.util.concurrent.TimeUnit;
- import static com.ylx.massage.utils.OtherUtil.verification;
- /**
- * @author b16mt
- */
- @Slf4j
- @RestController
- @Api(tags = {"微信公众号"})
- @RequestMapping("/weChat")
- public class WeChatController 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;
- @Resource
- private JsSignUtil jsSignUtil;
- @Autowired
- private TbFileService tbFileService;
- @Autowired
- private RedisCache redisCache;
- /**
- * 微信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")
- @ApiOperation("设置菜单")
- @Log(title = "设置菜单", businessType = BusinessType.OTHER)
- public Map<?,?> setMenu() {
- //获取access_token
- String token = weChatUtil.getToken();
- //获取的二维码ticket
- return weChatUtil.menuUtil(token);
- }
- @GetMapping("/getSignature")
- @ApiOperation("前端获取jssdk签名")
- @Log(title = "前端获取jssdk签名", businessType = BusinessType.OTHER)
- public Map<?,?> getSignature(String url) {
- //获取access_token
- String token = weChatUtil.getToken();
- //获取jsapi_ticket
- String jsapiTicket = weChatUtil.getJsapiTicket(token);
- //生成签名
- return jsSignUtil.sign(url,jsapiTicket);
- }
- /**
- * 处理微信公众号请求信息
- *
- * @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);
- redisCache.setCacheObject("code", state, 10, TimeUnit.MINUTES);
- log.info("code:{}", code);
- // QrCodeUtil.generate(code, config,
- // FileUtil.file(IMG_PATH));
- return code;
- }
- /**
- * 获取token和userInfo
- *
- * @param code 微信授权码
- * @return 访问令牌
- */
- @GetMapping("/getAccessToken")
- @ApiOperation("公众号网页登录")
- @Log(title = "公众号网页登录", businessType = BusinessType.OTHER)
- public R<WxLoginUser> 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 || StringUtils.isEmpty(user.getcNickName())) {
- if(user == null){
- user = new TWxUser();
- user.setcOpenid(openid);
- TWxUser finalUser = user;
- //异步 添加新人优惠卷
- // threadPoolTaskExecutor.submit(() -> couponReceiveService.submit(new CouponReceive().setOpenid(finalUser.getcOpenid()).setCouponId("1")));
- }
- user.setcOpenid(openid);
- user.setcNickName(jsonObject.get("nickname").toString());
- user.setcIcon(jsonObject.get("headimgurl").toString());
- user.setcSessionKey(refreshToken);
- // user.setcPhone(phoneNumber);
- wxUserService.saveOrUpdate(user);
- user.setId(user.getId());
- }
- WxLoginUser wxUser = new WxLoginUser();
- BeanUtils.copyProperties(user, wxUser);
- // 生成并返回令牌
- String token = wxTokenService.createToken(wxUser);
- if (token == null || token.isEmpty()) {
- return R.fail("生成令牌失败");
- }
- wxUser.setToken(token);
- // 返回用户信息
- // 记录登录信息
- AsyncManager.me().execute(AsyncFactory.recordLogininfor(wxUser.getCOpenid(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
- return R.ok(wxUser);
- }
- /**
- * 刷新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);
- }
- }
|