黑马苍穹外卖5 HttpClient+微信小程序开发+用户端微信登录+JWT令牌

用户端
在这里插入图片描述

HttpClient

通过客户端编程工具包(可以通过java构造和发送http请求),支持HTTP协议
在这里插入图片描述
HttpClient 是 Apache Jakarta Common 下的子项目,用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

HTTP和浏览器有点像,但却不是浏览器。很多人觉得既然HttpClient是一个HTTP客户端编程工具,很多人把他当做浏览器来理解,但是其实HttpClient不是浏览器,它是一个HTTP通信库,因此它只提供一个通用浏览器应用程序所期望的功能子集,最根本的区别是HttpClient中没有用户界面,浏览器需要一个渲染引擎来显示页面,并解释用户输入,例如鼠标点击显示页面上的某处,有一个布局引擎,计算如何显示HTML页面,包括级联样式表和图像。javascript解释器运行嵌入HTML页面或从HTML页面引用的javascript代码。来自用户界面的事件被传递到javascript解释器进行处理。除此之外,还有用于插件的接口,可以处理Applet,嵌入式媒体对象(如pdf文件,Quicktime电影和Flash动画)或ActiveX控件(可以执行任何操作)。HttpClient只能以编程的方式通过其API用于传输和接受HTTP消息。

HttpClient的主要功能:

  • 实现了所有 HTTP 的方法(GET、POST、PUT、HEAD、DELETE、HEAD、OPTIONS 等)
  • 支持 HTTPS 协议
  • 支持代理服务器(Nginx等)等
  • 支持自动(跳转)转向
  • ……

使用方法

使用HttpClient发送请求、接收响应很简单,一般需要如下几步即可。

  1. 创建HttpClient对象

  2. 创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。

  3. 如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HttpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数。

  4. 调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse。

  5. 调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容。

  6. 释放连接。无论执行方法是否成功,都必须释放连接

	/** 
     * 发送 get请求 
     */   
    public void get() {   
    		//创建httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();    
            // 创建请求对象httpget.     
            HttpGet httpget = new HttpGet("http://localhost:8080/admin/shop/status");   
            System.out.println("executing request " + httpget.getURI());   
            // 发送请求,接受响应结果     
            CloseableHttpResponse response = httpclient.execute(httpget);   
           	//获取服务端返回的状态码
           	int statusCode = response.getStatusLine().getStatusCode(); 
           // 获取响应实体     
            HttpEntity entity = response.getEntity();   
			String body = EntityUtils.toString(entity)
           // 打印响应内容长度     
            System.out.println("Response content length: " + entity.getContentLength());   
            // 打印响应内容     
            System.out.println("Response content: " + body);   

            System.out.println("------------------------------------");   

        //关闭资源
             response.close();   
             httpclient.close();   
    }  
/** 
     * 发送 post请求访问本地应用并根据传递参数不同返回不同结果 
     */   
    public void post() throws Exception {   
        // 创建默认的httpClient实例对象.     
        CloseableHttpClient httpclient = HttpClients.createDefault();   
        // 创建httppost     
        HttpPost httppost = new HttpPost("http://localhost:8080/admin/employee/login");   //post需要以json提交请求参数
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("username","admin");
        jsonObject.put("password","123456");
        
        //构造StringEntity对象
        StringEntity= new StringEntity(jsonObject.toString());//转为JSON格式
        //指定请求编码方式
        entity.setContentEncoding("uts-8");
        //数据格式
        entity.setContentType("application/json");
        httpPost.setEntity(entity);//把请求封装到post里去
		// 发送请求,接受响应结果     
        CloseableHttpResponse response = httpclient.execute(httpget);   
        //获取服务端返回的状态码
        int statusCode = response.getStatusLine().getStatusCode(); 
        // 获取响应实体     
        HttpEntity entity1 = response.getEntity();   
        String body = EntityUtils.toString(entity)
        // 打印响应状态     
        System.out.println(response.getStatusLine());   
        //关闭资源
        response.close();    
        httpclient.close();   
        
    }  

微信小程序开发

小程序
目录结构
在这里插入图片描述

在这里插入图片描述
小程序上传,但只是开发版本,然后在小程序页面提交审核,才能成功发布上线。

微信登录

官方开发指南
在这里插入图片描述
在这里插入图片描述

Path:/user/user/login
第一个user是用户端,第二个user是用户模块
id-是数据库里的唯主键值
openid是在微信里的唯一标识
代码开发
配置项,生成JWT令牌
application.yml

  jwt:
  #管理端生成JWT令牌
    # 设置jwt签名加密时使用的秘钥
    admin-secret-key: itcast
    # 设置jwt过期时间
    admin-ttl: 7200000
    # 设置前端传递过来的令牌名称
    admin-token-name: token
  #给微信
    user-token-name: authentication

    user-ttl: 7200000

    user-secret-key: ${sky.jwt.key}


  wechat:
    appid: ${sky.wechat.appid}
    secret: ${sky.wechat.secret}
    mchid: ${sky.dev.wechat.mchid}
    mchSerialNo: ${sky.dev.wechat.mchSerialNo}
    privateKeyFilePath: ${sky.dev.wechat.privateKeyFilePath}
    apiV3Key: ${sky.wechat.apiVersion3Key}
    weChatPayCertFilePath: ${sky.dev.wechat.weChatPayCertFilePath}
    notifyUrl: ${sky.dev.wechat.notifyUr1}
    refundNotifyUrl: ${sky.dev.wechat.refundNotifyUr1}

创建接口对应DTO(接收),VO(响应)
dto.UserLoginDTO.java
vo.UserLoginVO.java

Controller:

@RestController
@Slf4j
@Api(tags = "C端用户相关接口")
@RequestMapping("/user/user")
public class UserController {

    @Autowired
    private UserService userService;//登录的具体逻辑实现--微信登录--将用户信息(微信授权码)返回给Controller

    @Autowired
    private JwtProperties jwtProperties;

    @PostMapping("/login")
    @ApiOperation("用户微信登录")
    public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) {
        log.info("用户的授权码为:{}", userLoginDTO.getCode());

        //微信登录
        User user = userService.wxLogin(userLoginDTO);
        //用户的主键值
        Map<String, Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID, user.getId());

        //生成JWT令牌
        String jwt = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
        //封装VO对象
        UserLoginVO userLoginVO = UserLoginVO.builder()
            .openid(user.getOpenid())
            .token(jwt)
            .id(user.getId())
            .build();

        return Result.success(userLoginVO);
    }

}

Service:

public class UserServiceImpl implements UserService {

    //微信服务接口地址--用httpclient调
    private static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WeChatProperties weChatProperties;

    @Override
    public User wxLogin(UserLoginDTO userLoginDTO) {
        //1.调用微信接口,获得微信用户openid
        String openid = getOpenid(userLoginDTO.getCode());
        //2.判断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");
        //获取返回的json字符串
        String json = HttpClientUtil.doGet(WX_LOGIN, map);
        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");//取出openid

        return openid;
    }
}

Mapper:

@Select("select * from user where openid=#{openid}")
    User getByOpenid(String openid);
    void insert(User user);//需要返回主键值

为了让这个Insert能返回插入之后数据库自动生成的主键值,通过xml修改:

<insert id="insert" parameterType="User" 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>

编写拦截器校验用户端请求头携带的token是否合法

@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.java

protected void addInterceptors(InterceptorRegistry registry) {
        log.info("开始注册自定义拦截器...");
        registry.addInterceptor(jwtTokenAdminInterceptor)
            .addPathPatterns("/admin/**")
            .excludePathPatterns("/admin/employee/login");

        registry.addInterceptor(jwtTokenUserInterceptor)//注册用户端请求拦截器
            .addPathPatterns("/user/**")
            .excludePathPatterns("/user/user/login")//正要登录
            .excludePathPatterns("/user/shop/status");//在登录之前就查询了
    }

商品浏览

在这里插入图片描述
涉及这4个接口。
具体代码略。

  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值