目录
前置内容
微信登录
导入小程序代码
微信登录流程
微信登录——需求分析与设计
产品原型:
接口设计
数据库设计
微信登录——代码开发(1)
配置文件设置
微信登录——代码开发(2)
VO设计
UserController中
微信登录——代码开发(3)
UserService中
UserMapper中
微信登录——功能测试
编写拦截器校验小程序端发来的请求携带的token是否合法
导入商品浏览功能代码——需求分析与设计
产品原型
接口设计
导入商品浏览功能代码——代码导入+功能测试
前置内容
微信登录
导入小程序代码
用提供的资料里面的小程序代码用微信开发者工具进行导入,用自己的APPid。
微信登录流程
来微信官方文档的一张图
首先在小程序这边获取用户的授权码,然后发送到后端,再由后端发送appid+app密钥和code调用微信的接口服务(通过HttpClient发送请求)。
然后在数据库产生一个令牌返回给用户。小程序 存储令牌,要发起业务的时候就携带令牌。
后端请求官方接口的参数如下
响应数据格式为
小程序里面已经写好了获取code的功能代码,点击获取后如下。获取到这个code之后就可以用postman进行测试了。
成功通过appid和秘钥以及用户code获取到用户的openid
每个code只能使用一次,多次使用会报错。
返回数据没有unionid是因为小程序没有绑定到微信开放平台。在这里有解决方案。
微信登录——需求分析与设计
产品原型:
接口设计
数据库设计
微信登录——代码开发(1)
配置文件设置
微信登录——代码开发(2)
VO设计
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserLoginVO implements Serializable {
private Long id;
private String openid;
private String token;
}
UserController中
这里的主要逻辑就是接收前端传来code,然后根据这个code调用官方接口获取信息然后返回一个token和一个Openid给小程序端。
此处代码里面用到了userid,但是新用户的话没有id的,所以在新用户登录时会配置一个主键返回。
@RestController
@RequestMapping("/user/user")
@Api(tags="C端用户相关接口")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@Autowired
private JwtProperties jwtProperties;
@PostMapping("/login")
@ApiOperation("微信登录")
public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO){
log.info("微信用户登录:{}",userLoginDTO.getCode());
//微信登录
User user = userService.wxlogin();
//为微信用户生成jwt令牌
HashMap<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);
}
}
微信登录——代码开发(3)
UserService中
@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;
/**
* 微信登录
* @return
*/
@Override
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}")
public User getByOpenid(String openid);
/**
* 查入数据
* @param user
*/
void insert(User user);
}
对应的映射文件里面要开启主键返回
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.UserMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into user (openid, name, phone,sex,id_number,avatar,create_time )
values
(#{openid},#{name}, #{phone},#{sex},#{id_number},#{avatar},#{create_time})
</insert>
</mapper>
微信登录——功能测试
在小程序端成功实现登录并保存用户信息到数据库
编写拦截器校验小程序端发来的请求携带的token是否合法
使用管理端的拦截器复制一份出来放在同一文件夹下
/**
* 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;
}
}
}
然后要在配置类里面定义这个拦截器
导入商品浏览功能代码——需求分析与设计
产品原型
接口设计
导入商品浏览功能代码——代码导入+功能测试
代码按提供的进行导入。
前后端联调测试 正常