前言
苍穹外卖项目代码:https://github.com/Echo0701/take-out
1 HttpClient
1.1 介绍
HttpClient 是 Apche Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且支持 HTTP 协议最新的版本和建议。
pom.xml :
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version>
</dependency>
1.2 入门案例
HttpClientTest.java
@SpringBootTest
public class HttpClientTest {/*** 测试通过httpclient 发送 GET 方式请求*/@Testpublic 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 对象)HttpEntity entity = response.getEntity();//通过一个工具类 EntityUtils 解析 HttpEntity 对象String body = EntityUtils.toString(entity);System.out.println("服务端返回的数据为:" + body);//关闭资源response.close();httpClient.close();}/*** 测试通过httpclient 发送 POST 方式请求*/@Testpublic void testPOST() throws Exception {//创建 httpclient 对象CloseableHttpClient httpClient = HttpClients.createDefault();//创建请求对象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 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.1.1 注册小程序
注册地址:小程序 (qq.com)
2.1.2 完善小程序信息
2.1.3 下载开发者工具
下载地址:下载 / 稳定版更新日志 (qq.com)
2.2 入门案例
操作步骤:
- 了解小程序目录结构
- 编写小程序代码
- 编译小程序
3 微信登录
3.1 微信登录流程
微信登录:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
3.2 需求分析和设计
产品原型
接口设计
数据库设计(user 表)
【注】如果是以企业的资质注册的这个小程序是可以获得用户的手机号的,反之,以个人资质注册的不能
3.3 代码开发
配置微信登录所需配置项:
配置为微信用户生成 jwt 令牌时使用的配置项:
UserController.java
@RestController
//前面这个user代表的是user用户端,后面这个user代表user模块
@Api(tags = "C端用户相关接口")
@Slf4j
@RequestMapping("/user/user")
public class UserController {@Autowiredprivate UserService userService;@Autowiredprivate 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<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);}
}
JwtTokenUserInterceptor.java
/*** jwt令牌校验的拦截器*/
@Component
@Slf4j
public class JwtTokenUserInterceptor implements HandlerInterceptor {@Autowiredprivate 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); // 把 id 存到线程的独立空间 ThreadLocal 里面去了//3、通过,放行return true;} catch (Exception ex) {//4、不通过,响应401状态码response.setStatus(401);return false;}}
}
UserService.java
public interface UserService {/*** 微信登录* @param userLoginDTO* @return*/User wxLogin(UserLoginDTO userLoginDTO);
}
UserServiceImpl.java
@Service
@Slf4j
public class UserServiceImpl implements UserService {//微信服务接口地址public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";@Autowiredprivate WeChatProperties weChatProperties;@Autowiredprivate UserMapper userMapper;/*** 微信登录* @param userLoginDTO* @return*/public User wxLogin(UserLoginDTO userLoginDTO) {String openid = getOpenid(userLoginDTO.getCode());//判断openid是否为空,如果为空表示登录失败,抛出业务异常if(openid == null) {throw new LoginFailedException(MessageConstant.LOGIN_FAILED);}//判断当前用户是否为新用户(需要查询用户表,所以这里新建一个UserMapper)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) {//调用微信接口获得当前用户的openidMap<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);//解析json数据,先获得一个json对象,然后获取json里面的openidJSONObject jsonObject = JSON.parseObject(json);String openid = jsonObject.getString("openid");return openid;}
}
UserMapper.java
@Mapper
public interface UserMapper {/*** 根据openid查询用户* @param openid* @return*/@Select("select * from user where openid = #{openid}")User getByOpenid(String openid);/*** 插入数据* @param user*///需要返回主键值,这里需要通过xml文件 usegeneratekeys 来获取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"><!--useGeneratedKeys="true",keyProperty="id":表明我需要这个sql语句的主键返回值,而且这个主键值会赋给我们这个的id属性(为了获得这个id 然后返回给后面的口味处理的部分)--><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>
4 导入商品浏览功能代码
4.1 需求分析和设计
产品原型
接口设计
① 查询分类
② 根据分类 id 查询菜品 (查询菜品的时候关联的口味数据也一并查询)
③ 根据分类 id 查询套餐
④ 根据套餐 id 查询包含的菜品