基于SpringBoot+SSM的外卖平台Day1-6

该篇是一刷黑马程序员的苍穹外卖项目记录的笔记,参考了Purse Wind这个博主的博客(写的真心不错我觉得)

Day1开发环境搭建

nginx反向代理-网关

①提高访问速度、②进行负载均衡、③保证后端服务的安全

反向代理配置方式(在nginx软件的配置文件中进行设置),请求路径中含有api

通过proxy_pass指令进行配置http://localhost/api/employee/login--\>http://localhost:8080/admin/employee/login

负载均衡方式

MD5加密(单向的)

Swagger

帮助后端生成接口文档,可以进行在线接口测试

①导入knife4j坐标,②在配置类中加入knife4j相关配置,③设置静态资源映射,否则接口文档页面无法访问

Yapi是设计阶段使用的工具,管理和维护接口。Swagger在开发阶段使用的框架,帮助后端开发人员做后端的接口测试。

常用注解

通过注解影响原始参数的生成,使文档有更好的可读性。

代码模块说明

|--------|--------------|--------------------------------------------|
| 序号 | 名称 | 说明 |
| 1 | sky-take-out | meaven父工程,统一管理依赖版本,聚合其他子模块 |
| 2 | sky-common | 子模块,存放公共类,例如:工具类、常量类、异常类等 |
| 3 | sky-pojo | 子模块,存放实体类、VO、DTO等 |
| 4 | sky-server | 子模块,后端服务,存放配置文件、Controller、Service、Mapper等 |

sky-common:存放公共类,供其他模块使用

每个包的作用:

名称 说明
constant 存放相关常量类
context 存放上下文类
enumeration 项目的枚举类存储
exception 存放自定义异常类
json 处理json转换的类
properties 存放SpringBoot相关的配置属性类
result 返回结果类的封装
utils 常用工具类

sky-pojo:模块里存放的是entity、DTO、VO

名称 说明
Entity 实体,通常和数据库中的表对应
DTO 数据传输对象,通常用于程序中各层之间传递数据
VO 视图对象,为前端展示数据提供的对象
POJO 普通Java对象,只有属性和对应的getter和setter

sky-server:模块中存放配置文件、配置类、拦截器、controller、service、mapper、启动类

名称 说明
config 存放配置类
controller 存放controller类
interceptor 存放拦截器类
mapper 存放mapper接口
service 存放service类
SkyApplication 启动类

版权声明:本文为CSDN博主「Purse Wind」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/chan12345678910/article/details/147051485

Day2员工管理和分类操作

Day02-03配置好token之后如果出现401可以修改一下token(有时效性),换一个再运行。或者检查sql语句,下面的要是驼峰。代码修改完之后要再Debug才会生效

ThreadLocal并不是一个Thread,而是Thread的局部变量,为每一个线程提供单独一份的存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。

Page中的limit是通过TreadLocal传到Mapper层的。

新增员工

1 需求分析和设计

注意事项:

  1. 账号必须是唯一的

  2. 手机号为合法的11位手机号码

  3. 身份证号为合法的18位身份证号码

  4. 密码默认为123456

2 接口设计

3 代码开发

根据新增员工接口设计对应的DTO

3.1 controller层

进入到sky-server模块中,在com.sky.controller.admin包下,在EmployeeController中创建新增员工方法,接收前端提交的参数。

java 复制代码
 /**
     * 新增员工
     * @param employeeDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增员工")
    public Result save(@RequestBody EmployeeDTO employeeDTO){
        log.info("新增员工:{}",employeeDTO);
        employeeService.save(employeeDTO);//该方法后续步骤会定义
        return Result.success();
    }

**注:**Result类定义了后端统一返回结果格式。

进入sky-common模块,在com.sky.result包下定义了Result.java

java 复制代码
package com.sky.result;
​
import lombok.Data;
​
import java.io.Serializable;
​
/**
 * 后端统一返回结果
 * @param <T>
 */
@Data
public class Result<T> implements Serializable {
​
    private Integer code; //编码:1成功,0和其它数字为失败
    private String msg; //错误信息
    private T data; //数据
​
    public static <T> Result<T> success() {
        Result<T> result = new Result<T>();
        result.code = 1;
        return result;
    }
​
    public static <T> Result<T> success(T object) {
        Result<T> result = new Result<T>();
        result.data = object;
        result.code = 1;
        return result;
    }
​
    public static <T> Result<T> error(String msg) {
        Result result = new Result();
        result.msg = msg;
        result.code = 0;
        return result;
    }
​
}
3.2 Servicer层接口

在EmployeeService接口中声明新增员工方法

进入到sky-server模块中,com.sky.server.EmployeeService

java 复制代码
/**
     * 新增员工
     * @param employeeDTO
     */
    void save(EmployeeDTO employeeDTO);
3.3 Servicer层实现类

在EmployeeServiceImpl中实现新增员工方法

com.sky.server.impl.EmployeeServiceImpl中创建方法

java 复制代码
  /**
     * 新增员工
     *
     * @param employeeDTO
     */
    public void save(EmployeeDTO employeeDTO) {
        Employee employee = new Employee();
​
        //对象属性拷贝
        BeanUtils.copyProperties(employeeDTO, employee);
​
        //设置账号的状态,默认正常状态 1表示正常 0表示锁定
        employee.setStatus(StatusConstant.ENABLE);
​
        //设置密码,默认密码123456
        employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
​
        //设置当前记录的创建时间和修改时间
        employee.setCreateTime(LocalDateTime.now());
        employee.setUpdateTime(LocalDateTime.now());
​
        //设置当前记录创建人id和修改人id
        employee.setCreateUser(10L);//目前写个假数据,后期修改
        employee.setUpdateUser(10L);
​
        employeeMapper.insert(employee);//后续步骤定义
    }

3.4 Mapper层

在EmployeeMapper中声明insert方法

com.sky.EmployeeMapper中添加方法

java 复制代码
    /**
     * 插入员工数据
     * @param employee
     */
    @Insert("insert into employee (name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user,status) " +
            "values " +
            "(#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser},#{status})")
    void insert(Employee employee);

在application.yml中已开启驼峰命名,故id_number和idNumber可对应。

java 复制代码
mybatis:
  configuration:
    #开启驼峰命名
    map-underscore-to-camel-case: true

Day3菜品管理分类

公共字段填充

技术点:枚举、注解、AOP、反射

自定义AutoFill,用于标识需要进行公共字段自动填充的方法

自定义切面类AutoFillAspect,统一拦截加入了AutoFill注解的方法,通过反射为公共字段复制

在Mapper的方法上加入AutoFill注解

前端登录不进去有可能是8080端口被占用了,终止当前进程或者开始另一个端口就行。

复制代码
# 只查看 LISTENING(监听)状态
netstat -ano | findstr :8080 | findstr LISTENING

# 或者查看所有 8080 相关连接
netstat -ano | findstr :8080

如果显示
TCP 192.168.1.109:50763 157.148.59.148:8080 ESTABLISHED 3300

# 结束使用该连接的进程
taskkill /F /PID 3300

# 或者根据进程名判断
tasklist | findstr 3300

新增菜品

产品原型

业务规则:

  • 菜品名称是唯一的
  • 菜品必须属于某个分类下,不能单独存在
  • 新增菜品时可以根据情况选择菜品的口味
  • 每个菜品必须对应一张图片

接口设计

  • 根据类型查询分类
  • 文件上传
  • 新增菜品

接口设计

数据库设计

浏览器->后端服务->阿里云,参考下面这篇博客配置阿里云服务

苍穹外卖项目实战(日记九)-新增菜品文件上传(使用阿里云OSS对象存储服务的方法)-记录实战教程及问题的解决方法-CSDN博客

Day5 店铺营业设置状态

Redis技术

Redis是一个基于内存的key-value结构数据库,基于内存存储,读写性高,适合存储热点数据(是对于MySQL的补充)。

key是字符串类型,value有5种常用的数据类型(字符串string,哈希hash,列表list,集合set,有序集合sorted set/zset)

字符串操作命令

哈希操作命令

列表操作命令

集合操作命令

有序集合操作命令

通用命令

店铺营业状态设置

产品原型
接口设计

Day6-微信登陆、商品浏览

HttpClient:客户端编程的工具包,是Apache Jakarta Common下的子项目,可以用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议,只需要导入http坐标就可以在JAVA中使用。

微信小程序开发

电脑重启需要重新连接数据库和redis

①win+R输入services.msc找到mysql和redis手动打开,cmd窗口输入"mysql.exe所在路径" -uroot -p输入密码即可,redis如果没在目录中找到说明安装了绿色版,则在redis目录里

复制代码
redis-server.exe redis.windows.conf

再打开一个输入

复制代码
redis-cli.exe -h 127.0.0.1 -p 6379 -a 你的密码
127.0.0.1:6379> ping
PONG

然后把mysql和前端打开即可

exit退出数据可和mysql

这里有些代码可能是课程作业然后出现了一些问题,我也是调了好久终于调通了。

sky-common.src.main.java.com.sky.contant.messageConstant里面新加一个常量类

复制代码
public static final String SETMEAL_NOT_FOUND = "套餐不存在";

完整代码如下

java 复制代码
package com.sky.constant;

/**
 * 信息提示常量类
 */
public class MessageConstant {

    public static final String PASSWORD_ERROR = "密码错误";
    public static final String ACCOUNT_NOT_FOUND = "账号不存在";
    public static final String ACCOUNT_LOCKED = "账号被锁定";
    public static final String UNKNOWN_ERROR = "未知错误";
    public static final String ALREADY_EXISTS = "已存在";
    public static final String USER_NOT_LOGIN = "用户未登录";
    public static final String CATEGORY_BE_RELATED_BY_SETMEAL = "当前分类关联了套餐,不能删除";
    public static final String CATEGORY_BE_RELATED_BY_DISH = "当前分类关联了菜品,不能删除";
    public static final String SHOPPING_CART_IS_NULL = "购物车数据为空,不能下单";
    public static final String ADDRESS_BOOK_IS_NULL = "用户地址为空,不能下单";
    public static final String LOGIN_FAILED = "登录失败";
    public static final String UPLOAD_FAILED = "文件上传失败";
    public static final String SETMEAL_ENABLE_FAILED = "套餐内包含未启售菜品,无法启售";
    public static final String PASSWORD_EDIT_FAILED = "密码修改失败";
    public static final String DISH_ON_SALE = "起售中的菜品不能删除";
    public static final String SETMEAL_ON_SALE = "起售中的套餐不能删除";
    public static final String DISH_BE_RELATED_BY_SETMEAL = "当前菜品关联了套餐,不能删除";
    public static final String ORDER_STATUS_ERROR = "订单状态错误";
    public static final String ORDER_NOT_FOUND = "订单不存在";
    public static final String SETMEAL_NOT_FOUND = "套餐不存在";

}

sky-server.src.main.java.com.sky.config.WebMvcConfiguration

java 复制代码
package com.sky.config;

import com.sky.interceptor.JwtTokenAdminInterceptor;
import com.sky.interceptor.JwtTokenUserInterceptor;
import com.sky.json.JacksonObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.List;

/**
 * 配置类,注册web层相关组件
 */
@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");
    }

    /**
     * 通过knife4j生成接口文档
     * @return
     */
    @Bean
    public Docket docket1() {
        log.info("准备生成接口文档...");
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("苍穹外卖项目接口文档")
                .version("2.0")
                .description("苍穹外卖项目接口文档")
                .build();
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .groupName("管理端接口")
                .apiInfo(apiInfo)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.sky.controller.admin"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

    @Bean
    public Docket docket2() {
        log.info("准备生成接口文档...");
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("苍穹外卖项目接口文档")
                .version("2.0")
                .description("苍穹外卖项目接口文档")
                .build();
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .groupName("用户端接口")
                .apiInfo(apiInfo)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.sky.controller.user"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

    /**
     * 设置静态资源映射
     * @param registry
     */
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        log.info("开始设置静态资源映射...");
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    /**
     * 扩展Spring MVC框架的消息转化器
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器");
        //创建一个消息转换器
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        //需要为消息转换器设置一个对象转化器,对象转换器可以将JAVA对象序列化为json数据
        converter.setObjectMapper(new JacksonObjectMapper());
        //将自己的消息转化器加入到自己的容器中
        converters.add(0,converter);
    }


}

sky-server.src.main.java.com.sky.controller.admin.DishController完整代码

java 复制代码
package com.sky.controller.admin;

import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
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.*;

import java.util.List;

@RestController
@RequestMapping("/admin/dish")
@Api(tags = "后台菜品管理")
@Slf4j
public class DishController {
    @Autowired
    private DishService dishService;
    /**
     * 新增菜品
     * @param dishDTO
     * @return
     */
    @PostMapping
    @ApiOperation(value = "新增菜品")
    public Result save(@RequestBody DishDTO dishDTO){
        log.info("新增菜品:{}", dishDTO);
        dishService.saveWithFlavors(dishDTO);
        return Result.success();
    }

    /**
     * 分页查询菜品
     * @param dishPageQueryDTO
     * @return
     */
    @GetMapping("/page")
    @ApiOperation("分页查询菜品")
    public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO){
        log.info("分页查询菜品:{}", dishPageQueryDTO);
        PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);
        return Result.success(pageResult);
    }

    /**
     * 删除菜品
     * @param ids
     * @return
     */
    @DeleteMapping
    @ApiOperation("批量删除菜品")
    public Result delete(@RequestParam List<Long> ids){
        log.info("删除菜品:{}", ids);
        dishService.deleteBatch(ids);
        return Result.success();
    }

    /**
     * 根据ID查询菜品详情
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @ApiOperation("根据ID查询菜品详情")
    public Result<DishVO> getById(@PathVariable Long id){
        log.info("查询菜品:{}", id);
        DishVO dishVO = dishService.getByIdWithFlavors(id);
        return Result.success(dishVO);
    }

    @PutMapping
    @ApiOperation("更新菜品")
    public Result update(@RequestBody DishDTO dishDTO){
        log.info("更新菜品:{}", dishDTO);
        dishService.updateWithFlavors(dishDTO);
        return Result.success();
    }
    /**
     * 根据分类id查询菜品
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<Dish>> list(Long categoryId){
        List<Dish> list = dishService.list(categoryId);
        return Result.success(list);
    }

    /**
     * 菜品起售停售
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("菜品起售停售")
    public Result<String> startOrStop(@PathVariable Integer status, Long id){
        dishService.startOrStop(status,id);
        return Result.success();
    }

}

sky-server.src.main.java.com.sky.controller.admin.SetmealController完整代码

java 复制代码
package com.sky.controller.admin;

import com.sky.constant.StatusConstant;
import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.entity.Setmeal;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.SetmealService;
import com.sky.vo.DishItemVO;
import com.sky.vo.SetmealVO;
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.*;

import java.util.List;

@RestController
@RequestMapping("/admin/setmeal")
@Api(tags = "套餐相关接口")
@Slf4j
public class SetmealController {
    @Autowired
    private SetmealService setmealService;

    /**
     * 新增套餐
     * @param setmealDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增套餐")

    public Result save(@RequestBody SetmealDTO setmealDTO) {
        log.info("新增套餐:{}", setmealDTO);
        setmealService.saveWithDish(setmealDTO);
        return Result.success();
    }

    /**
     * 条件查询
     *
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询套餐")
    public Result<List<Setmeal>> list(Long categoryId) {
        Setmeal setmeal = new Setmeal();
        setmeal.setCategoryId(categoryId);
        setmeal.setStatus(StatusConstant.ENABLE);

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

    /**
     * 根据套餐id查询包含的菜品列表
     *
     * @param id
     * @return
     */
    @GetMapping("/dish/{id}")
    @ApiOperation("根据套餐id查询包含的菜品列表")
    public Result<List<DishItemVO>> dishList(@PathVariable("id") Long id) {
        List<DishItemVO> list = setmealService.getDishItemById(id);
        return Result.success(list);
    }

    /**
     * 分页查询
     * @param setmealPageQueryDTO
     * @return
     */
    @GetMapping("/page")
    @ApiOperation("分页查询")
    public Result<PageResult> page(SetmealPageQueryDTO setmealPageQueryDTO) {
        PageResult pageResult = setmealService.pageQuery(setmealPageQueryDTO);
        return Result.success(pageResult);
    }


    /**
     * 批量删除套餐
     * @param ids
     * @return
     */
    @DeleteMapping
    @ApiOperation("批量删除套餐")
    public Result delete(@RequestParam List<Long> ids){
        log.info("批量删除套餐:{}", ids);
        setmealService.delete(ids);
        return Result.success();
    }


    /**
     * 根据id获取套餐
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @ApiOperation("根据id获取套餐")
    public Result<SetmealVO> getById(@PathVariable("id") Long id){
        log.info("根据id获取套餐:{}", id);
        SetmealVO setmealVO = setmealService.getById(id);
        return Result.success(setmealVO);
    }

    // /**
    //  * 修改套餐
    //  *
    //  * @param setmealDTO
    //  * @return
    //  */
    // @PutMapping
    // @ApiOperation("修改套餐")
    // public Result update(@RequestBody SetmealDTO setmealDTO) {
    //     setmealService.update(setmealDTO);
    //     return Result.success();
    // }

    /**
     * 更新套餐
     * @param setmealDTO
     * @return
     */
    @PutMapping
    @ApiOperation("更新套餐")
    public Result Update(@RequestBody SetmealDTO setmealDTO) {
        log.info("更新套餐:{}", setmealDTO);
        setmealService.update(setmealDTO);
        return Result.success();
    }

    /**
     * 套餐起售停售
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("套餐起售停售")
    public Result startOrStop(@PathVariable Integer status, Long id) {
        setmealService.startOrStop(status, id);
        return Result.success();
    }


}

sky-server.src.main.java.com.sky.controller.user.CategoryController完整代码

java 复制代码
package com.sky.controller.user;

import com.sky.entity.Category;
import com.sky.result.Result;
import com.sky.service.CategoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController("userCategoryController")
@RequestMapping("/user/category")
@Api(tags = "C端-分类接口")
public class CategoryController {

    @Autowired
    private CategoryService categoryService;

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

sky-server.src.main.java.com.sky.controller.user.DishController完整代码

java 复制代码
package com.sky.controller.user;

import com.sky.constant.StatusConstant;
import com.sky.entity.Dish;
import com.sky.result.Result;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController("userDishController")
@RequestMapping("/user/dish")
@Slf4j
@Api(tags = "C端-菜品浏览接口")
public class DishController {
    @Autowired
    private DishService dishService;

    /**
     * 根据分类id查询菜品
     *
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<DishVO>> list(Long categoryId) {
        Dish dish = new Dish();
        dish.setCategoryId(categoryId);
        dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品

        List<DishVO> list = dishService.listWithFlavor(dish);

        return Result.success(list);
    }

}

sky-server.src.main.java.com.sky.controller.user.UserController完整代码

java 复制代码
package com.sky.controller.user;

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.jsonwebtoken.Claims;
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;
import java.util.Objects;

@RestController
@RequestMapping("/user/user")
@Api(tags = "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<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);
    }
}

sky-server.src.main.java.com.sky.interceptor.JwtTokenUserInterceptor完整代码

java 复制代码
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;
        }
    }
}

sky-server.src.main.java.com.sky.mapper.DishMapper完整代码

java 复制代码
package com.sky.mapper;

import com.github.pagehelper.Page;
import com.sky.annotation.Autofill;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.enumeration.OperationType;
import com.sky.vo.DishVO;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

@Mapper
public interface DishMapper {

    /**
     * 动态条件查询菜品
     * @param dish
     * @return
     */
    List<Dish> list(Dish dish);

    /**
     * 根据分类id查询菜品数量
     * @param categoryId
     * @return
     */
    @Select("select count(id) from dish where category_id = #{categoryId}")
    Integer countByCategoryId(Long categoryId);

    /**
     * 插入菜品数据
     * @param dish
     */
    @Autofill(value = OperationType.INSERT)
    void insert(Dish dish);

    /**
     * 菜品分页查询
     * @param dishPageQueryDTO
     * @return
     */
    Page<DishVO> pageQuery(DishPageQueryDTO dishPageQueryDTO);

    /**
     * 根据主键查询菜品
     * @param id
     * @return
     */
    @Select("select * from dish where id = #{id}")
    Dish getById(Long id);

    /**
     * 根据主键来删除菜品数据
     * @param id
     */
    @Delete("delete from dish where id = #{id}")
    void deleteById(Long id);

    /**
     * 根据菜品ID集合批量删除菜品
     * @param ids
     */
    void deleteByIds(List<Long> ids);

    /*
    根据ID动态修改菜品
     */
    @Autofill(value = OperationType.UPDATE)
    void update(Dish dish);

    /**
     * 根据套餐id查询菜品
     * sql语句的意思为根据传进来的id找到对应的套餐,
     * 然后再根据该套餐表的dish_id找到对应菜品,最后找到套餐中菜品
     * @param id
     * @return
     */
    @Select("select a.* from dish a, setmeal_dish b where a.id = b.dish_id and b.setmeal_id = #{id}")
    List<Dish> getBySetmealId(Long id);
}

sky-server.src.main.java.com.sky.mapper.SetmealDishMapper完整代码

java 复制代码
package com.sky.mapper;

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

import java.util.List;

@Mapper
public interface SetmealDishMapper {

    /**
     * 根据菜品ID查询对应的套餐ID
     * @param dishIds
     * @return
     */
    //select setmeal_id from setmeal_dish where dish_id in (1,2,3,4)
    List<Long> getSetmealIdsByDishIds(List<Long> dishIds);

    /**
     * 批量保存套餐和菜品的关联关系
     * @param setmealDishes
     */
    void insertBatch(List<SetmealDish> setmealDishes);

    /**
     * 根据套餐id删除套餐和菜品的关联关系
     * @param setmealId
     */
    @Delete("delete from setmeal_dish where setmeal_id = #{setmealId}")
    void deleteBySetmealId(Long setmealId);

    /**
     * 根据套餐id删除套餐菜品
     * @param ids
     */
    void deleteBySetmealIds(List<Long> ids);

    /**
     * 根据套餐id获取菜品id
     * @param ids
     * @return
     */
    List<Long> getDishIdsBySetmealIds(List<Long> ids);

    /**
     * 根据id获取套餐及菜品关联关系
     * @param id
     * @return
     */
    @Select("SELECT * FROM setmeal_dish WHERE id = #{id}")
    List<SetmealDish> getBySetmealId(Long id);
}

sky-server.src.main.java.com.sky.mapper.SetmealMapper完整代码

java 复制代码
package com.sky.mapper;

import com.github.pagehelper.Page;
import com.sky.annotation.Autofill;
import com.sky.annotation.Autofill;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.entity.Setmeal;
import com.sky.enumeration.OperationType;
import com.sky.vo.DishItemVO;
import com.sky.vo.SetmealVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;
@Mapper
public interface SetmealMapper {

    /**
     * 新增套餐
     * @param setmeal
     */
    @Autofill(value = OperationType.INSERT)
    void insert(Setmeal setmeal);


    /**
     * 根据分类id查询套餐的数量
     * @param id
     * @return
     */
    @Select("select count(id) from setmeal where category_id = #{categoryId}")
    Integer countByCategoryId(Long id);

    /**
     * 根据id修改套餐
     *
     * @param setmeal
     */
    @Autofill(OperationType.UPDATE)
    void update(Setmeal setmeal);

    /**
     *  分页查询
     * @param setmealPageQueryDTO
     * @return
     */
    Page<SetmealVO> pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);

    /**
     *  根据id删除套餐
     * @param ids
     */
    void deleteByIDs(List<Long> ids);

    /**
     *  根据id查询套餐1
     * @param id
     * @return
     */
    @Select("select * from setmeal where id = #{id}")
    Setmeal getByID(Long id);

    /**
     * 动态条件查询套餐
     * @param setmeal
     * @return
     */
    List<Setmeal> list(Setmeal setmeal);

    /**
     * 根据套餐id查询菜品选项
     * @param setmealId
     * @return
     */
    @Select("select sd.name, sd.copies, d.image, d.description " +
            "from setmeal_dish sd left join dish d on sd.dish_id = d.id " +
            "where sd.setmeal_id = #{setmealId}")
    List<DishItemVO> getDishItemBySetmealId(Long setmealId);


}

sky-server.src.main.java.com.sky.mapper.UserMapper完整代码

java 复制代码
package com.sky.mapper;

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

sky-server.src.main.java.com.sky.service.impl.DishServiceimpl完整代码

java 复制代码
package com.sky.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.entity.Setmeal;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.mapper.DishFlavorMapper;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealDishMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.result.PageResult;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class DishServiceimpl implements DishService {
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private DishFlavorMapper dishFlavorMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;

    @Autowired
    private SetmealMapper setmealMapper;

    /**
     * 保存菜品及其配料信息
     *@Transactional:由于涉及到多个表的操作,需要使用事务注解,保证操作的原子性
     * 事务指一组数据库操作要么全部成功,要么全部失败,如果失败,则回滚到事务开始前的状态
     * BeanUtils:用于将dto对象中的属性的值复制到entity对象(dish对象)中
     * @param dishDTO
     */
    @Transactional
    public void saveWithFlavors(DishDTO dishDTO) {
        //创建新的dish对象,用于向dish表中插入菜品信息
        Dish dish = new Dish();

        //将dto对象中的属性复制到dish对象中
        BeanUtils.copyProperties(dishDTO, dish);

        //向dish表中插入1条菜品信息
        dishMapper.insert(dish);

        //获取刚插入的菜品的id,id由数据库生成
        //这个id将用于向dish_flavor表中插入配料信息
        Long dishId = dish.getId();

        //向dish_flavor表中插入N个配料信息
        List<DishFlavor> flavors = dishDTO.getFlavors();

        //判断是否有配料信息
        //flavors != null && flavors.size() > :意义是防止空指针异常
        if (flavors != null && flavors.size() > 0) {
            //给配料信息设置dish_id
            flavors.forEach(dishflavor -> {
                dishflavor.setDishId(dishId);
            });
            //向dish_flavor表中插入N条配料信息
            dishFlavorMapper.insertBatch(flavors);
        }
    }

    /**
     * 分页查询菜品信息
     *
     * @param dishPageQueryDTO
     * @return
     */
    public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {
        PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());
        Page<DishVO> page = dishMapper.pageQuery(dishPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 根据ID批量删除菜品信息
     *
     * @param ids
     */
    @Transactional//由于涉及到多个表的操作,需要使用事务注解,保证删除操作的原子性
    public void deleteBatch(List<Long> ids) {
        //判断当前菜品是否能够被删除-是否存在起售中的菜品
        for (Long id : ids) {
            Dish dish = dishMapper.getById(id);
            if (dish.getStatus() == StatusConstant.ENABLE) {
                //抛出异常,提示菜品已上架,不能删除
                throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
            }
        }

        //是否被关联
        List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(ids);
        if (setmealIds != null && setmealIds.size() > 0) {
            //抛出异常,提示菜品已关联套餐,不能删除
            throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
        }


//        方法一:
//        删除菜品信息
//        for (Long id : ids) {
//            dishMapper.deleteByID(id);
//            //删除菜品口味信息
//            dishFlavorMapper.deleteByDishId(id);
//        }

        //方法二:
        //sql:delete from dish where id in (?,?,?)
        //批量删除菜品信息
        dishMapper.deleteByIds(ids);

        //sql:delete from dishFlavor where dish_id in (?,?,?)
        //批量删除菜品口味信息
        dishFlavorMapper.deleteByDishIds(ids);
    }

    /**
     * 根据ID查询菜品及其配料信息
     * @param id
     * @return
     */
    public DishVO getByIdWithFlavors(Long id) {
        //根据ID查询菜品
        Dish dish = dishMapper.getById(id);

        //根据id查询菜品口味信息
        List<DishFlavor> dishflavors = dishFlavorMapper.getByDishId(id);

        //将菜品和菜品口味信息封装到DishVO对象中
        DishVO dishVo = new DishVO();
        BeanUtils.copyProperties(dish, dishVo);//将dish对象中的属性复制到dishVo对象中
        dishVo.setFlavors(dishflavors);//将dishflavors列表复制到dishVo对象中
        return dishVo;
    }


    /**
     * 更新菜品及其配料信息
     * @param dishDTO
     */
    public void updateWithFlavors(DishDTO dishDTO) {
        //创建新的dish对象
        Dish dish = new Dish();

        //将dto对象中的属性复制到dish对象中
        BeanUtils.copyProperties(dishDTO, dish);//将dto对象中的属性复制到dish对象中

        //更新菜品信息
        dishMapper.update(dish);

        //删除原有的菜品口味信息
        dishFlavorMapper.deleteByDishId(dishDTO.getId());

        //插入新的菜品口味信息
        List<DishFlavor> flavors = dishDTO.getFlavors();

        //判断是否有配料信息
        if (flavors != null && flavors.size() > 0) {
            //给配料信息设置dish_id
            flavors.forEach(dishflavor -> {
                dishflavor.setDishId(dishDTO.getId());
            });
            //向dish_flavor表中插入N条配料信息
            dishFlavorMapper.insertBatch(flavors);
        }
    }

    /**
     * 根据分类ID查询菜品列表
     * @param categoryId
     * @return
     */
    public List<Dish> list(Long categoryId) {
        Dish dish = Dish.builder()
                .categoryId(categoryId)
                .status(StatusConstant.ENABLE)
                .build();
        return dishMapper.list(dish);
    }

    /**
     * 菜品起售停售
     *
     * @param status
     * @param id
     */
    @Transactional//由于涉及到多个表的操作,需要使用事务注解,保证操作的原子性
    public void startOrStop(Integer status, Long id) {
        //更新菜品状态,调用builder模式构建对象
        //为什么只使用id和status,而不使用其他属性呢?因为其他属性可能是有值的,
        // 比如name、categoryId等,但id和status是必须的,所以只使用这两个属性
        Dish dish = Dish.builder()
                .id(id)
                .status(status)
                .build();
        dishMapper.update(dish);

        if (status == StatusConstant.DISABLE) {
            // 如果是停售操作,还需要将包含当前菜品的套餐也停售
            List<Long> dishIds = new ArrayList<>();
            dishIds.add(id);
            // select setmeal_id from setmeal_dish where dish_id in (?,?,?)
            List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(dishIds);
            if (setmealIds != null && setmealIds.size() > 0) {
                for (Long setmealId : setmealIds) {
                    Setmeal setmeal = Setmeal.builder()
                            .id(setmealId)
                            .status(StatusConstant.DISABLE)
                            .build();
                    setmealMapper.update(setmeal);
                }
            }
        }
    }

    /**
     * 条件查询菜品和口味
     * @param dish
     * @return
     */
    public List<DishVO> listWithFlavor(Dish dish) {
        List<Dish> dishList = dishMapper.list(dish);

        List<DishVO> dishVOList = new ArrayList<>();

        for (Dish d : dishList) {
            DishVO dishVO = new DishVO();
            BeanUtils.copyProperties(d,dishVO);

            //根据菜品id查询对应的口味
            List<DishFlavor> flavors = dishFlavorMapper.getByDishId(d.getId());

            dishVO.setFlavors(flavors);
            dishVOList.add(dishVO);
        }

        return dishVOList;
    }


}

sky-server.src.main.java.com.sky.service.impl.SetmealServiceimpl完整代码

java 复制代码
package com.sky.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.entity.Setmeal;
import com.sky.entity.SetmealDish;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.exception.SetmealEnableFailedException;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealDishMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.result.PageResult;
import com.sky.service.SetmealService;
import com.sky.vo.DishItemVO;
import com.sky.vo.SetmealVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.datatype.DatatypeConfigurationException;
import java.util.List;

@Service//声明当前类是一个Service类,由Spring来管理
@Slf4j//声明当前类使用Slf4j日志,这样可以打印日志
public class SetmealServiceImpl implements SetmealService {
    @Autowired
    private SetmealMapper setmealMapper;
    @Autowired
    private SetmealDishMapper setmealDishMapper;
    @Autowired
    private DishMapper dishMapper;

    /**
     * 新增套餐,同时需要保存套餐和菜品的关联关系
     * @param setmealDTO
     */
    @Transactional//由于涉及到两个表的操作,需要事务控制
    public void saveWithDish(SetmealDTO setmealDTO) {
        //复制套餐dto到套餐实体
        Setmeal setmeal = new Setmeal();
        BeanUtils.copyProperties(setmealDTO, setmeal);

        //向套餐表插入数据
        setmealMapper.insert(setmeal);

        //获取生成的套餐id,id由数据库自动生成
        Long setmealId = setmeal.getId();

        //复制套餐菜品dto到套餐菜品实体,因为有套餐id,所以需要设置套餐id,然后保存到数据库,作用为保存套餐菜品的关联关系
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();//获取套餐菜品dto列表
        setmealDishes.forEach(setmealDish -> {
            setmealDish.setSetmealId(setmealId);//设置套餐id
        });

        //保存套餐和菜品的关联关系
        setmealDishMapper.insertBatch(setmealDishes);
    }

    /**
     * 分页查询
     * @param setmealPageQueryDTO
     * @return
     */
    public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {
        int pageNum = setmealPageQueryDTO.getPage();
        int pageSize = setmealPageQueryDTO.getPageSize();

        PageHelper.startPage(pageNum, pageSize);
        Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 批量删除套餐
     * 1.删除套餐表数据
     * 2.删除套餐菜品表数据
     * 3.删除菜品表数据
     * @param ids
     */
    @Transactional//由于涉及到三个表的操作,需要事务控制
    public void delete(List<Long> ids) {
        //判断起售状态是否为0,如果为0,则不能删除
        ids.forEach(id -> {
            Setmeal setmeal = setmealMapper.getByID(id);
            if (setmeal.getStatus() == StatusConstant.ENABLE) {
                throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);
            }
        });

        //判断是否有菜品关联了套餐,如果有,则不能删除
        ids.forEach(id -> {
            setmealMapper.deleteByIDs(ids);//删除套餐表数据
            setmealDishMapper.deleteBySetmealIds(ids);//删除套餐菜品表数据
        });
    }

    /**
     * 根据id查询套餐详情和菜品信息
     * @param id
     * @return
     */
    public SetmealVO getById(Long id) {
        //查询套餐信息,如果没有该菜品,则抛出异常
        Setmeal setmeal = setmealMapper.getByID(id);
        if (setmeal == null) {
            throw new SetmealEnableFailedException(MessageConstant.SETMEAL_NOT_FOUND);
        }

        //查询套餐菜品信息
        List<SetmealDish> setmealDishes = setmealDishMapper.getBySetmealId(id);

        //创建套餐vo对象
        SetmealVO setmealVO = new SetmealVO();
        BeanUtils.copyProperties(setmeal, setmealVO);

        //设置套餐菜品信息
        setmealVO.setSetmealDishes(setmealDishes);

        return setmealVO;
    }

    /**
     * 修改套餐
     * @param setmealDTO
     */
    @Transactional
    public void update(SetmealDTO setmealDTO) {
        Setmeal setmeal = new Setmeal();
        BeanUtils.copyProperties(setmealDTO, setmeal);

        //1、修改套餐表,执行update
        setmealMapper.update(setmeal);

        //套餐id
        Long setmealId = setmealDTO.getId();

        //2、删除套餐和菜品的关联关系,操作setmeal_dish表,执行delete
        setmealDishMapper.deleteBySetmealId(setmealId);

        //获取套餐菜品dto列表
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();

        //执行循环,给每个dto对象设置套餐id,然后保存到数据库,作用为保存套餐菜品的关联关系
        setmealDishes.forEach(setmealDish -> {
            setmealDish.setSetmealId(setmealId);
        });

        //3、重新插入套餐和菜品的关联关系,操作setmeal_dish表,执行insert
        setmealDishMapper.insertBatch(setmealDishes);
    }

    /**
     * 套餐起售、停售
     * @param status
     * @param id
     */
    public void startOrStop(Integer status, Long id) {
        //起售套餐时,判断套餐内是否有停售菜品,有停售菜品提示"套餐内包含未启售菜品,无法启售"
        if(status == StatusConstant.ENABLE){
            //如果有停售菜品,则抛出异常
            List<Dish> dishList = dishMapper.getBySetmealId(id);

            //判断是否有菜品关联了套餐,如果有,则不能删除
            //套餐菜品为空,就不需要判断菜品状态了
            if(dishList != null && dishList.size() > 0){
                dishList.forEach(dish -> {
                    //判断菜品状态是否为0,如果为0,则不能启用
                    if(StatusConstant.DISABLE == dish.getStatus()){
                        //抛出异常
                        throw new SetmealEnableFailedException(MessageConstant.SETMEAL_ENABLE_FAILED);
                    }
                });
            }
        }

        //修改套餐状态
        Setmeal setmeal = Setmeal.builder()
                .id(id)
                .status(status)
                .build();
        setmealMapper.update(setmeal);
    }

    /**
     * 条件查询
     * @param setmeal
     * @return
     */
    public List<Setmeal> list(Setmeal setmeal) {
        List<Setmeal> list = setmealMapper.list(setmeal);
        return list;
    }

    /**
     * 根据id查询菜品选项
     * @param id
     * @return
     */
    public List<DishItemVO> getDishItemById(Long id) {
        return setmealMapper.getDishItemBySetmealId(id);
    }


}

sky-server.src.main.java.com.sky.service.impl.UserServiceimpl完整代码

java 复制代码
package com.sky.service.impl;

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.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 WeChatProperties weChatProperties;
    @Autowired
    private 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);
        }

        //判断当前用户是否为新用户
        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");
        String json = HttpClientUtil.doGet(WX_LOGIN, map);

        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");
        return openid;
    }
}

sky-server.src.main.java.com.sky.service.DishService完整代码

java 复制代码
package com.sky.service;

import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.result.PageResult;
import com.sky.vo.DishVO;

import java.util.List;

public interface DishService {
    /**
     * 保存菜品及其配料信息
     * @param dishDTO
     */
    void saveWithFlavors(DishDTO dishDTO);

    /**
     * 分页查询菜品信息
     * @param dishPageQueryDTO
     * @return
     */
    PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO);

    /**
     * 根据ID删除菜品信息
     * @param ids
     */
    void deleteBatch(List<Long> ids);
    /**
     *
     * 根据ID查询菜品详情及其配料信息
     * @param id
     * @return
     */
    DishVO getByIdWithFlavors(Long id);

    /**
     * 更新菜品及其配料信息
     * @param dishDTO
     */
    void updateWithFlavors(DishDTO dishDTO);

    /**
     * 根据分类ID查询菜品列表
     * @param categoryId
     * @return
     */
    List<Dish> list(Long categoryId);

    /**
     * 根据ID更新菜品状态
     * @param status
     * @param id
     */
    void startOrStop(Integer status, Long id);

    /**
     * 条件查询菜品和口味
     * @param dish
     * @return
     */
    List<DishVO> listWithFlavor(Dish dish);
}

sky-server.src.main.java.com.sky.service.SetmealService完整代码

java 复制代码
package com.sky.service;

import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.entity.Setmeal;
import com.sky.result.PageResult;
import com.sky.vo.DishItemVO;
import com.sky.vo.SetmealVO;

import java.util.List;
public interface SetmealService {
    /**
     * 保存套餐及其菜品
     * @param setmealDTO
     */
    void saveWithDish(SetmealDTO setmealDTO);

    /**
     * 分页查询套餐
     * @param setmealPageQueryDTO
     * @return
     */
    PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);

    /**
     * 根据id删除套餐
     * @param ids
     */
    void delete(List<Long> ids);

    /**
     * 根据id获取套餐详情
     * @param id
     * @return
     */
    SetmealVO getById(Long id);

    /**
     * 更新套餐
     * @param setmealDTO
     */
    void update(SetmealDTO setmealDTO);

    /**
     * 套餐起售、停售
     * @param status
     * @param id
     */
    void startOrStop(Integer status, Long id);

    /**
     * 条件查询
     * @param setmeal
     * @return
     */
    List<Setmeal> list(Setmeal setmeal);

    /**
     * 根据id查询菜品选项
     * @param id
     * @return
     */
    List<DishItemVO> getDishItemById(Long id);

}

sky-server.src.main.java.com.sky.service.UserService完整代码

java 复制代码
package com.sky.service;

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

public interface UserService {


    /**
     * 微信登录
     * @param userLoginDTO
     * @return
     */
    User wxLogin(UserLoginDTO userLoginDTO);
}

sky-server.src.main.resources.mapper.DishMapper.xml完整代码

java 复制代码
<?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.DishMapper">

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into dish (name, category_id, price, image, description, status, create_time, update_time, create_user, update_user)
            values
        (#{name},#{categoryId},#{price},#{image},#{description},#{status},#{createTime},#{updateTime},#{createUser},#{updateUser})
    </insert>

    <delete id="deleteByIds">
        delete from dish where id in
        <foreach collection="ids" open="(" close=")" separator="," item="id">
            #{id}
        </foreach>
    </delete>
    <select id="pageQuery" resultType="com.sky.vo.DishVO">
        select d.* , c.name as categoryName  from dish d left outer join category c on d.category_id = c.id
        <where>
            <if test="name != null">
                and d.name like concat('%',#{name},'%')
            </if>
            <if test="categoryId != null">
                and d.category_id like concat('%',#{categoryId},'%')
            </if>
            <if test="status != null">
                and d.status like concat('%',#{status},'%')
            </if>
        </where>
        order by d.create_time desc
    </select>

    <select id="list" resultType="Dish" parameterType="Dish">
        select * from dish
        <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>
        order by create_time desc
    </select>

    <update id="update">
        update dish
        <set>
            <if test="name != null">name = #{name},</if>
            <if test="categoryId != null">category_id = #{categoryId},</if>
            <if test="price != null">price = #{price},</if>
            <if test="image != null">image = #{image},</if>
            <if test="description != null">description = #{description},</if>
            <if test="status != null">status = #{status},</if>
            <if test="updateTime != null">update_time = #{updateTime},</if>
            <if test="updateUser != null">update_user = #{updateUser},</if>
        </set>
        where id = #{id}
    </update>
</mapper>

sky-server.src.main.resources.mapper.SetmealDishMapper.xml完整代码

java 复制代码
<?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.SetmealDishMapper">

    <select id="getSetmealIdsByDishId" resultType="java.lang.Long">
        SELECT setmeal_id FROM setmeal_dish WHERE dish_id IN
        <foreach collection="dishIds" item="dishId" open="(" separator="," close=")">
            #{dishId}
        </foreach>
    </select>

    <select id="getSetmealIdsByDishIds" resultType="java.lang.Long">
        select setmeal_id from setmeal_dish where dish_id in
        <foreach collection="dishIds" item="dishId" separator="," open="(" close=")">
            #{dishId}
        </foreach>
    </select>

    <insert id="insertBatch" parameterType="list">
        insert into setmeal_dish
        (setmeal_id,dish_id,name,price,copies)
        values
        <foreach collection="setmealDishes" item="sd" separator=",">
            (#{sd.setmealId},#{sd.dishId},#{sd.name},#{sd.price},#{sd.copies})
        </foreach>
    </insert>

    <delete id="deleteBySetmealIds" parameterType="list">
        DELETE FROM setmeal_dish
        WHERE setmeal_id IN
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>

    <select id="getDishIdsBySetmealIds" resultType="java.lang.Long">
        SELECT DISTINCT dish_id
        FROM setmeal_dish
        WHERE setmeal_id IN
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>

</mapper>

sky-server.src.main.resources.mapper.SetmealMapper.xml完整代码

java 复制代码
<?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.SetmealMapper">
    <insert id="insert" parameterType="Setmeal" useGeneratedKeys="true" keyProperty="id">
        insert into setmeal
        (category_id, name, price, status, description, image, create_time, update_time, create_user, update_user)
        values (#{categoryId}, #{name}, #{price}, #{status}, #{description}, #{image}, #{createTime}, #{updateTime},
                #{createUser}, #{updateUser})
    </insert>

    <update id="update" parameterType="Setmeal">
        update setmeal
        <set>
            <if test="name != null">
                name = #{name},
            </if>
            <if test="categoryId != null">
                category_id = #{categoryId},
            </if>
            <if test="price != null">
                price = #{price},
            </if>
            <if test="status != null">
                status = #{status},
            </if>
            <if test="description != null">
                description = #{description},
            </if>
            <if test="image != null">
                image = #{image},
            </if>
            <if test="updateTime != null">
                update_time = #{updateTime},
            </if>
            <if test="updateUser != null">
                update_user = #{updateUser}
            </if>
        </set>
        where id = #{id}
    </update>

    <select id="pageQuery" resultType="com.sky.vo.SetmealVO">
        select
        s.*,c.name categoryName
        from
        setmeal s
        left join
        category c
        on
        s.category_id = c.id
        <where>
            <if test="name != null">
                and s.name like concat('%',#{name},'%')
            </if>
            <if test="status != null">
                and s.status = #{status}
            </if>
            <if test="categoryId != null">
                and s.category_id = #{categoryId}
            </if>
        </where>
        order by s.create_time desc
    </select>

    <delete id="deleteByIDs">
        delete from setmeal
        where id in
        <foreach collection = "ids" item="id" index="index" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>

    <select id="list" parameterType="Setmeal" resultType="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>

</mapper>

sky-server.src.main.resources.mapper.UserMapper.xml完整代码

java 复制代码
<?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>

sky-server.src.main.resources.application.xml和sky-server.src.main.resources.application-dev.xml按照自己的账号和密码进行修改就行了

相关推荐
zs宝来了2 小时前
Spring Cloud+Redis+Kafka高并发电商微服务系统源码深度解读
spring boot·redis·spring cloud·微服务·kafka·高并发·电商
崎岖Qiu2 小时前
【设计模式笔记26】:深入浅出「观察者模式」
java·笔记·观察者模式·设计模式
古城小栈2 小时前
Rust 模块管理与文件联动
开发语言·后端·rust
会算数的⑨2 小时前
Java场景化面经分享(一)—— JVM有关
java·开发语言·jvm·后端·面试
lpfasd1232 小时前
Spring Boot 4.0 新特性全解析 + 实操指南
java·spring boot·后端
葵花楹2 小时前
【JAVA期末复习】
java·开发语言·排序算法
3824278272 小时前
Edge开发者工具:保留日志与禁用缓存详解
java·前端·javascript·python·selenium
m0_598177232 小时前
SQL(5)- 事务
java·数据库·sql