苍穹外卖学习 Day06

前言

本篇文章用于记录苍穹外卖Day06微信登录、商品浏览的学习。

要完成微信登录功能,我们需要用到HttpClient,所以在介绍微信登录功能前,先介绍一下HttpClient

HttpClient

HttpClient可以提供高效的、功能丰富的支持Http协议的客户端编程工具包。允许我们在Java程序中通过编码的方式向客户端发送Http请求(GET、POST…)。

核心API:

  • HttpClient
  • HttpClients
  • CloseableHttpClient
  • HttpGet
  • HttpPost

HttpClient为一个接口,CloseableHttpClient为其实现类

发送请求步骤:

  • 创建HttpClient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
  • 创建Http请求对象(HttpGet、HttpPost)
HttpGet httpGet=new HttpGet("http://localhost:9010/user/shop/status");
  • 调用HttpClient的execute方法发送请求
CloseableHttpResponse response=httpClient.execute(httpGet);
  • 最后就是将返回的数据做个解析以及释放资源

微信登录

关于微信小程序端我就直接导入代码了(按照老师的导入的话可能出现报错,这里导入时我的后端服务选择的是不使用云服务),对小程序开发感兴趣的可以去深入了解一下,这里把主要工作放在后端代码开发。

在开发微信登录接口之前,我先来简单介绍一下微信登录的流程

  • 首先小程序就是微信小程序,开发者服务器就是我们编写的后端服务,微信接口服务是由微信官方提供的服务。

在这里插入图片描述

  • 在我们的小程序端点击确定去登录时,会调用login()方法生成一个code(如下图所示)

在这里插入图片描述

  • 此时我们的后端服务要接收到这个code和其他参数(具体如下所示),发送请求调用微信接口服务为我们生成返回一些数据如session_key、openid,其中openid是我们微信用户的一个唯一标识,此时我们就可以根据openid为用户生成一个token令牌,每次访问都携带这个令牌进行数据访问

在这里插入图片描述

那么正式进入到微信登录功能的代码开发:

  • UserController,在controller层,我们发送登录请求之后,响应成功后会返回一个微信用户唯一标识openid,我们要根据这个openid生成一个JWT令牌,后续用户都要携带这个JWT令牌进行数据访问。同时我们要封装好一个UserLoginVO返回给小程序端。
@RestController
@Slf4j
@RequestMapping("/user/user")
@Api(tags = "用户登录接口")
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private JwtProperties jwtProperties;
    @PostMapping("/login")
    @ApiOperation("微信登录")
    public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO){
        log.info("微信登录:{}",userLoginDTO.getCode());
        //微信登录
        User user=userService.login(userLoginDTO);

        //生成jwt令牌
        HashMap<String, Object> claims=new HashMap<>();
        //JwtClaimsConstant.USER_ID->userId
        claims.put(JwtClaimsConstant.USER_ID,user.getId());
        String token=JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
		//封装UserLoginVO对象返回给小程序端
        UserLoginVO userLoginVO=new UserLoginVO();
        userLoginVO.setId(user.getId());
        userLoginVO.setOpenid(user.getOpenid());
        userLoginVO.setToken(token);

        return Result.success(userLoginVO);
    }
}
  • UserService
public interface UserService {
    User login(UserLoginDTO userLoginDTO);
}
  • UserServiceImpl,在service实现类中我们要先通过HttpClient获得openid,接着就是做一些判断新增user之类的操作
@Service
public class UserServiceImpl implements UserService {

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

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WeChatProperties weChatProperties;
    @Override
    public User login(UserLoginDTO userLoginDTO) {
        //调用微信接口服务获得当前微信用户的openid
        Map<String,String> map=new HashMap<>();
        map.put("appid", weChatProperties.getAppid());
        map.put("secret", weChatProperties.getSecret());
        map.put("js_code",userLoginDTO.getCode());
        map.put("grant_type","authorization_code");
        String json=HttpClientUtil.doGet(WX_LOGIN,map);

        //获取当前的openid
        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");

        //判断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;
    }
}
  • UserMapper
@Mapper
public interface UserMapper {
    @Select("select * from user where openid=#{openid}")
    User getByOpenId(String openid);

    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>

那么登录接口就开发好了,最后别忘了配置一下拦截器

启动服务,在小程序端登录,出现以下则代表登录成功(http响应码为200):

在这里插入图片描述

菜品浏览

在课程中,该部分的代码是直接导入的,这里我还是从头来编码一遍。

许多方法在我们之前的接口已经开发好了,这里直接调用即可

在菜品浏览功能开发,我们要涉及到四个接口的开发:

  • 查询分类

  • 根据分类id查询菜品(同时查询口味)

  • 根据分类id查询套餐

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

查询分类

一定要记得因为我们admin包下也有一个CategoryController,记得区分开

@RestController("userCategoryController")
@Slf4j
@Api(tags = "查询分类接口")
@RequestMapping("/user/category")
public class CategoryController {
    @Autowired
    private CategoryService categoryService;

    @GetMapping("/list")
    @ApiOperation("查询分类")
    public Result<List<Category>> list(Integer type){
        log.info("查询分类:{}",type);
        List<Category> list=categoryService.list(type);
        return Result.success(list);
    }
}

其他层的代码我们之前就写好了,在controller层调用List()方法即可

根据分类id查询菜品同时查询口味

同样记得与admin包下的DishController区分开

@RestController("userDishController")
@Slf4j
@RequestMapping("/user/dish")
@Api(tags = "根据分类id查询菜品")
public class DishController {
    @Autowired
    private DishService dishService;

    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<DishVO>> list(Long categoryId){
        log.info("根据分类id查询菜品:{}",categoryId);
        Dish dish=new Dish();
        dish.setCategoryId(categoryId);
        dish.setStatus(StatusConstant.ENABLE);

        List<DishVO> list=dishService.listWithFlavor(dish);
        return Result.success(list);
    }
}

service层代码就省略了,这里直接给出实现类代码:

	//查询菜品以及其口味
    @Override
    public List<DishVO> listWithFlavor(Dish dish) {
        List<Dish> list=dishMapper.list(dish);
        List<DishVO> dishVOList=new ArrayList<>();
        for (Dish dish1 : list) {
            //将查询出来的dish的所以属性赋值给dishVO
            DishVO dishVO=new DishVO();
            BeanUtils.copyProperties(dish1,dishVO);

            //查询口味数据
            List<DishFlavor> flavors=dishMapper.getByDishId(dish1.getId());
            dishVO.setFlavors(flavors);

            dishVOList.add(dishVO);
        }
        return dishVOList;
    }

根据分类id查询套餐、根据套餐id查询包含的菜品

@RestController("userSetmealController")
@Slf4j
@RequestMapping("/user/setmeal")
@Api(tags = "根据分类id查询套餐")
public class SetmealController {
    @Autowired
    private SetmealService setmealService;

    @GetMapping("/list")
    public Result<List<Setmeal>> list(Long categoryId){
        log.info("根据分类id查询套餐:{}",categoryId);
        Setmeal setmeal=new Setmeal();
        setmeal.setCategoryId(categoryId);
        setmeal.setStatus(StatusConstant.ENABLE);

        List<Setmeal> list=setmealService.list(setmeal);
        return Result.success(list);
    }

    @GetMapping("/dish/{id}")
    @ApiOperation("根据套餐id查询菜品")
    public Result<List<DishItemVO>> dishItemVO(@PathVariable Long id){
        log.info("根据套餐id查询菜品:{}",id);
        List<DishItemVO> list=setmealService.dishItemVO(id);
        return Result.success(list);
    }
}

SetmealServiceImpl实现类:

	@Override
    public List<Setmeal> list(Setmeal setmeal) {
        List<Setmeal> list=setmealMapper.getByCategoryId(setmeal);
        return list;
    }

    @Override
    public List<DishItemVO> dishItemVO(Long id) {
        //根据套餐id查询套餐中包含的菜品
        List<DishItemVO> list=setmealMapper.getDishItemVO(id);
        return list;
    }

SetmealMapper:

因为DishItemVO中的属性在setmeal_dish和dish这两张表中,所以在这多表查询

	List<Setmeal> getByCategoryId(Setmeal setmeal);

    @Select("select dish.name,sd.copies,dish.image,dish.description from setmeal_dish sd left join dish on sd.dish_id=dish.id where sd.setmeal_id=#{id}")
    List<DishItemVO> getDishItemVO(Long id);

SetmealMapper.xml:

	<select id="getByCategoryId" resultType="com.sky.entity.Setmeal">
        select * from setmeal
        <where>
            <if test="name!=null">and name like concat('%',#{name},'%')</if>
            <if test="categoryId!=null">and category_id=#{categoryId}</if>
            <if test="status!=null">and status=#{status}</if>
        </where>
    </select>

  • 21
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值