parent
d950819399
commit
41dcf52b25
@ -0,0 +1,98 @@
|
||||
package com.ruoyi.system.controller;
|
||||
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.system.domain.dto.request.WeChatCodeRequest;
|
||||
import com.ruoyi.system.domain.dto.request.WeChatRequest;
|
||||
import com.ruoyi.system.service.WeChatService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 微信签名
|
||||
*
|
||||
* @Author: wu
|
||||
* @DateTime: 2023/4/25 9:14
|
||||
*/
|
||||
@Api(tags = "微信签名")
|
||||
@RestController
|
||||
@RequestMapping("/shian/wechat")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class WeChatController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private WeChatService weChatService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取微信accessToken
|
||||
*
|
||||
* @return accessToken
|
||||
*/
|
||||
@ApiOperation("获取微信accessToken")
|
||||
@GetMapping("/findAccessToken")
|
||||
public AjaxResult findAccessToken() {
|
||||
|
||||
return AjaxResult.success(weChatService.findAccessToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信二维码
|
||||
*
|
||||
* @param req 获取小程序码请求类
|
||||
* @return 微信二维码二进制
|
||||
*/
|
||||
@ApiOperation("获取微信二维码")
|
||||
@PostMapping("/findWxCode")
|
||||
public AjaxResult findWxCode(@RequestBody WeChatCodeRequest req) {
|
||||
|
||||
return AjaxResult.success(weChatService.findWxCode(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信手机号
|
||||
*
|
||||
* @param code 手机号获取凭证
|
||||
* @return 手机号
|
||||
*/
|
||||
@ApiOperation("获取微信手机号")
|
||||
@GetMapping("/getUserPhoneNumber")
|
||||
public AjaxResult getUserPhoneNumber(String code) {
|
||||
|
||||
return AjaxResult.success(weChatService.getUserPhoneNumber(code));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信jsapiTicket
|
||||
*
|
||||
* @return jsapiTicket
|
||||
*/
|
||||
@ApiOperation("获取微信jsapiTicket")
|
||||
@GetMapping("/findJsapiTicket")
|
||||
public AjaxResult findJsapiTicket() {
|
||||
|
||||
return AjaxResult.success(weChatService.findJsapiTicket());
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信获取签名
|
||||
*
|
||||
* @param req 请求类
|
||||
* @return 微信签名
|
||||
*/
|
||||
@ApiOperation("微信获取签名")
|
||||
@GetMapping("/findSignature")
|
||||
public AjaxResult findSignature(@Validated WeChatRequest req) {
|
||||
|
||||
return AjaxResult.success(weChatService.findSignature(req));
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.ruoyi.system.domain.dto.request;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 微信获取签名请求类
|
||||
*
|
||||
* @Author: wu
|
||||
* @DateTime: 2023/4/25 10:37
|
||||
*/
|
||||
@Data
|
||||
@ApiModel("微信获取签名请求类")
|
||||
public class WeChatRequest implements Serializable {
|
||||
private static final long serialVersionUID = 8932390218136420099L;
|
||||
|
||||
/**
|
||||
* 随机字符串
|
||||
*/
|
||||
@ApiModelProperty(value = "随机字符串", required = true)
|
||||
@NotBlank(message = "字符串不能为空")
|
||||
private String noncestr;
|
||||
|
||||
/**
|
||||
* 时间戳
|
||||
*/
|
||||
@ApiModelProperty(value = "时间戳", required = true)
|
||||
@NotBlank(message = "时间戳不能为空")
|
||||
private String timestamp;
|
||||
|
||||
/**
|
||||
* 当前网页的URL
|
||||
*/
|
||||
@ApiModelProperty(value = "当前网页的URL", required = true)
|
||||
@NotBlank(message = "当前网页的URL不能为空")
|
||||
private String url;
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package com.ruoyi.system.service;
|
||||
|
||||
|
||||
import com.ruoyi.system.domain.dto.request.WeChatCodeRequest;
|
||||
import com.ruoyi.system.domain.dto.request.WeChatRequest;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 微信接口业务层
|
||||
*
|
||||
* @Author: wu
|
||||
* @DateTime: 2023/4/25 9:30
|
||||
*/
|
||||
public interface WeChatService {
|
||||
|
||||
/**
|
||||
* 获取微信accessToken
|
||||
*
|
||||
* @return 微信accessToken
|
||||
*/
|
||||
String findAccessToken();
|
||||
|
||||
/**
|
||||
* 获取微信jsapiTicket
|
||||
*
|
||||
* @return jsapiTicket
|
||||
*/
|
||||
String findJsapiTicket();
|
||||
|
||||
/**
|
||||
* 获取微信签名
|
||||
*
|
||||
* @param req 请求类
|
||||
* @return 微信签名
|
||||
*/
|
||||
String findSignature(WeChatRequest req);
|
||||
|
||||
/**
|
||||
* 获取微信手机号
|
||||
*
|
||||
* @param code 手机号获取凭证
|
||||
* @return 手机号
|
||||
*/
|
||||
Map<String, Object> getUserPhoneNumber(String code);
|
||||
|
||||
/**
|
||||
* 获取微信二维码
|
||||
*
|
||||
* @param req 获取小程序码请求类
|
||||
* @return 微信二维码二进制
|
||||
*/
|
||||
byte[] findWxCode(WeChatCodeRequest req);
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
package com.ruoyi.system.service.impl;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.ruoyi.common.constant.TokenConstants;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.system.domain.dto.request.WeChatCodeRequest;
|
||||
import com.ruoyi.system.domain.dto.request.WeChatRequest;
|
||||
import com.ruoyi.system.service.WeChatService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 微信业务实现层
|
||||
*
|
||||
* @Author: wu
|
||||
* @DateTime: 2023/4/25 9:31
|
||||
*/
|
||||
@Service
|
||||
public class WeChatServiceImpl implements WeChatService {
|
||||
|
||||
@Value("${wechat.appid}")
|
||||
private String appid;
|
||||
|
||||
@Value("${wechat.secret}")
|
||||
private String secret;
|
||||
|
||||
@Resource
|
||||
private RedisCache redisCache;
|
||||
|
||||
/**
|
||||
* sha摘要算法
|
||||
*
|
||||
* @param str 生成摘要的字符串
|
||||
* @return 摘要
|
||||
* @throws NoSuchAlgorithmException 算法不存在异常
|
||||
*/
|
||||
private String SHA1(String str) throws NoSuchAlgorithmException {
|
||||
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
|
||||
crypt.reset();
|
||||
crypt.update(str.getBytes());
|
||||
Formatter formatter = new Formatter();
|
||||
for (byte b : crypt.digest()) {
|
||||
formatter.format("%02x", b);
|
||||
}
|
||||
String result = formatter.toString();
|
||||
formatter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findAccessToken() {
|
||||
String accessToken;
|
||||
accessToken = redisCache.getCacheObject(TokenConstants.ACCESS_TOKEN + appid);
|
||||
if (StrUtil.isNotEmpty(accessToken)) {
|
||||
return accessToken;
|
||||
}
|
||||
Map<String, Object> map = new HashMap<>(3);
|
||||
String grantType = "client_credential";
|
||||
map.put("grant_type", grantType);
|
||||
map.put("appid", appid);
|
||||
map.put("secret", secret);
|
||||
String body = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token", map);
|
||||
accessToken = (String) new JSONObject(body).get("access_token");
|
||||
// accessToken存入redis
|
||||
redisCache.setCacheObject(TokenConstants.ACCESS_TOKEN + appid, accessToken, 7200, TimeUnit.SECONDS);
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findJsapiTicket() {
|
||||
String ticket;
|
||||
ticket = redisCache.getCacheObject(TokenConstants.JsapiTicket + appid);
|
||||
if (StrUtil.isNotEmpty(ticket)) {
|
||||
return ticket;
|
||||
}
|
||||
String accessToken = findAccessToken();
|
||||
Map<String, Object> map = new HashMap<>(2);
|
||||
map.put("access_token", accessToken);
|
||||
String type = "jsapi";
|
||||
map.put("type", type);
|
||||
String body = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket", map);
|
||||
ticket = (String) new JSONObject(body).get("ticket");
|
||||
// accessToken存入redis
|
||||
redisCache.setCacheObject(TokenConstants.JsapiTicket + appid, ticket, 7200, TimeUnit.SECONDS);
|
||||
return ticket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findSignature(WeChatRequest req) {
|
||||
String signature;
|
||||
String jsapi_ticket = findJsapiTicket();
|
||||
String url = req.getUrl();
|
||||
String nonceStr = req.getNoncestr();
|
||||
String timestamp = req.getTimestamp();
|
||||
String[] arr = new String[]{"jsapi_ticket=" + jsapi_ticket, "noncestr=" + nonceStr, "timestamp=" + timestamp, "url=" + url};
|
||||
Arrays.sort(arr);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
sb.append(arr[i]);
|
||||
if (i != arr.length - 1) {
|
||||
sb.append("&");
|
||||
}
|
||||
}
|
||||
try {
|
||||
signature = SHA1(sb.toString());
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("未知异常,请联系管理员");
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信手机号
|
||||
*
|
||||
* @param code 手机号获取凭证
|
||||
* @return 手机号
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getUserPhoneNumber(String code) {
|
||||
String accessToken = this.findAccessToken();
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("code", code);
|
||||
String jsonStr = JSONUtil.toJsonStr(map);
|
||||
String body = HttpUtil.post("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken, jsonStr);
|
||||
return new JSONObject(body);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信二维码
|
||||
*
|
||||
* @param req 获取小程序码请求类
|
||||
* @return 微信二维码二进制
|
||||
*/
|
||||
@Override
|
||||
public byte[] findWxCode(WeChatCodeRequest req) {
|
||||
String accessToken = this.findAccessToken();
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
if (req.getWidth() != null) {
|
||||
map.put("width", req.getWidth());
|
||||
}
|
||||
map.put("path", req.getPath() + "?shanghuId=" + req.getShanghuId());
|
||||
String jsonStr = JSONUtil.toJsonStr(map);
|
||||
String body = HttpUtil.post("https://api.weixin.qq.com/wxa/getwxacode?access_token=" + accessToken, jsonStr);
|
||||
return body.getBytes();
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.ruoyi.common.constant;
|
||||
|
||||
/**
|
||||
* token 常量
|
||||
*
|
||||
* @Author: wu
|
||||
* @DateTime: 2023/3/14 17:18
|
||||
*/
|
||||
public class TokenConstants {
|
||||
|
||||
/**
|
||||
* redis token 前缀
|
||||
*/
|
||||
public static String LOGIN_INFO = "loginInfo:";
|
||||
|
||||
/**
|
||||
* redis WeChat token 前缀
|
||||
*/
|
||||
public static String ACCESS_TOKEN = "accessToken:";
|
||||
|
||||
/**
|
||||
* redis WeChat ticket 前缀
|
||||
*/
|
||||
public static String JsapiTicket = "jsapiTicket:";
|
||||
}
|
Loading…
Reference in new issue