微信小程序服务端工具类

小程序服务端会涉及到获取小程序用户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 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 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
     * 

例如:

* 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 *

例如:

* 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或全空白字符
{@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 onLogin(@RequestParam("code") String code, @RequestParam("nickname") String nickname) throws Exception {
        if (logger.isInfoEnabled()) {
            logger.info(code);
        }
        try {
            Map 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 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 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 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 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;
        }
    }

你可能感兴趣的:(微信小程序服务端工具类)