Browse Source

Merge remote-tracking branch 'upstream/release' into release

zhushouping 1 month ago
parent
commit
1660fe7c42

+ 1 - 1
build.gradle

@@ -118,7 +118,7 @@ dependencies {
 }
 
 group = 'com.ematou'
-version = '0.0.1-SNAPSHOT'
+version = '1.0.0'
 description = 'wxbase'
 sourceCompatibility = '1.8'
 

+ 1 - 1
pom.xml

@@ -10,7 +10,7 @@
     </parent>
     <groupId>com.ematou</groupId>
     <artifactId>wxbase</artifactId>
-    <version>0.0.1-SNAPSHOT</version>
+    <version>1.0.0</version>
     <name>wxbase</name>
     <description>Demo project for Spring Boot</description>
     <properties>

+ 9 - 0
src/main/java/com/ematou/wxbase/controller/TokenRecordController.java

@@ -58,4 +58,13 @@ public class TokenRecordController {
 
     }
 
+    @GetMapping("/wxbase/tokenByAppId/{appId}")
+    public R<?> getTokenByAppId(@PathVariable String appId) {
+        try {
+            return new R<>().success(tokenRecordService.getLatestTokenByAppId(appId));
+        } catch (Exception e) {
+            return new R<>().error("获取AccessToken失败!errorMessage: " + e.getMessage());
+        }
+    }
+
 }

+ 49 - 0
src/main/java/com/ematou/wxbase/entity/MerchApp.java

@@ -16,5 +16,54 @@ public class MerchApp {
     private String merchSn;// 商户编号
     private String appCode;// 应用编码
     private String appName;// 应用名称
+    private String appId;// 微信appId
+    private String appSecret;// 应用名称
 
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getMerchSn() {
+        return merchSn;
+    }
+
+    public void setMerchSn(String merchSn) {
+        this.merchSn = merchSn;
+    }
+
+    public String getAppCode() {
+        return appCode;
+    }
+
+    public void setAppCode(String appCode) {
+        this.appCode = appCode;
+    }
+
+    public String getAppName() {
+        return appName;
+    }
+
+    public void setAppName(String appName) {
+        this.appName = appName;
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getAppSecret() {
+        return appSecret;
+    }
+
+    public void setAppSecret(String appSecret) {
+        this.appSecret = appSecret;
+    }
 }

+ 18 - 3
src/main/java/com/ematou/wxbase/scheduler/RefreshAccessTokenScheduler.java

@@ -1,8 +1,11 @@
 package com.ematou.wxbase.scheduler;
 
 import com.ematou.wxbase.common.utils.DateUtils;
+import com.ematou.wxbase.entity.MerchApp;
 import com.ematou.wxbase.entity.TokenRecord;
+import com.ematou.wxbase.service.EidService;
 import com.ematou.wxbase.service.TokenRecordService;
+import com.ematou.wxbase.utils.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -14,6 +17,8 @@ import org.springframework.util.CollectionUtils;
 import java.text.ParseException;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 /**
@@ -30,6 +35,8 @@ public class RefreshAccessTokenScheduler {
     @Autowired
     TokenRecordService tokenRecordService;
 
+    @Autowired
+    private EidService eidService;
     /**
      * 定时器刷新token
      */
@@ -37,10 +44,18 @@ public class RefreshAccessTokenScheduler {
     public void refreshAccessToken() {
         try {
             logger.info("定时器开始刷新Token...");
-            tokenRecordService.generateToken("emato");
-            tokenRecordService.generateToken("qhemato");
+            List<MerchApp> merchApps = eidService.selectList(null, null, null);
+            if (Objects.isNull(merchApps) || merchApps.isEmpty()){
+                logger.info("定时器开始刷新Token异常,查询不到需要扫描的appid...");
+                return;
+            }
+            // 进行分组避免出现两个相同appId一起刷新
+            Map<String, List<MerchApp>> merchAppMap = merchApps.stream().filter(merchApp -> StringUtils.isNotEmpty(merchApp.getAppId())).collect(Collectors.groupingBy(MerchApp::getAppId));
+            merchAppMap.forEach((appId,appIds) ->{
+                tokenRecordService.generateTokenByAppId(appId);
+            });
         } catch (Exception e) {
-            logger.error("定时刷新Token失败!errorMessage: " + e.getMessage());
+            logger.error("定时刷新Token失败!errorMessage: " + e);
         }
     }
 

+ 4 - 0
src/main/java/com/ematou/wxbase/service/EidService.java

@@ -1,9 +1,12 @@
 package com.ematou.wxbase.service;
 
 import com.ematou.wxbase.common.web.R;
+import com.ematou.wxbase.entity.MerchApp;
 import com.ematou.wxbase.entity.dto.EidTokenRequestDTO;
 import com.ematou.wxbase.entity.vo.EidTokenResponseVO;
 
+import java.util.List;
+
 /**
  * E证通业务接口
  *
@@ -24,4 +27,5 @@ public interface EidService {
      */
     R getEidResult();
 
+    List<MerchApp> selectList(String merchSn, String appCode, String appId);
 }

+ 69 - 0
src/main/java/com/ematou/wxbase/service/TokenRecordService.java

@@ -2,6 +2,7 @@ package com.ematou.wxbase.service;
 
 import com.ematou.wxbase.common.utils.DateUtils;
 import com.ematou.wxbase.config.WxGeneralConfig;
+import com.ematou.wxbase.entity.MerchApp;
 import com.ematou.wxbase.entity.OperationRecord;
 import com.ematou.wxbase.entity.TokenRecord;
 import com.ematou.wxbase.mapper.TokenRecordMapper;
@@ -44,6 +45,9 @@ public class TokenRecordService {
     @Autowired
     WxGeneralConfig wxGeneralConfig;
 
+    @Autowired
+    private EidService eidService;
+
     private static Map<String,WxGeneralConfig> configMap = new ConcurrentHashMap<>();
     @PostConstruct
     private static void init (){
@@ -149,6 +153,27 @@ public class TokenRecordService {
         return tokenRecord;
     }
 
+    /**
+     * 获取数据库中最新且未过期的AccessToken
+     *
+     * @return token
+     */
+    public TokenRecord getLatestTokenByAppId(String appId) throws ParseException {
+        TokenRecord tokenRecord = tokenRecordMapper.queryLatestAndValidRecord(appId);
+        if (null == tokenRecord) {
+            // 需要生成Token
+            return generateTokenByAppId(appId);
+        }
+        String expiresTime = tokenRecord.getExpiresTime();
+        Date tokenExpiresTime = DateUtils.parseString(expiresTime);
+        Date now = new Date();
+        if (now.getTime() > tokenExpiresTime.getTime()) {
+            // 需要生成Token
+            return generateTokenByAppId(appId);
+        }
+        return tokenRecord;
+    }
+
 
     /**
      * 主动请求微信生成accessToken
@@ -233,6 +258,50 @@ public class TokenRecordService {
     }
 
     /**
+     * 主动请求微信生成accessToken
+     *
+     * @return token记录
+     */
+    public TokenRecord generateTokenByAppId(String appId) throws RuntimeException {
+        List<MerchApp> merchApps = eidService.selectList(null, null, appId);
+        if (Objects.isNull(merchApps) || merchApps.isEmpty()){
+            throw new RuntimeException("appId信息不存在!");
+        }
+        // 如果出现不同商户 相同appid使用其中一个就可以了,密钥是一样的
+        MerchApp merchApp = merchApps.get(0);
+        String url = String.format(wxGeneralConfig.getUrl(), wxGeneralConfig.getGrantType(), merchApp.getAppId(), merchApp.getAppSecret());
+        Map response = null;
+        try {
+            response = restTemplate.getForEntity(url, Map.class).getBody();
+        } catch (Exception e) {
+            logger.error("请求微信平台失败!errorMessage:" + e.getMessage());
+            throw new RuntimeException("请求微信平台失败!");
+        }
+        if (null == response) {
+            logger.error("请求微信平台失败!errorMessage:response is null");
+            throw new RuntimeException("请求微信平台失败!");
+        }
+
+        OperationRecord operationRecord = wrapOperationRecord("目前暂无");
+        TokenRecord tokenRecord = wrapTokenRecord(operationRecord, response,merchApp.getAppId());
+
+        if (null == tokenRecord) {
+            Object errcode = response.get("errcode");
+            Object errmsg = response.get("errmsg");
+            logger.error("请求微信平台生成AccessToken失败!errorCode:" + errcode + ",errorMessage:" + errmsg);
+            throw new RuntimeException("请求微信平台生成AccessToken失败!");
+        }
+
+        // 保存操作记录
+        operationRecordService.insertRecord(operationRecord);
+        int latestId = operationRecordService.queryLatestId();
+        // 保存TokenRecord
+        tokenRecord.setOpId(latestId);
+        insertRecord(tokenRecord);
+        return tokenRecord;
+    }
+
+    /**
      * 批量更新Token的状态
      * @param resultList id数组
      */

+ 16 - 0
src/main/java/com/ematou/wxbase/service/impl/EidServiceImpl.java

@@ -153,6 +153,22 @@ public class EidServiceImpl implements EidService {
     }
 
     /**
+     * 校验商户应用
+     *
+     * @param merchSn
+     * @param appCode
+     */
+    @Override
+    public List<MerchApp> selectList(String merchSn, String appCode, String appId) {
+        MerchApp query = new MerchApp();
+        query.setMerchSn(merchSn);
+        query.setAppCode(appCode);
+        query.setAppId(appId);
+        List<MerchApp> merchApps = merchAppMapper.selectByCondition(query);
+        return merchApps;
+    }
+
+    /**
      * 校验商户
      *
      * @param merchSn

+ 220 - 0
src/main/java/com/ematou/wxbase/utils/StringUtils.java

@@ -0,0 +1,220 @@
+/*
+ * 创建时间:2017-09-03 21:37
+ * 项目名称:kmall_pt
+ * 类名称:StringUtils.java
+ * 包名称:com.kmall.common.utils
+ */
+package com.ematou.wxbase.utils;
+
+import java.text.SimpleDateFormat;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 名称:StringUtils <br>
+ * 描述:String工具类<br>
+ *
+ * @author Scott
+ * @version 1.0
+ * @since 1.0.0
+ */
+public class StringUtils {
+    public static final String EMPTY = "";
+    private static Pattern linePattern = Pattern.compile("_(\\w)");
+
+    /**
+     * 判断字符串是否不为空,不为空则返回true
+     *
+     * @param str 源数据
+     * @return Boolean
+     */
+    public static boolean isNotEmpty(String str) {
+        if (str != null && !"".equals(str.trim()) && !"null".equalsIgnoreCase(str)) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * 判断对象或对象数组中每一个对象是否为空: 对象为null,字符序列长度为0,集合类、Map为empty
+     *
+     * @param obj
+     * @return
+     */
+    public static boolean isNullOrEmpty(Object obj) {
+        if (obj == null) {
+            return true;
+        }
+
+        if (obj instanceof CharSequence) {
+            return ((CharSequence) obj).length() == 0;
+        }
+
+        if (obj instanceof Collection) {
+            return ((Collection) obj).isEmpty();
+        }
+
+        if (obj instanceof Map) {
+            return ((Map) obj).isEmpty();
+        }
+
+        if (obj instanceof Object[]) {
+            Object[] object = (Object[]) obj;
+            if (object.length == 0) {
+                return true;
+            }
+            boolean empty = true;
+            for (int i = 0; i < object.length; i++) {
+                if (!isNullOrEmpty(object[i])) {
+                    empty = false;
+                    break;
+                }
+            }
+            return empty;
+        }
+        return false;
+    }
+
+    /**
+     * 下划线转驼峰
+     */
+    public static String lineToHump(String str) {
+        str = str.toLowerCase();
+        Matcher matcher = linePattern.matcher(str);
+        StringBuffer sb = new StringBuffer();
+        while (matcher.find()) {
+            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
+        }
+        matcher.appendTail(sb);
+        return sb.toString();
+    }
+
+    /**
+     * 校验数值只能是数字且可以带两位小数
+     * @param value
+     * @return
+     */
+    public static boolean checkNumberByTwoDecimal(String value){
+        // 要验证的字符串
+        String str = String.valueOf(value);
+        // 带小数
+        String regEx = "\\d+(\\.\\d{1,2})?";
+        // 编译正则表达式
+        Pattern pattern = Pattern.compile(regEx);
+        Matcher matcher = pattern.matcher(str);
+        // 字符串是否与正则表达式相匹配
+        boolean rs = matcher.matches();
+        return rs;
+    }
+
+    /*
+     * 判断是否为整数
+     * @param str 传入的字符串
+     * @return 是整数返回true,否则返回false
+     */
+    public static boolean isInteger(String str) {
+        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
+        return pattern.matcher(str).matches();
+    }
+
+    /**
+     * 校验数值只能是数字且只可以带一位小数
+     * @param value
+     * @return
+     */
+    public static boolean checkNumberByOneDecimal(String value){
+        // 要验证的字符串
+        String str = String.valueOf(value);
+        // 带小数
+        String regEx = "\\d+(\\.\\d{1,1})?";
+        // 编译正则表达式
+        Pattern pattern = Pattern.compile(regEx);
+        Matcher matcher = pattern.matcher(str);
+        // 字符串是否与正则表达式相匹配
+        boolean rs = matcher.matches();
+        return rs;
+    }
+
+    /**
+     * 校验数值只能是数字
+     * @param value
+     * @return
+     */
+    public static boolean checkNumberByInteger(String value){
+        // 要验证的字符串
+        String str = String.valueOf(value);
+        // 带小数
+        String regEx = "[+]{0,1}(\\d+)";
+        // 编译正则表达式
+        Pattern pattern = Pattern.compile(regEx);
+        Matcher matcher = pattern.matcher(str);
+        // 字符串是否与正则表达式相匹配
+        boolean rs = matcher.matches();
+        return rs;
+    }
+
+    /**
+     * 获取字符串的长度,如果有中文,则每个中文字符计为2位
+     *
+     * @param value
+     *         指定的字符串
+     *
+     * @return 字符串的长度
+     */
+    public static int length(String value) {
+        int valueLength = 0;
+        String chinese = "[\u0391-\uFFE5]";
+        /* 获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1 */
+        for (int i = 0; i < value.length(); i++) {
+            /* 获取一个字符 */
+            String temp = value.substring(i, i + 1);
+            /* 判断是否为中文字符 */
+            if (temp.matches(chinese)) {
+                /* 中文字符长度为2 */
+                valueLength += 2;
+            } else {
+                /* 其他字符长度为1 */
+                valueLength += 1;
+            }
+        }
+        return valueLength;
+    }
+
+    /**
+     * 根据身份证计算年龄
+     * @param idCard
+     * @return
+     */
+    public static Integer countAge(String idCard) {
+        if (idCard.length() != 18 && idCard.length() != 15) {
+            throw new IllegalArgumentException("身份证号长度错误");
+        }
+        String year;
+        String monthDay;
+        if (idCard.length() == 18) {
+            year = idCard.substring(6,10);
+            monthDay = idCard.substring(10,14);
+        } else {
+            year = "19" + idCard.substring(6, 8);
+            monthDay = idCard.substring(8, 12);
+        }
+        //获取当前时间字符串如:2022-1128
+        String nowTimeStr = new SimpleDateFormat("yyyy-MMdd").format(new Date());
+        String yearNow = nowTimeStr.substring(0, 4);// 当前年份
+        String monthDayNow = nowTimeStr.substring(5, 9);// 当前月日
+        int age = Integer.parseInt(yearNow) - Integer.parseInt(year);
+        //age减一的情况 :用户月日大于当前月日(开头可以为0的4位数int)
+        if (Integer.parseInt(monthDay) > Integer.parseInt(monthDayNow)) {
+            age = age - 1;
+        }
+        return age;
+    }
+
+
+    public static void main(String[] args) {
+
+    }
+}

+ 9 - 1
src/main/resources/mybatis/MerchAppMapper.xml

@@ -7,7 +7,9 @@
     <sql id="merchAppColumns">
         t.merch_sn,
         t.app_code,
-        t.app_name
+        t.app_name,
+        t.app_id,
+        t.app_secret
     </sql>
 
     <!-- 根据条件查询商户应用信息 -->
@@ -26,6 +28,12 @@
             <if test="appName != null and appName !='' ">
                 AND app_name = #{appName}
             </if>
+            <if test="appId != null and appId !='' ">
+                AND app_id = #{appId}
+            </if>
+            <if test="appSecret != null and appSecret !='' ">
+                AND app_secret = #{appSecret}
+            </if>
         </where>
     </select>