苍穹外卖-day06 -基于微信小程序开发

1. HttpClient

前言

Hyper-Text Transfer Protocol(HTTP 超文本传输协议)应该是应用在互联网上最重要的协议了。
网络服务,网络使能应用以及云计算的增多,在增加需要 HTTP 支持的应用数量时,不断的扩展 HTTP 协议在用户主导的浏览器中所扮演的角色。

尽管 java.net 包提供了基础的功能,可以通过 HTTP 协议来访问网络资源,但它没有提供许多应用需要的灵活性或功能性。
HttpClient 通过高效,即时,并且富有特色的包填补 java.net 这一空缺,实现了 HTTP 绝大部分的标准和建议的客户端。

用于扩展,并为基础 HTTP 协议提供鲁棒性支持的 HttpClient 将受到那些构建 HTTP 客户端应用的用户青睐,
例如 web 浏览器,网络服务客户端,或者是运用或扩展 HTTP 协议用于分布式会议。

HttpClient 适用范围

  • 客户端 HTTP 传输库基于 HttpCore
  • 基于传统(阻塞式)I/O
  • 内容无关

HttpClient 不是什么

  • HttpClient 不是浏览器,它是客户端的 HTTP 传输库。它的目的在于发送、接受 HTTP 信息。如果没有明确设置,或者
    重新格式化请求 / 重写定位 URI, 或其它不涉及 HTTP 传输的功能,HttpClient 不会去
    解析内容,运行嵌入在 HTML 页面的 javascript 代码,获取内容类型(content type)。

HttpClient作用:

  • 发送HTTP请求

  • 接收响应数据

其实,应用程序本身并未实现这些功能,都是在应用程序里访问提供这些功能的服务,访问这些服务需要发送HTTP请求,并且接收响应数据,可通过HttpClient来实现。

HttpClient的maven依赖:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>

HttpClient的核心API:

         HttpClient:Http客户端对象类型,使用该类型对象可发起Http请求。

         HttpClients:可认为是构建器,可创建HttpClient对象。

         CloseableHttpClient:实现类,实现了HttpClient接口。

         HttpGet:Get方式请求类型。

         HttpPost:Post方式请求类型。

HttpClient发送请求步骤:

  • 创建HttpClient对象

  • 创建Http请求对象

  • 调用HttpClient的execute方法发送请求

例子:

实现步骤:

  1. 创建HttpClient对象

  2. 创建请求对象

  3. 发送请求,接受响应结果

  4. 解析结果

  5. 关闭资源

package com.sky.test;
​
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
​
@SpringBootTest
public class HttpClientTest {
​
    /**
     * 测试通过httpclient发送GET方式的请求
     */
    @Test
    public void testGET() throws Exception{
        //创建httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
​
        //创建请求对象(在请求该路径的时候,该路径必须在运行中)
        HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status");
​
        //发送请求,接受响应结果
        CloseableHttpResponse response = httpClient.execute(httpGet);
​
        //获取服务端返回的状态码
        int statusCode = response.getStatusLine().getStatusCode();
        System.out.println("服务端返回的状态码为:" + statusCode);
​
        HttpEntity entity = response.getEntity();
        String body = EntityUtils.toString(entity);
        System.out.println("服务端返回的数据为:" + body);
​
        //关闭资源
        response.close();
        httpClient.close();
    }
}

在访问http://localhost:8080/user/shop/status请求时,需要提前启动项目。

1.2.2 POST方式请求
在HttpClientTest中添加POST方式请求方法,相比GET请求来说,POST请求若携带参数需要封装请求体对象,并将该对象设置在请求对象中。

实现步骤:

创建HttpClient对象

创建请求对象

发送请求,接收响应结果

解析响应结果

关闭资源

 /**
     * 测试通过httpclient发送POST方式的请求
     */
    @Test
    public void testPOST() throws Exception{
        // 创建httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
​
        //创建请求对象
        HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");
​
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("username","admin");
        jsonObject.put("password","123456");
​
        StringEntity entity = new StringEntity(jsonObject.toString());
        //指定请求编码方式
        entity.setContentEncoding("utf-8");
        //数据格式
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
​
        //发送请求
        CloseableHttpResponse response = httpClient.execute(httpPost);
​
        //解析返回结果
        int statusCode = response.getStatusLine().getStatusCode();
        System.out.println("响应码为:" + statusCode);
​
        HttpEntity entity1 = response.getEntity();
        String body = EntityUtils.toString(entity1);
        System.out.println("响应数据为:" + body);
​
        //关闭资源
        response.close();
        httpClient.close();
    }

2. 微信小程序开发
2.1 介绍
小程序是一种新的开放能力,开发者可以快速地开发一个小程序。可以在微信内被便捷地获取和传播,同时具有出色的使用体验。

官方网址:微信小程序

小程序主要运行微信内部,可通过上述网站来整体了解微信小程序的开发。

首先,在进行小程序开发时,需要先去注册一个小程序,在注册的时候,它实际上又分成了不同的注册的主体。我们可以以个人的身份来注册一个小程序,当然,也可以以企业政府、媒体或者其他组织的方式来注册小程序。那么,不同的主体注册小程序,最终开放的权限也是不一样的。比如以个人身份来注册小程序,是无法开通支付权限的。若要提供支付功能,必须是企业、政府或者其它组织等。所以,不同的主体注册小程序后,可开发的功能是不一样的。

2.2 准备工作

1. 注册小程序

注册地址:小程序

2. 完善小程序信息

登录小程序后台:微信公众平台

登录方式

完善小程序信息、小程序类目

查看小程序的 AppID(一定要记下来)

3.下载开发者工具

资料中已提供,无需下载,熟悉下载步骤即可。

创建小程序项目

熟悉开发者工具布局

设置不校验合法域名

注意:在没有域名的情况下,如果直接使用小程序发出的请求到服务器的话,会发送失败。所以需要勾选上不检验合法域名

2.3 入门案例

实际上,小程序的开发本质上属于前端开发,主要使用JavaScript开发,所以,对于小程序开发简单了解即可。

2.3.1 小程序目录结构

小程序包含一个描述整体程序的 app 和多个描述各自页面的 page。一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下:

文件说明:

app.js:必须存在,主要存放小程序的逻辑代码

app.json:必须存在,小程序配置文件,主要存放小程序的公共配置

app.wxss: 非必须存在,主要存放小程序公共样式表,类似于前端的CSS样式

对小程序主体三个文件了解后,其实一个小程序又有多个页面。比如说,有商品浏览页面、购物车的页面、订单支付的页面、商品的详情页面等等。那这些页面会放在哪呢? 会存放在pages目录。

每个小程序页面主要由四个文件组成:

文件说明:

js文件:必须存在,存放页面业务逻辑代码,编写的js代码。

wxml文件:必须存在,存放页面结构,主要是做页面布局,页面效果展示的,类似于HTML页面。

json文件:非必须,存放页面相关的配置。

wxss文件:非必须,存放页面样式表,相当于CSS文件。

2.3.2 编写和编译小程序

1). 编写

进入到index.wxml,编写页面布局

<view class="container">
  <view>{{msg}}</view>
   <view>
    <button type="default" bindtap="getUserInfo">获取用户信息</button>
    <image style="width: 100px;height: 100px;" src="{{avatarUrl}}"></image>
    {{nickName}}
  </view>
   <view>
    <button type="primary" bindtap="wxlogin">微信登录</button>
    授权码:{{code}}
  </view>
   <view>
    <button type="warn" bindtap="sendRequest">发送请求</button>
    响应结果:{{result}}
  </view>
</view>


进入到index.js,编写业务逻辑代码

Page({
  data:{
    msg:'hello world',
    avatarUrl:'',
    nickName:'',
    code:'',
    result:''
  },
  getUserInfo:function(){
    wx.getUserProfile({
      desc: '获取用户信息',
      success:(res) => {
        console.log(res)
        this.setData({
          avatarUrl:res.userInfo.avatarUrl,
          nickName:res.userInfo.nickName
        })
      }
    })
  },
  wxlogin:function(){
    wx.login({
      success: (res) => {
        console.log("授权码:"+res.code)
        this.setData({
          code:res.code
        })
      }
    })
  },
  sendRequest:function(){
    wx.request({
      url: 'http://localhost:8080/user/shop/status',
      method:'GET',
      success:(res) => {
        console.log("响应结果:" + res.data.data)
        this.setData({
          result:res.data.data
        })
      }
    })
  }})


2). 编译

点击编译按钮

3). 运行效果

点击获取用户信息

点击发送请求

因为请求http://localhost:8080/user/shop/status,先要启动后台项目。

注:设置不校验合法域名,若不勾选,请求发送失败。

2.3.3 发布小程序

小程序的代码都已经开发完毕,要将小程序发布上线,让所有的用户都能使用到这个小程序。

点击上传按钮:

定版本号:

上传成功:

把代码上传到微信服务器就表示小程序已经发布了吗? 其实并不是。当前小程序版本只是一个开发版本。

进到微信公众平台,打开版本管理页面。

需提交审核,变成审核版本,审核通过后,进行发布,变成线上版本。

一旦成为线上版本,这就说明小程序就已经发布上线了,微信用户就可以在微信里面去搜索和使用这个小程序了。

3. 微信登录

3.1 导入小程序代码

开发微信小程序,本质上是属于前端的开发,我们的重点其实还是后端代码开发。所以,小程序的代码已经提供好了,直接导入到微信开发者工具当中,直接来使用就可以了。

2. 导入代码

AppID:使用自己的AppID

3. 查看项目结构

主体的文件:app.js app.json app.wxss 项目的页面比较多,主要存放在pages目录。

4. 修改配置

因为小程序要请求后端服务,需要修改为自己后端服务的ip地址和端口号(默认不需要修改)

common-->vendor.js-->搜索(ctrl+f)-->baseUri

3.2 微信登录流程(流程图具体看微信开放文档)

微信登录:小程序登录 | 微信开放文档

步骤分析:

小程序端,调用wx.login()获取code,就是授权码。

小程序端,调用wx.request()发送请求并携带code,请求开发者服务器(自己编写的后端服务)。

开发者服务端,通过HttpClient向微信接口服务发送请求,并携带appId+appsecret+code三个参数。

开发者服务端,接收微信接口服务返回的数据,session_key+opendId等。opendId是微信用户的唯一标识。

开发者服务端,自定义登录态,生成令牌(token)和openid等数据返回给小程序端,方便后绪请求身份校验。

小程序端,收到自定义登录态,存储storage。

小程序端,后绪通过wx.request()发起业务请求时,携带token。

开发者服务端,收到请求后,通过携带的token,解析当前登录用户的id。

开发者服务端,身份校验通过后,继续相关的业务逻辑处理,最终返回业务数据

测试

1.调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。

2.调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 、 用户在微信开放平台帐号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台帐号) 和 会话密钥 session_key。

之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。

实现步骤:

1. 获取授权码

点击确定按钮,获取授权码,每个授权码只能使用一次,每次测试,需重新获取。

2. 调用微信提供的请求接口

请求方式、请求路径、请求参数

3. 发送请求

获取session_key和openid

若出现code been used错误提示,说明授权码已被使用过,请重新获取

3.3 需求分析和设计
3.3.1 产品原型
第一次进入到小程序的时候,微信授权登录之后才能点餐。需要获取当前微信用户的相关信息,比如昵称、头像等,这样才能够进入到小程序进行下单操作。是基于微信登录来实现小程序的登录功能,没有采用传统账户密码登录的方式。若第一次使用小程序来点餐,就是一个新用户,需要把这个新的用户保存到数据库当中完成自动注册。

业务规则:

  • 基于微信登录实现小程序的登录功能

  • 如果是新用户需要自动完成注册

3.3.2 接口设计

通过微信登录的流程,如果要完成微信登录的话,最终就要获得微信用户的openid。在小程序端获取授权码后,向后端服务发送请求,并携带授权码,这样后端服务在收到授权码后,就可以去请求微信接口服务。最终,后端向小程序返回openid和token等数据。

说明:请求路径/user/user/login,第一个user代表用户端,第二个user代表用户模块。

3.3.3 表设计

当用户第一次使用小程序时,会完成自动注册,把用户信息存储到user表中。

字段名数据类型 说明备注
id    bigint主键自增
openidvarchar(45)微信用户的唯一标识
namevarchar(32) 用户姓名
phonevarchar(11)手机号 
sexvarchar(2)性别 
id_numbervarchar(18)身份证号
avatarvarchar(500)微信用户头像路径
create_timedatetime注册时间

说明:手机号字段比较特殊,个人身份注册的小程序没有权限获取到微信用户的手机号。

3.4 代码开发
3.4.1 定义相关配置

配置微信登录所需配置项:

application-dev.yml

application.yml

配置为微信用户生成jwt令牌时使用的配置项:

application.yml

3.4.2 DTO设计

在sky-pojo模块,UserLoginDTO

3.4.3 VO设计

3.4.4 Controller层

根据接口定义创建UserController的login方法:

3.4.5 Service层接口

创建UserService接口:

3.4.6 Service层实现类

创建UserServiceImpl实现类:实现获取微信用户的openid和微信登录功能

3.4.7 Mapper层

创建UserMapper接口:

创建UserMapper.xml映射文件:

3.4.8 编写拦截器

编写拦截器JwtTokenUserInterceptor:统一拦截用户端发送的请求并进行jwt校验

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配置类中注册拦截器:

@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {

    @Autowired
    private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;

    @Autowired
    private JwtTokenUserInterceptor jwtTokenUserInterceptor;
    /**
     * 注册自定义拦截器
     *
     * @param registry
     */
    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");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值