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/model

  • wxconfig配置
    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简便的配置微信小程序相关推荐

  1. 基于spring-boot的社区社交微信小程序,适合做脚手架、二次开发

    代码地址如下: http://www.demodashi.com/demo/13867.html 1 概述 笔者做的一个后端基于spring-boot的社区社交微信小程序,可以作为开发的脚手架,开发速 ...

  2. java+SpringBoot+HTML+Mysq基于微信小程序的掌上博物馆游览

    详细功能设计:请点击下面链接查看 java+SpringBoot+HTML+Mysq基于微信小程序的掌上博物馆游览_哔哩哔哩_bilibili 源码+论文获取: 源码+论文获取请私信获取 摘  要 本 ...

  3. 基于springboot高校闲置物品交易系统微信小程序源码和论文

    基于springboot二手物品交易系统微信小程序 互联网的兴起从本质上改变了整个社会的商品交易方式,国内各大企业从上个世纪 90 年代互联网兴起之时,就产生了通过网络进行销售经营商品的想法.但是由于 ...

  4. (附源码)springboot人体健康检测微信小程序 毕业设计 012142

    Springboot人体健康检测微信小程序的设计与实现 摘 要 本文设计了一种基于微信小程序的人体健康检测小程序,主要为人们提供了方便的各项健康检测服务,包括健康数据编辑.健康科普.健康讨论.注册登录 ...

  5. 基于java springboot的小说阅读微信小程序含后台管理系统源码

    系统运行环境 开发工具 eclipse(idea),mysql5.7(大于5.5),navicat,小程序开发工具 硬件要求 windows操作系统 cpu:2.4GHz 内存:4G 硬盘:100G ...

  6. 配置微信小程序添加企业微信为好友的组件

    在企业微信上配置客服人员 配置微信小程序后台 配置代码 使用处: 效果

  7. 在阿里云或腾讯云配置微信小程序

    默认域名解析.微信小程序上传并通过的情况下,只在阿里云或腾讯云部署配置微信小程序 1. 安装宝塔工具,并且安装mysql  8.0 和 nginx 2. 在宝塔工具里,点击网站,新建一个网站 2.1 ...

  8. Java后台微信点餐小程序开发最新版笔记,Springboot+Mysql+Freemarker+Bootstrap+微信小程序实现扫码点餐小程序,包含语音提示,微信消息推送,网页管理后台

    由于之前的Java后台微信点餐小程序有些知识点过时了,所以今天重新出一版,把里面过时的知识点更新下 前五章是部署笔记,后面是知识点的详细讲解,大家可以先看部署笔记,部署起来后,再跟着详细知识学习. 第 ...

  9. 计算机毕业设计springboot+vue基本安卓/微信小程序的驾校考试预约系统 uniapp

    驾校行业是一个传统的行业.根据当前发展现状,网络信息时代的全面普及,驾校行业也在发生着变化,单就考试预约这一方面,利用手机预约考试正在逐步进入人们的生活.传统的考试预约方式,不仅会耗费大量的人力.时间 ...

最新文章

  1. 微生物组研发管理真的很难吗?
  2. JS实现的ajax和同源策略
  3. 安卓牛客专项练习2020.12.31
  4. Multi-thread--C++11中std::mutex的使用
  5. 读书笔记-大型网站技术架构
  6. RMAN 数据库克隆文件位置转换方法
  7. lol全队消息怎么发_英雄联盟如何发全部消息,LOL怎样发送消息给全部
  8. python培训班-python培训班哪家好
  9. 趣味证书制作生成微信小程序源码
  10. C# winform 自定义控件配置代码 多显示 换行
  11. 深拷⻉浅拷⻉的区别?什么是深拷⻉浅拷⻉
  12. 金额数字转换(小写转大写)
  13. linux驱动系列学习之DRM(十)
  14. 数据库高并发的解决方案
  15. 腾讯后端面试题python_腾讯后端开发,一面面试题分享
  16. GIS开发:分享NASA火灾地图(FIRMS Fire Map)
  17. 渗透杂记2013-07-31
  18. 【人工智能实验室】第三次培训之手写数字识别代码理解
  19. 计算机原理中的二进制除法,多字节除法--汇编实现原理
  20. esp8266设置sta失败_ESP8266的AP模式与STA模式简单测试

热门文章

  1. android 模拟器手机如何添加文件到sd卡?
  2. 零基础带你Ubuntu20.04安装Rosbridge并操作测试小乌龟,手把手教学【超级详细】
  3. Java实现PDF打印的解决方案
  4. 抽卡模拟系统(包含图形界面,结果可存储到数据库中)
  5. 学会感谢--谈辞职信的写法
  6. 山东省计算机技能大赛通报,比赛成绩通报
  7. python3+selenium框架设计04-封装测试基类
  8. win10 凭据管理
  9. 怎么在火狐中调试html,如何利用火狐浏览器开发工具调试网页颜色搭配?
  10. 拉格朗日乘子法详解(Lagrange multiplier)