课程内容

  • HttpClient
  • 微信小程序开发
  • 微信登录
  • 导入商品浏览功能代码
  • 实现微信登录功能
  • 实现商品浏览功能

HttpClient

HttpClient介绍

  • 提供高效 最新 功能丰富的支持http协议的客户端编程工具包
  • 支持HTTP协议最新的版本和建议
  • 核心api
    • HttpClient
    • HttpClients
    • CloseableHttpClient
    • HttpGet
    • HttpPost
  • 发送请求步骤
    • 创建HttpClient对象
    • 创建Http请求对象
    • 调用HttpClient的execute方法发送请求
    • 解析结果
    • 关闭资源
  • maven坐标
<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.5.13</version>
</dependency>
  • 在aliyun-sdk-oss坐标中底层已经包含了HttpClient相关依赖
  • 故无需再次添加

微信小程序开发

微信小程序介绍

  • 一种新的开发能力
  • 可以在微信内部便捷地获取和传播
  • 同时具有出色使用体验
  • 接入流程
    • 在微信公众平台注册小程序 完成注册后可以同步进行信息完善和开发
    • 小程序信息完善
    • 开发小程序
    • 提交审核和发布

准备工作

小程序目录结构

  • 包含一个描述整体程序的app
  • 多个描述各自页面的page
  • 一个小程序文件主体部分由三个文件组成
    • app.js 必须存在 主要存档小程序的逻辑代码
    • app.json 必须存在 小程序配置文件主要存在公共配置
    • app.wxss 非必须 存放公共样式表(类似css)
  • 小程序的不同页面存放在pages目录
    • js文件 必须存在 页面逻辑代码
    • wxml文件 必须存在 存放页面结构 类似html
    • json文件 非必须 存放页面相关配置
    • wxss文件 非必须 存放公共样式表(类似css)

微信登录

导入小程序代码

  • 黑马官方资料已经提供小程序代码
  • 导入即可
  • 使用自己的appid
  • 在common–>vendor.js文件中
  • 搜索baseUri 将后端服务改为自己的ip地址和端口号

微信登录流程

步骤分析

  1. 小程序端,调用wx.login()获取code,就是授权码。
  2. 小程序端,调用wx.request()发送请求并携带code,请求开发者服务器(自己编写的后端服务)。
  3. 开发者服务端,通过HttpClient向微信接口服务发送请求,并携带appId+appsecret+code三个参数。
  4. 开发者服务端,接收微信接口服务返回的数据,session_key+opendId等。opendId是微信用户的唯一标识。
  5. 开发者服务端,自定义登录态,生成令牌(token)和openid等数据返回给小程序端,方便后绪请求身份校验。
  6. 小程序端,收到自定义登录态,存储storage。
  7. 小程序端,后绪通过wx.request()发起业务请求时,携带token。
  8. 开发者服务端,收到请求后,通过携带的token,解析当前登录用户的id。
  9. 开发者服务端,身份校验通过后,继续相关的业务逻辑处理,最终返回业务数据。

需求分析与设计

  • 基于微信登录实现小程序的登录功能
  • 如果是新用户需要自动完成注册

表设计

字段名 数据类型 说明 备注
id bigint 主键 自增
openid varchar(45) 微信用户的唯一标识
name varchar(32) 用户姓名
phone varchar(11) 手机号
sex varchar(2) 性别
id_number varchar(18) 身份证号
avatar varchar(500) 微信用户头像路径
create_time datetime 注册时间

代码开发

配置所需配置项

  • application.yml
sky:
  wechat:
    appid: ${sky.wechat.appid}
    secret: ${sky.wechat.secret}
  • application-dev.yml

Controller层

  • 根据接口定义创建UserController类
  • 在controller中新建user.UserController
  • 创建Login方法
@Slf4j  
@RequestMapping("/user/user")  
@RestController  
@Api(tags = "用户端用户相关接口")  
public class UserController {  
  
    @Autowired  
    private  UserService userService;  
  
    @Autowired  
    private JwtProperties jwtProperties;  
  
    @ApiOperation("微信登录")  
    @PostMapping("/login")  
    public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO){  
        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);  
    }  
}

Service层

  • 先创建UserService层接口
  • 无需单独创建user文件包
  • 在接口中声明wxLogin方法
public interface UserService {  
	 //微信登录
     User wxlogin(UserLoginDTO userLoginDTO);  
}
  • 在实现类中实现
@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;  
  
    @Override  
    public User wxlogin(UserLoginDTO userLoginDTO) {  
          
        String openid = getOpenId(userLoginDTO.getCode());  
        //判断openid是否为空 如果为空表示登录失败  
        if ("0".equals(openid)){  
            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;  
    }  
      
    //调用微信接口方法  
    private String getOpenId(String code){  
        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);  
        return jsonObject.getString("openid");  
    }  
}

编写拦截器

  • 新建JwtTokenUserInterceptor
package com.sky.interceptor;

import com.sky.constant.JwtClaimsConstant;
import com.sky.context.BaseContext;
import com.sky.properties.JwtProperties;
import com.sky.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 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");
    }

导入商品浏览功能代码

  • 黑马提供了商品浏览代码 直接导入即可

想温柔的对待这个世界