Springboot简便的配置微信小程序
Springboot简便的配置微信小程序
ShareNotes
最近在完成一个微信小程序项目,即将上线
欢迎star
Github–ShareNotes
issue
写小程序接口遇到的具体情况
- 通过openId登录。也就是所谓的微信点击直接登录。不需要输入账户密码
- 使用微信自带的api过滤不合法的字符或者图片
- 商户,支付接口
- 更多issue后期遇到情况会添加
微信直接登录
在最早的时候我帮过朋友写过一个花店卖花的程序。
最开始的时候大多数都是通过
微信官方文档API
找到api。然后RestTemplate来访问url。
RestTemplate是Spring提供的用于访问Rest服务的客户端。
@Autowird
private RestTemplate restTemplate;WxConfig wxConfig= restTemplate.getForObject("https://api.weixin.qq.com/xxxxx/" , WxConfig.class);
十分的烦琐
引入别人写好的微信封装工具类
Github-Binary Wang
开始操作
引入依赖
<dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-miniapp</artifactId><version>3.3.0</version>
</dependency>
<!--如果不需要支付功能-->
<dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-pay</artifactId><version>3.3.0</version>
</dependency>
jwt的依赖
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.1</version>
</dependency>
创建用户表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(63) NOT NULL COMMENT '用户名称',`password` varchar(63) NOT NULL DEFAULT '' COMMENT '用户密码',`gender` tinyint(3) NOT NULL DEFAULT '0' COMMENT '性别:0 未知, 1男, 1 女',`birthday` date DEFAULT NULL COMMENT '生日',`last_login_time` datetime DEFAULT NULL COMMENT '最近一次登录时间',`last_login_ip` varchar(63) NOT NULL DEFAULT '' COMMENT '最近一次登录IP地址',`nickname` varchar(63) NOT NULL DEFAULT '' COMMENT '用户昵称或网络名称',`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '用户手机号码',`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '用户头像图片',`weixin_openid` varchar(63) NOT NULL DEFAULT '' COMMENT '微信登录openid',`session_key` varchar(100) NOT NULL DEFAULT '' COMMENT '微信登录会话KEY',`status` tinyint(3) NOT NULL DEFAULT '0' COMMENT '0 可用, 1 禁用, 2 注销',`add_time` datetime DEFAULT NULL COMMENT '创建时间',`update_time` datetime DEFAULT NULL COMMENT '更新时间',`deleted` tinyint(1) DEFAULT '0' COMMENT '逻辑删除',PRIMARY KEY (`id`),UNIQUE KEY `user_name` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
本质是 weixin_openid,session_key。
因为登录不需要账户密码。是直接登录。所以如果第一次登录创建用户的时候username和password可以设置为 weixin_openid,或者任意值。
配置wxConfig。
如果weixin-java-miniapp依赖已经导入完成就可以开始配置你的appid和appsecret,其在到微信开发者平台里头
在之前先配置好properties(我这里是yml格式)
wx:app-id: xxxxxapp-secret: xxxxxmch-id: xxxxxxxxmch-key: xxxxxxnotify-url: http://www.example.com/wx/order/pay-notify# 商户证书文件路径# 请参考“商户证书”一节 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3key-path: xxxxx
获取properties的值
@Configuration
@ConfigurationProperties(prefix = "wx")
public class WxProperties {private String appId;private String appSecret;private String mchId;private String mchKey;private String notifyUrl;private String keyPath;public String getNotifyUrl() {return notifyUrl;}public void setNotifyUrl(String notifyUrl) {this.notifyUrl = notifyUrl;}public String getMchKey() {return mchKey;}public void setMchKey(String mchKey) {this.mchKey = mchKey;}public String getAppId() {return this.appId;}public void setAppId(String appId) {}public String getAppSecret() {return appSecret;}}}this.keyPath = keyPath;public void setKeyPath(String keyPath) {}return keyPath;public String getKeyPath() {}this.mchId = mchId;public void setMchId(String mchId) {}return mchId;public String getMchId() {}this.appSecret = appSecret;public void setAppSecret(String appSecret) {
配置wxConfig
@Configuration
public class WxConfig {@Autowiredprivate WxProperties properties;@Beanpublic WxMaConfig wxMaConfig() {WxMaInMemoryConfig config = new WxMaInMemoryConfig();config.setAppid(properties.getAppId());config.setSecret(properties.getAppSecret());return config;}@Beanpublic WxMaService wxMaService(WxMaConfig maConfig) {WxMaService service = new WxMaServiceImpl();service.setWxMaConfig(maConfig);return service;}@Beanpublic WxPayConfig wxPayConfig() {WxPayConfig payConfig = new WxPayConfig();payConfig.setAppId(properties.getAppId());payConfig.setMchId(properties.getMchId());payConfig.setMchKey(properties.getMchKey());payConfig.setNotifyUrl(properties.getNotifyUrl());payConfig.setKeyPath(properties.getKeyPath());payConfig.setTradeType("JSAPI");payConfig.setSignType("MD5");return payConfig;}@Beanpublic WxPayService wxPayService(WxPayConfig payConfig) {WxPayService wxPayService = new WxPayServiceImpl();wxPayService.setConfig(payConfig);return wxPayService;}
}
所有关于微信小程序配置都在这里了。
然后我们可以使用他封装好的wxMaService了。
生成(写好)对应的 实体类,mapper。
User.java
@Data
public class User {
private Integer id;
private String username;
private String password;
private Byte gender;
private Date birthday;
private Date lastLoginTime;
private String lastLoginIp;
private String nickname;
private String mobile;
private String avatar;
private String weixinOpenid;
private String sessionKey;
private Byte status;
private Date addTime;
private Date updateTime;
private Boolean deleted;
}
WxLoginInfo.java
public class WxLoginInfo {private String code;private UserDto userInfo;public String getCode() {return code;}public void setCode(String code) {this.code = code;}public UserDto getUserInfo() {return userInfo;}public void setUserInfo(UserDto userInfo) {this.userInfo = userInfo;}
}
UserDto.java
@Data
public class UserDto {private String nickName;private String avatarUrl;private String country;private String province;private String city;private String language;private Byte gender;
UserService.java
需要放这两个方法
public interface UserService {
//根据openId查询
public User queryByOid(String openId);
//加入user表
public void add(User user);
实现
UserServiceImpl.java
@Override
public User queryByOid(String openId) {
//这里用了ExampleUserExample example = new UserExample();example.or().andWeixinOpenidEqualTo(openId).andDeletedEqualTo(false);return userMapper.selectOneByExample(example);
}
@Override
public void add(User user) {user.setAddTime(new Date());user.setUpdateTime(new Date());userMapper.insertSelective(user);
}
Controller
WxAuthController.java
@Slf4j
@RestController
@RequestMapping("/wx/auth")
@Validated
public class WxAuthController {@Autowiredprivate UserService userService;//这里是之前添加依赖里面的方法@Autowiredprivate WxMaService wxService;@PostMapping("login_by_weixin")
public Object loginByWeixin(@RequestBody WxLoginInfo wxLoginInfo, HttpServletRequest request) {String code = wxLoginInfo.getCode();UserDto userDto = wxLoginInfo.getUserInfo();if (code == null || userDto == null) {return ResponseUtil.badArgument();}String sessionKey = null;String openId = null;try {WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(code);sessionKey = result.getSessionKey();openId = result.getOpenid();} catch (Exception e) {e.printStackTrace();}if (sessionKey == null || openId == null) {return ResponseUtil.fail();}User user = userService.queryByOid(openId);if (user == null) {user = new User();user.setUsername(openId);user.setPassword(openId);user.setWeixinOpenid(openId);user.setAvatar(userDto.getAvatarUrl());user.setNickname(userDto.getNickName());user.setGender(userDto.getGender());user.setStatus((byte) 0);user.setLastLoginTime(new Date());user.setLastLoginIp(IpUtil.getIpAddr(request));user.setSessionKey(sessionKey);userService.add(user);} else {user.setLastLoginTime(new Date());user.setLastLoginIp(IpUtil.getIpAddr(request));user.setSessionKey(sessionKey);if (userService.updateById(user) == 0) {return ResponseUtil.updatedDataFailed();}}// tokenString token = UserTokenManager.generateToken(user.getId());Map<Object, Object> result = new HashMap<Object, Object>();result.put("token", token);result.put("userInfo", userDto);return ResponseUtil.ok(result);
}
这里的ResponseUtil.ok(result)是我自己的返回值封装类。
举个例子
public static Object ok(Object data) {Map<String, Object> obj = new HashMap<String, Object>();obj.put("errno", 0);obj.put("errmsg", "成功");obj.put("data", data);return obj;
}
JWT配置
接上面的 UserTokenManager
JwtHelper----> UserTokenManager
JwtHelper.java
public class JwtHelper {// 秘钥static final String SECRET = "YOUR-SECRET-TOKEN";// 签名是有谁生成static final String ISSUSER = "SECRET";// 签名的主题static final String SUBJECT = "this is you token";// 签名的观众static final String AUDIENCE = "MINIAPP";public String createToken(Integer userId){try {Algorithm algorithm = Algorithm.HMAC256(SECRET);Map<String, Object> map = new HashMap<String, Object>();Date nowDate = new Date();// 过期时间:7天2小时Date expireDate = getAfterDate(nowDate,0,0,7,2,0,0);map.put("alg", "HS256");map.put("typ", "JWT");String token = JWT.create()// 设置头部信息 Header.withHeader(map)// 设置 载荷 Payload.withClaim("userId", userId).withIssuer(ISSUSER).withSubject(SUBJECT).withAudience(AUDIENCE)// 生成签名的时间 .withIssuedAt(nowDate)// 签名过期的时间 .withExpiresAt(expireDate)// 签名 Signature.sign(algorithm);return token;} catch (JWTCreationException exception){exception.printStackTrace();}return null;}public Integer verifyTokenAndGetUserId(String token) {try {Algorithm algorithm = Algorithm.HMAC256(SECRET);JWTVerifier verifier = JWT.require(algorithm).withIssuer(ISSUSER).build();DecodedJWT jwt = verifier.verify(token);Map<String, Claim> claims = jwt.getClaims();Claim claim = claims.get("userId");return claim.asInt();} catch (JWTVerificationException exception){
// exception.printStackTrace();} return 0;}public Date getAfterDate(Date date, int year, int month, int day, int hour, int minute, int second){if(date == null){date = new Date();} Calendar cal = new GregorianCalendar(); cal.setTime(date);if(year != 0){cal.add(Calendar.YEAR, year);}if(month != 0){cal.add(Calendar.MONTH, month);}if(day != 0){cal.add(Calendar.DATE, day);}if(hour != 0){cal.add(Calendar.HOUR_OF_DAY, hour);}if(minute != 0){cal.add(Calendar.MINUTE, minute);}if(second != 0){cal.add(Calendar.SECOND, second);}return cal.getTime();}
}
UserTokenManager.java
public static String generateToken(Integer id) {JwtHelper jwtHelper = new JwtHelper();return jwtHelper.createToken(id);
}
public static Integer getUserId(String token) {JwtHelper jwtHelper = new JwtHelper();Integer userId = jwtHelper.verifyTokenAndGetUserId(token);if(userId == null || userId == 0){return null;}return userId;
}
小程序前端
user.js
function loginByWeixin(userInfo) {return new Promise(function (resolve, reject) {return login().then((res) => {//这里的api.AuthLoginByWeixin 为 localhost:8080/wx/auth/login_by_weixinutil.request(api.AuthLoginByWeixin, {code: res.code,userInfo: userInfo}, 'POST').then(res => {if (res.errno === 0) {//存储用户信息wx.setStorageSync('userInfo', res.data.userInfo);wx.setStorageSync('token', res.data.token);resolve(res);} else {reject(res);}}).catch((err) => {reject(err);});}).catch((err) => {reject(err);})});
}
utils.js
function request(url, data = {}, method = "GET") {return new Promise(function (resolve, reject) {wx.request({url: url,data: data,method: method,header: {'Content-Type': 'application/json',
//刚刚你设置的token'YOUR-SECRET-TOKEN': wx.getStorageSync('token')},success: function (res) {if (res.statusCode == 200) {if (res.data.errno == 501) {// 清除登录相关内容try {wx.removeStorageSync('userInfo');wx.removeStorageSync('token');} catch (e) {// Do something when catch error}// 切换到登录页面wx.navigateTo({url: '/pages/ucenter/index/index'});} else {resolve(res.data);}} else {reject(res.errMsg);}},fail: function (err) {reject(err)}})});
}
小程序页面js的使用
user.loginByWeixin(e.detail.userInfo).then(res => {app.globalData.hasLogin = true;this.onShow();
}).catch((err) => {app.globalData.hasLogin = false;util.showErrorToast('微信登录失败');
});
关于登录就到这里了。可以打开我的GitHub源码其分别对应
Github–ShareNotes
实体类和mapper还有sql
share-Notes-db----->sql文件夹
share-Notes-db----->src–>main–>java–>cn.sharenotes.db---->domain/mapper/modelwxconfig配置
share-Notes-core----->src–>main–>java–>cn.sharenotes.core---->config
share-Notes-core----->src–>main–>java–>cn.sharenotes.core---->utils
share-Notes-core----->src–>main–>resources---->wxconfig.properties(我这里不是yml)controller使用
share-Notes-wx-api----->src–>main–>java–>cn.sharenotes.wxapi---->web
share-Notes-wx-api----->src–>main–>java–>cn.sharenotes.wxapi---->service
- 微信小程序
shareNotes---->config—>api.js 地址配置
shareNotes---->utils—>user.js /utils工具类
shareNotes---->page---->uncenter---->index—>index.js 登录js
用binarywang的工具类使用过滤
我们回到wxconfig中
重新添加上wxmaSecCheckService
@Slf4j
@Configuration
@PropertySource(value = "classpath:wxconf.properties")
public class WxConfig {@Value("${APP_ID}")private String appId;@Value("${APP_SERCET}")private String appSecret;@Beanpublic WxMaConfig wxMaConfig() {WxMaInMemoryConfig config = new WxMaInMemoryConfig();config.setAppid(appId);config.setSecret(appSecret);log.info("id"+appId);log.info("key"+appSecret);return config;}@Beanpublic WxMaService wxMaService(WxMaConfig maConfig) {WxMaService service = new WxMaServiceImpl();service.setWxMaConfig(maConfig);return service;}@Beanpublic WxMaSecCheckService wxMaSecCheckService(){WxMaSecCheckService wxMaSecCheckService = new WxMaSecCheckServiceImpl(wxMaService(wxMaConfig()));return wxMaSecCheckService;}@Beanpublic WxPayConfig wxPayConfig() {WxPayConfig payConfig = new WxPayConfig();payConfig.setAppId(appId);payConfig.setTradeType("JSAPI");payConfig.setSignType("MD5");return payConfig;}@Beanpublic WxPayService wxPayService(WxPayConfig payConfig) {WxPayService wxPayService = new WxPayServiceImpl();wxPayService.setConfig(payConfig);return wxPayService;}
}
使用
文字过滤
@Autowiredprivate WxMaSecCheckService wxMaSecCheckService;if(!wxMaSecCheckService.checkMessage(JacksonUtil.parseString(body, "name"))){ResponseUtil.fail(500,"违法违规标题");}
图片
wxMaSecCheckService.checkImage(f)
他的方法都是返回布尔值。
分析原理
https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/sec-check/security.imgSecCheck.html
这里的本质是使用微信开发文档中的api
POST https://api.weixin.qq.com/wxa/img_sec_check?access_token=ACCESS_TOKEN
通过post请求这段api返回是否是内容安全。
官方文档很详细了。返回errcode和errMsg
通过为0失败为87014
Post的body中放图片。
不过我们看一下整句api,后面有一个accessToken。
这个accesstoken怎么获取呢。
回到官方文档
获取小程序全局唯一后台接口调用凭据(access_token)。调调用绝大多数后台接口时都需使用 access_token,开发者需要进行妥善保存。
api为
GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
这里需要我们的appid和appsecret。
请求后可以过去accesstoken。但是请求的token只会支持2个小时,后他将重新生成。2个小时后得再次请求。
tips
微信官方api中关于服务端的有趣api很多,可以查阅。虽然有请求次数限制。但是已经足够了
Springboot简便的配置微信小程序相关推荐
- 基于spring-boot的社区社交微信小程序,适合做脚手架、二次开发
代码地址如下: http://www.demodashi.com/demo/13867.html 1 概述 笔者做的一个后端基于spring-boot的社区社交微信小程序,可以作为开发的脚手架,开发速 ...
- java+SpringBoot+HTML+Mysq基于微信小程序的掌上博物馆游览
详细功能设计:请点击下面链接查看 java+SpringBoot+HTML+Mysq基于微信小程序的掌上博物馆游览_哔哩哔哩_bilibili 源码+论文获取: 源码+论文获取请私信获取 摘 要 本 ...
- 基于springboot高校闲置物品交易系统微信小程序源码和论文
基于springboot二手物品交易系统微信小程序 互联网的兴起从本质上改变了整个社会的商品交易方式,国内各大企业从上个世纪 90 年代互联网兴起之时,就产生了通过网络进行销售经营商品的想法.但是由于 ...
- (附源码)springboot人体健康检测微信小程序 毕业设计 012142
Springboot人体健康检测微信小程序的设计与实现 摘 要 本文设计了一种基于微信小程序的人体健康检测小程序,主要为人们提供了方便的各项健康检测服务,包括健康数据编辑.健康科普.健康讨论.注册登录 ...
- 基于java springboot的小说阅读微信小程序含后台管理系统源码
系统运行环境 开发工具 eclipse(idea),mysql5.7(大于5.5),navicat,小程序开发工具 硬件要求 windows操作系统 cpu:2.4GHz 内存:4G 硬盘:100G ...
- 配置微信小程序添加企业微信为好友的组件
在企业微信上配置客服人员 配置微信小程序后台 配置代码 使用处: 效果
- 在阿里云或腾讯云配置微信小程序
默认域名解析.微信小程序上传并通过的情况下,只在阿里云或腾讯云部署配置微信小程序 1. 安装宝塔工具,并且安装mysql 8.0 和 nginx 2. 在宝塔工具里,点击网站,新建一个网站 2.1 ...
- Java后台微信点餐小程序开发最新版笔记,Springboot+Mysql+Freemarker+Bootstrap+微信小程序实现扫码点餐小程序,包含语音提示,微信消息推送,网页管理后台
由于之前的Java后台微信点餐小程序有些知识点过时了,所以今天重新出一版,把里面过时的知识点更新下 前五章是部署笔记,后面是知识点的详细讲解,大家可以先看部署笔记,部署起来后,再跟着详细知识学习. 第 ...
- 计算机毕业设计springboot+vue基本安卓/微信小程序的驾校考试预约系统 uniapp
驾校行业是一个传统的行业.根据当前发展现状,网络信息时代的全面普及,驾校行业也在发生着变化,单就考试预约这一方面,利用手机预约考试正在逐步进入人们的生活.传统的考试预约方式,不仅会耗费大量的人力.时间 ...
最新文章
- 微生物组研发管理真的很难吗?
- JS实现的ajax和同源策略
- 安卓牛客专项练习2020.12.31
- Multi-thread--C++11中std::mutex的使用
- 读书笔记-大型网站技术架构
- RMAN 数据库克隆文件位置转换方法
- lol全队消息怎么发_英雄联盟如何发全部消息,LOL怎样发送消息给全部
- python培训班-python培训班哪家好
- 趣味证书制作生成微信小程序源码
- C# winform 自定义控件配置代码 多显示 换行
- 深拷⻉浅拷⻉的区别?什么是深拷⻉浅拷⻉
- 金额数字转换(小写转大写)
- linux驱动系列学习之DRM(十)
- 数据库高并发的解决方案
- 腾讯后端面试题python_腾讯后端开发,一面面试题分享
- GIS开发:分享NASA火灾地图(FIRMS Fire Map)
- 渗透杂记2013-07-31
- 【人工智能实验室】第三次培训之手写数字识别代码理解
- 计算机原理中的二进制除法,多字节除法--汇编实现原理
- esp8266设置sta失败_ESP8266的AP模式与STA模式简单测试