小程序服务端会涉及到获取小程序用户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;
}
}
网友评论