【苍穹外卖】项目实战Day06

🔥 本文由 程序喵正在路上 原创,优快云首发!
💖 系列专栏:苍穹外卖项目实战
🌠 首发时间:2024年5月9日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾

HttpClient

介绍

HttpClientApache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。

HttpClient 作用:

  1. 发送 HTTP 请求
  2. 接收响应数据

核心API

  • HttpClient
  • HttpClients
  • CloseableHttpClient
  • HttpGet
  • HttpPost

发送请求步骤:

  • 创建 HttpClient 对象
  • 创建 Http 请求对象
  • 调用 HttpClientexecute 方法发送请求

使用 HttpClient 需要导入它的 maven 坐标:
在这里插入图片描述

由于我们项目中已经导入了阿里云 OSS 的依赖,而阿里云 OSS 的底层已经包含了 HttpClient,所以我们就不用再导入了。当然,再单独导入也没什么问题。

在这里插入图片描述

入门案例

GET 方式请求:

新建测试类 HttpClientTest,创建测试方法 testGET

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;

import java.io.IOException;

@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();
    }
}

先启动项目和 redis 服务端,再执行 testGET 方法,查看结果:

在这里插入图片描述

POST 方式请求:

/**
 * 测试通过httpclient发送POST方式的请求
 */
@Test
public void testPOST() throws Exception {
    //创建httpclient对象
    CloseableHttpClient httpClient = HttpClients.createDefault();

    //创建请求对象, 请求地址为管理端登录的地址
    HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");

    //构造json数据
    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();
}

在这里插入图片描述

为了方便我们后续使用,项目中已经实现了一个 HttpClient 的工具类:

在这里插入图片描述

微信小程序开发

介绍

在这里插入图片描述

官网:https://mp.weixin.qq.com/cgi-bin/wx?token=&lang=zh_CN

在这里插入图片描述

ps:个人开发的小程序是不支持支付功能的。

在这里插入图片描述

在这里插入图片描述

准备工作

开发微信小程序之前需要做如下准备工作:

  • 注册小程序
  • 完善小程序信息
  • 下载开发者工具

注册小程序

注册地址:https://mp.weixin.qq.com/wxopen/waregister?action=step1

在这里插入图片描述

完善小程序信息

登录小程序后台:https://mp.weixin.qq.com/,点击进入登录,然后自行完善小程序信息、小程序类目

在这里插入图片描述

下滑来到开发管理页面,这里的小程序ID和小程序密钥我们后面都会用到,记得保存:

在这里插入图片描述

下载开发者工具

下载地址: https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html

在这里插入图片描述

下载安装,登录后来到主页面:

在这里插入图片描述

创建小程序项目:

在这里插入图片描述

熟悉开发者工具布局:

在这里插入图片描述

设置不校验合法域名:

在这里插入图片描述

入门案例

操作步骤:

  • 了解小程序目录结构
  • 编写小程序代码
  • 编译小程序

了解小程序目录结构

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

在这里插入图片描述

一个小程序页面由四个文件组成:
在这里插入图片描述

编写小程序代码

我们在项目自带的这个页面中来写一些小程序的入门案例:

在这里插入图片描述

index.wxml

<!--index.wxml-->
<navigation-bar title="Weixin" back="{{false}}" color="black" background="#FFF"></navigation-bar>
<scroll-view class="scrollarea" scroll-y type="list">
  <view class="container">
    <view>{{msg}}</view>

    <!-- 获取用户的头像和昵称 -->
    <view>
      <button type="default" bind:tap="getUserInfo">获取用户信息</button>
      <image style="width: 100px;height: 100px;" src="{{avatarUrl}}"></image>
      {{nickName}}
    </view>

    <!-- 微信登录,获取微信用户的授权码 -->
    <view>
      <button type="primary" bind:tap="wxlogin">微信登录</button>
      <text style="font-size: small;">获取到的授权码: {{code}}</text>
    </view>

    <!-- 发送请求 -->
    <view>
      <button type="primary" bind:tap="sendRequest">发送请求</button>
      <text style="font-size: small;">响应结果: {{result}}</text>
    </view>

  </view>
</scroll-view>

index.js

// index.js
Page({
  //数据
  data: {
    msg: 'hello weixin',
    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
        })
      }
    })
  }
})

在这里插入图片描述

编译小程序

在这里插入图片描述

发布小程序

如果我们的小程序已经开发完,我们可以将其上传到微信的服务器:

在这里插入图片描述

然后它就会出现在微信平台的版本管理中的开发版本中,我们需要提交审核,审核通过后小程序才算上线。

在这里插入图片描述

微信登录

导入小程序代码

由于小程序开发属于前端的内容,我们这里就不再多讲,直接导入准备好的小程序代码。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

需要说明一下的是,如果你的后端服务端口号和图中的不同,那么需要修改一下。

在这里插入图片描述

微信登录流程

微信登录:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

在这里插入图片描述

说明

  1. 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
  2. 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 、 用户在微信开放平台账号下的唯一标识UnionID(若当前小程序已绑定到微信开放平台账号) 和 会话密钥 session_key

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

在这里插入图片描述

需求分析和设计

产品原型:
在这里插入图片描述

业务规则:

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

接口设计:

在这里插入图片描述

数据库设计(user表):

在这里插入图片描述

ps:个人注册的小程序是无法获取到用户的手机号的。

代码开发

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

在这里插入图片描述

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

在这里插入图片描述

DTO 设计:

在这里插入图片描述

VO 设计:

在这里插入图片描述

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

import com.sky.constant.JwtClaimsConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;
import com.sky.properties.JwtProperties;
import com.sky.result.Result;
import com.sky.service.UserService;
import com.sky.utils.JwtUtil;
import com.sky.vo.UserLoginVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/user/user")
@Api("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 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 接口,声明 wxLogin 方法:

import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;

public interface UserService {

    /**
     * 根据微信授权码实现微信登录
     *
     * @param userLoginDTO
     * @return
     */
    User wxLogin(UserLoginDTO userLoginDTO);
}

创建 UserServiceImpl 实现类,实现 wxLogin 方法:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sky.constant.MessageConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;
import com.sky.exception.LoginFailedException;
import com.sky.mapper.UserMapper;
import com.sky.properties.WeChatProperties;
import com.sky.service.UserService;
import com.sky.utils.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.spel.ast.OpNE;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WeChatProperties weChatProperties;

    /**
     * 根据微信授权码实现微信登录
     *
     * @param userLoginDTO
     * @return
     */
    public User wxLogin(UserLoginDTO userLoginDTO) {
        //授权码
        String code = userLoginDTO.getCode();
        String openid = getOpenid(code);

        if (openid == null) {
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
        }

        //根据openid查询用户信息
        User user = userMapper.getByOpenid(openid);

        //用户为小程序的新用户, 将其信息保存起来
        if (user == null) {
            user = new User();
            user.setOpenid(openid);
            user.setCreateTime(LocalDateTime.now());
            userMapper.insert(user);
        }

        return user;
    }

    /**
     * 获取微信用户的唯一标识openid
     *
     * @param code
     * @return
     */
    private String getOpenid(String code) {
        //请求参数封装
        Map 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);
        log.info("微信登录返回结果:{}", json);

        //解析json字符串, 获取openid
        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");
        log.info("微信用户的openid为:{}", openid);

        return openid;
    }
}

创建 UserMapper 接口:

import com.sky.entity.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@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 映射文件:

<?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}, #{idNumber}, #{avatar}, #{createTime})
    </insert>
</mapper>

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

复制 JwtTokenAdminInterceptor,再稍微修改即可

在这里插入图片描述

WebMvcConfiguration 配置类中注册拦截器:

在这里插入图片描述

功能测试

启动项目,来到小程序端点击登录:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

导入商品浏览功能代码

需求分析和设计

产品原型:

在这里插入图片描述

接口设计:

  • 查询分类

    在这里插入图片描述

  • 根据分类 id 查询菜品

    在这里插入图片描述

  • 根据分类 id 查询套餐

    在这里插入图片描述

  • 根据套餐 id 查询包含的菜品

    在这里插入图片描述

代码导入

除了 Controller 的代码可以直接拷贝文件,其他的代码都需要打开文件复制对应的代码到原文件中

在这里插入图片描述

功能测试

在这里插入图片描述

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序喵正在路上

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值