diff --git a/src/main/java/com/jingcheng/template/controller/WechatController.java b/src/main/java/com/jingcheng/template/controller/WechatController.java new file mode 100644 index 0000000..42cb1e9 --- /dev/null +++ b/src/main/java/com/jingcheng/template/controller/WechatController.java @@ -0,0 +1,51 @@ +package com.jingcheng.template.controller; + +import com.alibaba.fastjson.JSONObject; +import com.jingcheng.template.service.WeixinService; +import com.jingcheng.template.util.AjaxRequest; +import com.jingcheng.template.util.AjaxResult; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.bind.annotation.CrossOrigin; +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; +import java.util.Map; + +@RestController +@RequestMapping("/wechat") +@CrossOrigin +public class WechatController { + @Resource + WeixinService weixinService; + + @RequestMapping("get-sign") + public AjaxResult getSign(@RequestBody AjaxRequest ajaxRequest) { + AjaxResult ajaxResult = new AjaxResult(); + JSONObject data = ajaxRequest.getData(); + if (data == null) { + ajaxResult.setRetcode(AjaxResult.FAILED); + ajaxResult.setRetmsg("data missing"); + return ajaxResult; + } else { + String url = data.getString("url"); + if (StringUtils.isEmpty(url)) { + ajaxResult.setRetcode(AjaxResult.FAILED); + ajaxResult.setRetmsg("url missing"); + return ajaxResult; + } else { + Map sign = weixinService.getSign(url); + ajaxResult.setRetmsg("SUCCESS"); + ajaxResult.setRetcode(AjaxResult.SUCCESS); + ajaxResult.setData(sign); + } + } + return ajaxResult; + } + + @RequestMapping("refresh-access-token") + public void refreshToken(){ + weixinService.refreshAccessToken(); + } +} diff --git a/src/main/java/com/jingcheng/template/mapper/WechatConfigMapper.java b/src/main/java/com/jingcheng/template/mapper/WechatConfigMapper.java new file mode 100644 index 0000000..b814449 --- /dev/null +++ b/src/main/java/com/jingcheng/template/mapper/WechatConfigMapper.java @@ -0,0 +1,9 @@ +package com.jingcheng.template.mapper; + +import com.jingcheng.template.model.WechatConfig; +import com.jingcheng.template.util.CommonMapper; +import org.springframework.stereotype.Repository; + +@Repository +public interface WechatConfigMapper extends CommonMapper { +} diff --git a/src/main/java/com/jingcheng/template/model/WechatConfig.java b/src/main/java/com/jingcheng/template/model/WechatConfig.java new file mode 100644 index 0000000..5729266 --- /dev/null +++ b/src/main/java/com/jingcheng/template/model/WechatConfig.java @@ -0,0 +1,12 @@ +package com.jingcheng.template.model; + +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +@TableName("wechat_config") +@Data +@EqualsAndHashCode(callSuper = false) +public class WechatConfig extends BaseEntity{ + private String accessToken; +} diff --git a/src/main/java/com/jingcheng/template/quartz/ScheduledTask.java b/src/main/java/com/jingcheng/template/quartz/ScheduledTask.java index 1189f64..eb81f19 100644 --- a/src/main/java/com/jingcheng/template/quartz/ScheduledTask.java +++ b/src/main/java/com/jingcheng/template/quartz/ScheduledTask.java @@ -3,6 +3,7 @@ package com.jingcheng.template.quartz; import com.jingcheng.template.mapper.AwardRuleMapper; import com.jingcheng.template.service.AwardRecordService; import com.jingcheng.template.service.UsersService; +import com.jingcheng.template.service.WeixinService; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -19,8 +20,12 @@ public class ScheduledTask { UsersService usersService; @Resource AwardRecordService awardRecordService; + @Resource + WeixinService weixinService; private static final String CHANCE_TASK = "0 0 0 * * ?"; + + private static final String REFRESH_TOKEN_TASK = "0 0 0/1 * * ?"; /** * 每天凌晨0:00刷新命 * @throws IOException @@ -30,4 +35,13 @@ public class ScheduledTask { usersService.chancesTask(); awardRecordService.refreshDayAwards(); } + + /** + * 每小时刷新accessToken + * @throws IOException + */ + @Scheduled(cron = REFRESH_TOKEN_TASK) + public void refreshTokenTask() { + weixinService.refreshAccessToken(); + } } diff --git a/src/main/java/com/jingcheng/template/service/WeixinService.java b/src/main/java/com/jingcheng/template/service/WeixinService.java new file mode 100644 index 0000000..4a10207 --- /dev/null +++ b/src/main/java/com/jingcheng/template/service/WeixinService.java @@ -0,0 +1,77 @@ +package com.jingcheng.template.service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; + +import com.jingcheng.template.mapper.WechatConfigMapper; +import com.jingcheng.template.model.WechatConfig; +import com.jingcheng.template.util.HttpRequestUtils; +import com.jingcheng.template.util.LogUtils; +import com.jingcheng.template.util.Sign; + +import com.sun.org.apache.bcel.internal.generic.NEW; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Value; + +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.Map; + +@Service +public class WeixinService{ + + @Value("${weixin.appId}") + private String appId; + @Value("${weixin.appSecret}") + private String appSecret; + @Value("${weixin.getAccessTokenUrl}") + private String getAccessTokenUrl; + @Value("${wechat.getTicketUrl}") + private String getTicketUrl; + @Resource + private WechatConfigMapper wechatConfigMapper; + + Logger logger = LogUtils.getBussinessLogger(); + + /** + * 刷新accesstoken + * @return + */ + public void refreshAccessToken() { + String accessTokenUrl = getAccessTokenUrl + appId + "&secret=" + appSecret; + String result = HttpRequestUtils.sendGet(accessTokenUrl); + String accessToken = JSON.parseObject(result).getString("access_token"); + WechatConfig wechatConfig = wechatConfigMapper.selectByPrimaryKey(1L); + wechatConfig.setAccessToken(accessToken); + wechatConfig.setUpdateDateTime(new Date()); + wechatConfigMapper.updateByPrimaryKeySelective(wechatConfig); + } + + /** + * 通过accessToken刷新ticket + */ + public String getTicket() { + WechatConfig wechatConfig = wechatConfigMapper.selectByPrimaryKey(1L); + String access_token = wechatConfig.getAccessToken(); + String getTicketNewUrl = getTicketUrl + access_token + "&type=jsapi"; + String ticketResult = HttpRequestUtils.sendGet(getTicketNewUrl); + JSONObject ticketJson = JSONObject.parseObject(ticketResult); + String jsapi_ticket = ticketJson.getString("ticket"); + return jsapi_ticket; + } + + public Map getSign(String url) { + String jsapiTicket = getTicket(); + logger.info("jsapiTicket:" + jsapiTicket); + Map sign = Sign.sign(jsapiTicket, url); + sign.put("appId", appId); + logger.info("sign:" + sign); + return sign; + } + + +} diff --git a/src/main/java/com/jingcheng/template/service/impl/UsersServiceImpl.java b/src/main/java/com/jingcheng/template/service/impl/UsersServiceImpl.java index 653179b..e938cf0 100644 --- a/src/main/java/com/jingcheng/template/service/impl/UsersServiceImpl.java +++ b/src/main/java/com/jingcheng/template/service/impl/UsersServiceImpl.java @@ -38,6 +38,8 @@ public class UsersServiceImpl extends BaseServiceImpl implem private String getAccessTokenUrl; @Value("${weixin.getUserInfoUrl}") private String getUserInfoUrl; + @Resource + private WechatConfigMapper wechatConfigMapper; Logger logger = LogUtils.getBussinessLogger(); public Users selectByUserNoOrOpenId(String key) { Users caseUser = new Users(); @@ -130,9 +132,8 @@ public class UsersServiceImpl extends BaseServiceImpl implem // String userInfoUrl = getUserInfoUrl + userAccessToken + "&openid=" + openId + "&lang=zh_CN"; // String userInfoResult = HttpRequestUtils.sendGet(userInfoUrl); //获取基础token - String accessTokenUrl = getAccessTokenUrl + appId + "&secret=" + appSecret; - String result = HttpRequestUtils.sendGet(accessTokenUrl); - String accessToken = JSON.parseObject(result).getString("access_token"); + WechatConfig wechatConfig = wechatConfigMapper.selectByPrimaryKey(1L); + String accessToken = wechatConfig.getAccessToken(); String subscribeUrl = getSubscribeUrl + accessToken + "&openid=" + openId + "&lang=zh_CN"; String subscribeResult = HttpRequestUtils.sendGet(subscribeUrl); Integer subscribe = JSON.parseObject(subscribeResult).getInteger("subscribe"); diff --git a/src/main/java/com/jingcheng/template/util/Sign.java b/src/main/java/com/jingcheng/template/util/Sign.java new file mode 100644 index 0000000..8151827 --- /dev/null +++ b/src/main/java/com/jingcheng/template/util/Sign.java @@ -0,0 +1,86 @@ +package com.jingcheng.template.util; + +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Formatter; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * CK + * 2020/8/12 + * 微信JS-SDK使用权限签名算法 + */ + +public class Sign { + public static void main(String[] args) { + String jsapi_ticket = "sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg"; + + // 注意 URL 一定要动态获取,不能 hardcode + String url = "http://mp.weixin.qq.com?params=value"; + Map ret = sign(jsapi_ticket, url); + for (Map.Entry entry : ret.entrySet()) { + System.out.println(entry.getKey() + ", " + entry.getValue()); + } + } + + public static Map sign(String jsapi_ticket, String url) { + Map ret = new HashMap(); + String nonce_str = create_nonce_str(); + String timestamp = create_timestamp(); + String string1; + String signature = ""; + + //注意这里参数名必须全部小写,且必须有序 + string1 = "jsapi_ticket=" + jsapi_ticket + + "&noncestr=" + nonce_str + + "×tamp=" + timestamp + + "&url=" + url; +// System.out.println(string1); + + try + { + MessageDigest crypt = MessageDigest.getInstance("SHA-1"); + crypt.reset(); + crypt.update(string1.getBytes("UTF-8")); + signature = byteToHex(crypt.digest()); + } + catch (NoSuchAlgorithmException e) + { + e.printStackTrace(); + } + catch (UnsupportedEncodingException e) + { + e.printStackTrace(); + } + + ret.put("url", url); + ret.put("jsapi_ticket", jsapi_ticket); + ret.put("nonceStr", nonce_str); + ret.put("timestamp", timestamp); + ret.put("signature", signature); + + return ret; + } + + private static String byteToHex(final byte[] hash) { + Formatter formatter = new Formatter(); + for (byte b : hash) + { + formatter.format("%02x", b); + } + String result = formatter.toString(); + formatter.close(); + return result; + } + + private static String create_nonce_str() { + return UUID.randomUUID().toString(); + } + + private static String create_timestamp() { + return Long.toString(System.currentTimeMillis() / 1000); + } +} diff --git a/src/main/resources/application-production.yml b/src/main/resources/application-production.yml index 9fe0364..5a4dfcd 100644 --- a/src/main/resources/application-production.yml +++ b/src/main/resources/application-production.yml @@ -62,4 +62,5 @@ weixin: getOpenIdUrl: https://api.weixin.qq.com/sns/oauth2/access_token?appid= getSubscribeUrl: https://api.weixin.qq.com/cgi-bin/user/info?access_token= getAccessTokenUrl: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid= - getUserInfoUrl: https://api.weixin.qq.com/sns/userinfo?access_token= \ No newline at end of file + getUserInfoUrl: https://api.weixin.qq.com/sns/userinfo?access_token= + getTicketUrl: https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token= \ No newline at end of file