美文网首页
微信小程序服务端工具类

微信小程序服务端工具类

作者: Hiseico | 来源:发表于2019-04-18 16:02 被阅读0次

    小程序服务端会涉及到获取小程序用户openId等功能,记录一下常用的工具类。以便后续使用。

    小程序工具类

    package wechat.miniprogram.utils;
    
    import wechat.TemplateData;
    import wechat.WeiXinTeamplateMsg;
    import util.*;
    import handler.Global;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.RestTemplate;
    
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    import java.net.URL;
    import java.net.URLConnection;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.ResourceBundle;
    
    /**
     * @author hiseico
     * @date 2019/3/11 14:15
     * @desc
     */
    @Component
    public class MiniProgramUtls {
    
    
        private final static String publicKey = FileUtil.readFileByBytes(ResourceBundle.getBundle(WebConstants.PROPERTIES_FILE_NAME).getString(WebConstants.RSA_PUBLIC_KEY_PATH));
        private final static String privateKey = FileUtil.readFileByBytes(ResourceBundle.getBundle(WebConstants.PROPERTIES_FILE_NAME).getString(WebConstants.RSA_PRIVATE_KEY_PATH));
    
        /**
         * 获取用户的openid
         *
         * @param appid
         * @param code
         * @param secret
         * @return
         * @throws Exception
         */
        public static String getopenidUtil(String appid, String code, String secret) throws Exception {
            BufferedReader in = null;
            //appid和secret是开发者分别是小程序ID和小程序密钥,开发者通过微信公众平台-》设置-》开发设置就可以直接获取,
            String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
            try {
                URL weChatUrl = new URL(url);
                // 打开和URL之间的连接
                URLConnection connection = weChatUrl.openConnection();
                // 设置通用的请求属性
                connection.setConnectTimeout(5000);
                connection.setReadTimeout(5000);
                // 建立实际的连接
                connection.connect();
                // 定义 BufferedReader输入流来读取URL的响应
                in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                StringBuffer sb = new StringBuffer();
                String line;
                while ((line = in.readLine()) != null) {
                    sb.append(line);
                }
                return sb.toString();
            } catch (Exception e) {
                throw e;
            }
            // 使用finally块来关闭输入流
            finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }
    
        /**
         * 微信小程序推送单个用户
         *
         * @param access_token 令牌
         * @param openId       小程序用户openId
         * @param formid       推送formid
         * @param value1    
         * @param value2 
         * @param value3
         * @param value4      
         * @param value5       
         * @param value6       
         * @return
         */
        public static String pushTicketReplyMsgToUser(String access_token, String openId, String formid, String value1, String value2, String value3, String value4, String value5, String value6) {
            String url = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=" + access_token;
    
            //拼接推送的模版
            WeiXinTeamplateMsg weiXinTeamplateMsg = new WeiXinTeamplateMsg();
            weiXinTeamplateMsg.setTouser(openId);//用户openid
            weiXinTeamplateMsg.setTemplate_id(Global.getProperty(WeChatConstants.TICKETREPLY_PUSHTEMPLATE));//模版id
            weiXinTeamplateMsg.setForm_id(formid);//formid
            weiXinTeamplateMsg.setPage("index");//跳转至对应页面
    
    
            Map<String, TemplateData> msgMap = new HashMap<>(5);
    
            TemplateData keyword1 = new TemplateData();
            keyword1.setValue(value1);
            msgMap.put("keyword1", keyword1);
    
            TemplateData keyword2 = new TemplateData();
            keyword2.setValue(value2);
            msgMap.put("keyword2", keyword2);
            weiXinTeamplateMsg.setData(msgMap);
    
            TemplateData keyword3 = new TemplateData();
            keyword3.setValue(value3);
            msgMap.put("keyword3", keyword3);
            weiXinTeamplateMsg.setData(msgMap);
    
            TemplateData keyword4 = new TemplateData();
            keyword4.setValue(value4);
            msgMap.put("keyword4", keyword4);
            weiXinTeamplateMsg.setData(msgMap);
    
            TemplateData keyword5 = new TemplateData();
            keyword5.setValue(value5);
            msgMap.put("keyword5", keyword5);
            weiXinTeamplateMsg.setData(msgMap);
    
            TemplateData keyword6 = new TemplateData();
            keyword6.setValue(value6);
            msgMap.put("keyword6", keyword6);
            weiXinTeamplateMsg.setData(msgMap);
    
            RestTemplate restTemplate = new RestTemplate();
            ResponseEntity<String> responseEntity =
                    restTemplate.postForEntity(url, weiXinTeamplateMsg, String.class);
    //        System.out.println("小程序推送结果={}" + responseEntity.getBody());
            return responseEntity.getBody();
        }
    
    
        /**
         * RSA加密
         *
         * @param beEncryptStr
         * @return
         * @throws Exception
         */
        public static String encryptByRSA(String beEncryptStr) throws Exception {
            try {
    
                // 获取公钥
                PublicKey publicKey = RSAUtil.keyStrToPublicKey(MiniProgramUtls.publicKey);
                //加密
                String publicEncryptedResult = RSAUtil.encryptDataByPublicKey(beEncryptStr.getBytes(), publicKey);
                //将加密内容转换为base64编码
                publicEncryptedResult = BASE64.encryptBASE64(publicEncryptedResult.getBytes());
                //转换为16进制 处理特殊字符
                return MiniProgramUtls.bytes2HexString(publicEncryptedResult.getBytes());
            } catch (Exception e) {
                throw e;
            }
        }
    
        /**
         * RSA解密
         *
         * @param beDecryptStr
         * @return
         * @throws Exception
         */
        public static String decryptByRSA(String beDecryptStr) throws Exception {
            try {
                //将数据从16进制转为10进制
                beDecryptStr = new String(MiniProgramUtls.hexString2Bytes(beDecryptStr));
                //将数据做base64解密
                beDecryptStr = new String(cn.edu.cuit.framework.util.BASE64.decryptBASE64(beDecryptStr));
                // 获取私钥
                PrivateKey privateKey = RSAUtil.keyStrToPrivateKey(MiniProgramUtls.privateKey);
                //解密
                String privateDecryptedResult = RSAUtil.decryptedToStrByPrivate(beDecryptStr, privateKey);
                return privateDecryptedResult;
            } catch (Exception e) {
                throw e;
            }
        }
    
    
    
    //=============以下为字符转16进制方法========
        private static final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    
        /**
         * byteArr转hexString
         * <p>例如:</p>
         * bytes2HexString(new byte[] { 0, (byte) 0xa8 }) returns 00A8
         *
         * @param bytes 字节数组
         * @return 16进制大写字符串
         */
        private static String bytes2HexString(final byte[] bytes) {
            if (bytes == null) return null;
            int len = bytes.length;
            if (len <= 0) return null;
            char[] ret = new char[len << 1];
            for (int i = 0, j = 0; i < len; i++) {
                ret[j++] = hexDigits[bytes[i] >>> 4 & 0x0f];
                ret[j++] = hexDigits[bytes[i] & 0x0f];
            }
            return new String(ret);
        }
    
        /**
         * hexString转byteArr
         * <p>例如:</p>
         * hexString2Bytes("00A8") returns { 0, (byte) 0xA8 }
         *
         * @param hexString 十六进制字符串
         * @return 字节数组
         */
        private static byte[] hexString2Bytes(String hexString) {
            if (isSpace(hexString)) return null;
            int len = hexString.length();
            if (len % 2 != 0) {
                hexString = "0" + hexString;
                len = len + 1;
            }
            char[] hexBytes = hexString.toUpperCase().toCharArray();
            byte[] ret = new byte[len >> 1];
            for (int i = 0; i < len; i += 2) {
                ret[i >> 1] = (byte) (hex2Dec(hexBytes[i]) << 4 | hex2Dec(hexBytes[i + 1]));
            }
            return ret;
        }
    
        /**
         * 判断字符串是否为null或全为空白字符
         *
         * @param s 待校验字符串
         * @return {@code true}: null或全空白字符<br> {@code false}: 不为null且不全空白字符
         */
        private static boolean isSpace(final String s) {
            if (s == null) return true;
            for (int i = 0, len = s.length(); i < len; ++i) {
                if (!Character.isWhitespace(s.charAt(i))) {
                    return false;
                }
            }
            return true;
        }
    
        /**
         * hexChar转int
         *
         * @param hexChar hex单个字节
         * @return 0..15
         */
        private static int hex2Dec(final char hexChar) {
            if (hexChar >= '0' && hexChar <= '9') {
                return hexChar - '0';
            } else if (hexChar >= 'A' && hexChar <= 'F') {
                return hexChar - 'A' + 10;
            } else {
                throw new IllegalArgumentException();
            }
        }
    
    
    }
    
    

    上方使用的SRA加密是对现有业务的id传到小程序以防暴露,对id进行加密处理。

    部分业务Controller

    用户登录方法

    /**
         * 登录获取获取openid和tel
         *
         * @param code
         * @return
         * @throws Exception
         */
        @GetMapping("onLogin")
        public Map<String, Object> onLogin(@RequestParam("code") String code, @RequestParam("nickname") String nickname) throws Exception {
            if (logger.isInfoEnabled()) {
                logger.info(code);
            }
            try {
                Map<String, Object> resultMap = new HashMap<>();
                if (StringUtil.isEmpty(code)) {
                    resultMap.put("resultStatus", false);
                    resultMap.put("openid", null);
                    return resultMap;
                }
                String userid = "";
                String token = "";
                //调用访问微信服务器工具方法,传入三个参数获取带有openid、session_key的json字符串
                String jsonId = null;
                try {
                    jsonId = MiniProgramUtls.getopenidUtil(Global.getProperty(WeChatConstants.APPID), code, Global.getProperty(WeChatConstants.SECRET));
                } catch (Exception e) {
                    resultMap.put("userSession", token);
                    resultMap.put("resultStatus", false);
                    resultMap.put("userId", userid);
                    return resultMap;
                }
                JSONObject jsonObject = JSONObject.fromObject(jsonId);
                //从json字符串获取openid和session_key
                String openid = jsonObject.getString("openid");
    
                MiniProgramUser miniProgramUser = miniProgramService.selectMiniProgramUserByOpenId(openid);
                //用户首次登录,记录用户openId
                resultMap.put("tel", null);
                if (miniProgramUser == null) {
                    MiniProgramUser user = new MiniProgramUser();
                    user.setWnu_open_id(openid);
                    user.setWnu_uuid(GetUtil.getUUID());
                    //设置token
                    token = EncryptUtils.getSHA1EncString(openid + user.getWnu_uuid() + new Date());
                    user.setWnu_token(token);
                    user.setWnu_nick_name(nickname);
                    miniProgramService.insertMiniProgramUser(user);
    
                    userid = user.getWnu_uuid();
                } else {
                    if (!StringUtil.isEmpty(nickname)) {
                        miniProgramUser.setWnu_nick_name(nickname);
                        //设置token
                        token = EncryptUtils.getSHA1EncString(openid + miniProgramUser.getWnu_uuid() + new Date());
                        miniProgramUser.setWnu_token(token);
                        miniProgramService.updateMiniProgramUser(miniProgramUser);
                        userid = miniProgramUser.getWnu_uuid();
                    }
                    resultMap.put("tel", miniProgramUser.getWnu_tel());
                }
                resultMap.put("session_key", token);
                resultMap.put("resultStatus", true);
                resultMap.put("user_id", userid);
                return resultMap;
            } catch (Exception e) {
                logger.error("Exception Stack Info: ", e);
                throw e;
            }
        }
    

    手机号绑定方法

        /**
         * 通过手机号获取验证码
         *
         * @param phone
         * @param session_key
         * @param user_id
         * @return
         * @throws Exception
         */
        @GetMapping("getCheckCode")
        public Map<String, Object> getCheckCode(@RequestParam("phone") String phone, @RequestParam("session_key") String session_key, @RequestParam("user_id") String user_id) throws Exception {
            if (logger.isInfoEnabled()) {
                logger.info(phone);
                logger.info(session_key);
                logger.info(user_id);
            }
            Map<String, Object> resultMap = new HashMap<>();
            try {
                //检查用户登录状态
                /**
                 * 这里检查用户登录的逻辑为:每次用户登录都重新派发一个系统自动生成的Token,只要用户重新登录,token就会更新,防止API被恶意调用。
                 **/
                
                boolean checkResult = miniProgramService.checkUserToken(user_id, session_key);
                if (checkResult == false) {
                    //直接返回 并设置code为500,引导用户重新授权登录
                    resultMap.put("resultStatus", false);
                    resultMap.put("code", MessagePair.STATUS_CODE_JSON_SESSION_TIMEOUT);
                    resultMap.put("msg", MessagePair.getMessage(MessagePair.STATUS_CODE_JSON_SESSION_TIMEOUT));
                    return resultMap;
                }
    
    
                MiniProgramUser miniProgramUser = miniProgramService.selectMiniProgramUserByUuid(user_id);
                if (miniProgramUser == null) {
                    resultMap.put("resultStatus", false);
                    resultMap.put("code", MessagePair.STATUS_CODE_JSON_SESSION_TIMEOUT);
                    resultMap.put("msg", MessagePair.getMessage(MessagePair.STATUS_CODE_JSON_SESSION_TIMEOUT));
                    return resultMap;
                }
    
                //一分钟之内只能获取一次
               /* if (miniProgramUser.getWnu_update_date() != null) {
                    if ((new Date().getTime() / 1000 - miniProgramUser.getWnu_update_date().getTime() / 1000) < 60) {
                        resultMap.put("resultStatus", false);
                        resultMap.put("msg", "请勿频繁获取验证码,请一分钟后重试!");
                        return resultMap;
                    }
                }*/
    
    
                //生成随机数
                String radomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
    
    
                //SMSUtil发送短信
                SMSUtil.sendSMSWechatVerificationCode(phone, radomNumber);
    
                miniProgramUser.setWnu_verification_tel(phone);
                miniProgramUser.setWnu_verification_code(radomNumber);
                miniProgramService.updateMiniProgramUser(miniProgramUser);
    
                resultMap.put("resultStatus", true);
                resultMap.put("code", MessagePair.STATUS_CODE_SUCCESS);
                resultMap.put("msg", "验证码已发送至您的手机!");
                return resultMap;
            } catch (Exception e) {
                logger.error("Exception Stack Info: ", e);
                resultMap.put("resultStatus", false);
                resultMap.put("code", MessagePair.STATUS_CODE_JSON_SYSTEM_EXCEPTION);
                resultMap.put("msg", MessagePair.getMessage(MessagePair.STATUS_CODE_JSON_SYSTEM_EXCEPTION));
                return resultMap;
            }
        }
    
        /**
         * 绑定手机号
         *
         * @param phone
         * @param code
         * @param session_key
         * @param user_id
         * @return
         * @throws Exception
         */
        @GetMapping("bindTel")
        public Map<String, Object> bindTel(@RequestParam("phone") String phone, @RequestParam("checkCode") String code, @RequestParam("session_key") String session_key, @RequestParam("user_id") String user_id) throws Exception {
            if (logger.isInfoEnabled()) {
                logger.info(phone);
                logger.info(code);
                logger.info(session_key);
                logger.info(user_id);
            }
            Map<String, Object> resultMap = new HashMap<>();
            try {
                //检查用户登录状态
                boolean checkResult = miniProgramService.checkUserToken(user_id, session_key);
                if (checkResult == false) {
                    //直接返回 并设置code为500,引导用户重新授权登录
                    resultMap.put("resultStatus", false);
                    resultMap.put("code", MessagePair.STATUS_CODE_JSON_SESSION_TIMEOUT);
                    resultMap.put("msg", MessagePair.getMessage(MessagePair.STATUS_CODE_JSON_SESSION_TIMEOUT));
                    return resultMap;
                }
    
    
                MiniProgramUser miniProgramUser = miniProgramService.selectMiniProgramUserByUuid(user_id);
    
                if (miniProgramUser == null) {
                    resultMap.put("resultStatus", false);
                    resultMap.put("code", MessagePair.STATUS_CODE_JSON_SESSION_TIMEOUT);
                    resultMap.put("msg", MessagePair.getMessage(MessagePair.STATUS_CODE_JSON_SESSION_TIMEOUT));
                    return resultMap;
                }
    
                //校验码有效时间校验 三分钟内有效
                if ((new Date().getTime() / 1000 - miniProgramUser.getWnu_update_date().getTime() / 1000) >= 60 * 3) {
                    resultMap.put("resultStatus", false);
                    resultMap.put("code", MessagePair.STATUS_CODE_WECHAT_MINI_CHECK_CODE_LOSE);
                    resultMap.put("msg", MessagePair.getMessage(MessagePair.STATUS_CODE_WECHAT_MINI_CHECK_CODE_LOSE));
                    return resultMap;
                }
    
                //校验提交的手机号和发送验证码手机号是否一致
                if (!miniProgramUser.getWnu_verification_tel().equals(phone)) {
                    resultMap.put("resultStatus", false);
                    resultMap.put("code", MessagePair.STATUS_CODE_WECHAT_MINI_PHONE_BIND_ERROR);
                    resultMap.put("msg", MessagePair.getMessage(MessagePair.STATUS_CODE_WECHAT_MINI_PHONE_BIND_ERROR));
                    return resultMap;
                }
    
                //校验验证码
                if (!code.equals(miniProgramUser.getWnu_verification_code())) {
                    resultMap.put("resultStatus", false);
                    resultMap.put("code", MessagePair.STATUS_CODE_WECHAT_MINI_CHECK_CODE_ERROR);
                    resultMap.put("msg", MessagePair.getMessage(MessagePair.STATUS_CODE_WECHAT_MINI_CHECK_CODE_ERROR));
                    return resultMap;
                }
    
                miniProgramUser.setWnu_tel(miniProgramUser.getWnu_verification_tel());
                miniProgramService.updateMiniProgramUser(miniProgramUser);
    
                resultMap.put("resultStatus", true);
                resultMap.put("code", MessagePair.STATUS_CODE_SUCCESS);
                resultMap.put("msg", "绑定成功!");
    
                return resultMap;
            } catch (Exception e) {
                logger.error("Exception Stack Info: ", e);
                resultMap.put("resultStatus", false);
                resultMap.put("code", MessagePair.STATUS_CODE_JSON_SYSTEM_EXCEPTION);
                resultMap.put("msg", MessagePair.getMessage(MessagePair.STATUS_CODE_JSON_SYSTEM_EXCEPTION));
                return resultMap;
            }
        }
    

    相关文章

      网友评论

          本文标题:微信小程序服务端工具类

          本文链接:https://www.haomeiwen.com/subject/pvstgqtx.html