HttpClient
HttpClient作用:发送HTTP请求,接收响应数据
发送请求步骤:创建HttpClient对象 创建Http请求对象 调用HttpClient的execute方法发送请求
微信小程序开发
这里因为我之前用邮箱注册过一个了,所以我直接用的测试号
注意:
微信登录
导入小程序代码
这里注意解压之后有外层的文件夹,一定要选择里面那个
微信登录流程
小程序调用 wx.login 获取临时 code,传给后端;后端使用 HttpClient 调用微信开放平台接口,传入 appid、appsecret、code,获取用户 openid;依据 openid 完成自动注册,生成 JWT 令牌返回小程序;后续每次业务请求携带 JWT,后端拦截器校验令牌识别用户身份。
需求分析和设计
业务规则:基于微信登录实现小程序的登录功能,如果是新用户需要自动完成注册
接口设计
数据库设计
代码开发
配置微信登录所需配置项
application.yml
sky: jwt: # 设置jwt签名加密时使用的秘钥 admin-secret-key: itcast # 设置jwt过期时间 admin-ttl: 7200000 # 设置前端传递过来的令牌名称 admin-token-name: token user-secret-key: itheima user-ttl: 7200000 user-token-name: authentication wechat: appid: ${sky.wechat.appid} secret: ${sky.wechat.secret}application-dev.yml
sky: wechat: appid: 你的 secret: 你的我用的是测试号,在这里看
https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
小程序端调用 wx.login 拿到一次性临时 code,将 code 通过请求传给我们的 Java 后端,后端读取配置文件里的 appid 和 secret,使用 HttpClient 工具去调用微信官方的 jscode2session 接口,传入 appid、secret、code,从微信返回结果中解析出用户唯一标识 openid,拿着 openid 去数据库查询用户,如果查不到就自动完成新用户注册,之后后端生成项目自己的 JWT 登录令牌,把用户信息和 JWT 封装成 VO 返回给小程序,小程序将 JWT 存在本地存储,后续所有业务请求都在请求头带上这个 JWT,后端拦截器校验 JWT 就能识别是哪个用户,完成业务处理并返回数据。
UserController
@RestController @RequestMapping("/user/user") @Api(tags = "C端用户相关接口") @Slf4j public class UserController { @Autowired private UserService userService; @Autowired private JwtProperties jwtProperties; /** * 微信登录 * @param userLoginDTO * @return */ @PostMapping("/login") @ApiOperation("微信登录") public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO){ log.info("微信用户登录:{}",userLoginDTO.getCode()); //微信登录 User user = userService.wxLogin(userLoginDTO);//后绪步骤实现 //为微信用户生成jwt令牌 Map<String, Object> claims = new HashMap<>(); claims.put(JwtClaimsConstant.USER_ID,user.getId()); String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims); UserLoginVO userLoginVO = UserLoginVO.builder() .id(user.getId()) .openid(user.getOpenid()) .token(token) .build(); return Result.success(userLoginVO); } }UserService
public interface UserService { /** * 微信登录 * @param userLoginDTO * @return */ User wxLogin(UserLoginDTO userLoginDTO); }UserServiceImpl
@Service @Slf4j public class UserServiceImpl implements UserService { //微信服务接口地址 public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session"; @Autowired private WeChatProperties weChatProperties; @Autowired private UserMapper userMapper; /** * 微信登录 * @param userLoginDTO * @return */ public User wxLogin(UserLoginDTO userLoginDTO) { String openid = getOpenid(userLoginDTO.getCode()); //判断openid是否为空,如果为空表示登录失败,抛出业务异常 if(openid == null){ throw new LoginFailedException(MessageConstant.LOGIN_FAILED); } //判断当前用户是否为新用户 User user = userMapper.getByOpenid(openid); //如果是新用户,自动完成注册 if(user == null){ user = User.builder() .openid(openid) .createTime(LocalDateTime.now()) .build(); userMapper.insert(user);//后绪步骤实现 } //返回这个用户对象 return user; } /** * 调用微信接口服务,获取微信用户的openid * @param code * @return */ private String getOpenid(String code){ //调用微信接口服务,获得当前微信用户的openid Map<String, String> map = new HashMap<>(); map.put("appid",weChatProperties.getAppid()); map.put("secret",weChatProperties.getSecret()); map.put("js_code",code); map.put("grant_type","authorization_code"); String json = HttpClientUtil.doGet(WX_LOGIN, map); JSONObject jsonObject = JSON.parseObject(json); String openid = jsonObject.getString("openid"); return openid; } }UserMapper
@Mapper public interface UserMapper { /** * 根据openid查询用户 * @param openid * @return */ @Select("select * from user where openid = #{openid}") User getByOpenid(String openid); /** * 插入数据 * @param user */ void insert(User user); }UserMapper.xml
<insert id="insert" useGeneratedKeys="true" keyProperty="id"> insert into user (openid, name, phone, sex, id_number, avatar, create_time) values (#{openid}, #{name}, #{phone}, #{sex}, #{idNumber}, #{avatar}, #{createTime}) </insert>JwtTokenUserInterceptor
/** * jwt令牌校验的拦截器 */ @Component @Slf4j public class JwtTokenUserInterceptor implements HandlerInterceptor { @Autowired private JwtProperties jwtProperties; /** * 校验jwt * * @param request * @param response * @param handler * @return * @throws Exception */ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //判断当前拦截到的是Controller的方法还是其他资源 if (!(handler instanceof HandlerMethod)) { //当前拦截到的不是动态方法,直接放行 return true; } //1、从请求头中获取令牌 String token = request.getHeader(jwtProperties.getUserTokenName()); //2、校验令牌 try { log.info("jwt校验:{}", token); Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token); Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString()); log.info("当前用户的id:", userId); BaseContext.setCurrentId(userId); //3、通过,放行 return true; } catch (Exception ex) { //4、不通过,响应401状态码 response.setStatus(401); return false; } } }WebMvcConfiguration
@Autowired private JwtTokenUserInterceptor jwtTokenUserInterceptor; /** * 注册自定义拦截器 * @param registry */ protected void addInterceptors(InterceptorRegistry registry) { log.info("开始注册自定义拦截器..."); //......... registry.addInterceptor(jwtTokenUserInterceptor) .addPathPatterns("/user/**") .excludePathPatterns("/user/user/login") .excludePathPatterns("/user/shop/status"); }运行之后发现报错
测试号要关注测试公众号
后面还是一直显示登录失败,我直接把openid写死了。。。
String openid = "o0Abcdef1234567890testmockopenid";//随便一串字符串
导入商品浏览功能代码
代码已上传