项目实战——苍穹外卖(Day2)

目录

1.新增员工

1.1需求分析与设计

1.2代码开发

1.3功能测试

1.4代码完善

1.5 代码提交

2. 员工分页查询

2.1 需求分析和设计

2.2 代码开发

2.3 功能测试

2.4 代码完善

3. 启用禁用员工账号

3.1 需求分析设计

3.2 代码开发

3.3 功能测试

3.4 代码提交

4. 编辑员工

4.1 需求分析与设计

4.2 代码开发

4.2.1 回显员工信息功能

4.2.2 修改员工信息功能

4.3 功能测试

4.4 代码提交

5.导入分类模块功能代码

5.1 需求分析与设计

5.2 代码导入

5.2.1Mapper层

5.2.2Service层

5.2.3 Controller层

5.3 功能测试

5.4 代码提交


1.新增员工

1.1需求分析与设计

做需求分析时,往往都是对照着产品原型进行分析。

新增员工原型:

项目实战——苍穹外卖(Day2)_第1张图片

当填写完表单信息, 点击"保存"按钮后, 会提交该表单的数据到服务端, 在服务端中需要接受数据, 然后将数据保存至数据库中。

接口设计:

项目实战——苍穹外卖(Day2)_第2张图片

表设计:新增员工,其实就是将我们新增页面录入的员工数据插入到employee表。

employee表结构:

字段名 数据类型 说明 备注
id bigint 主键 自增
name varchar(32) 姓名
username varchar(32) 用户名 唯一
password varchar(64) 密码
phone varchar(11) 手机号
sex varchar(2) 性别
id_number varchar(18) 身份证号
status Int 账号状态 1正常 0锁定
create_time Datetime 创建时间
update_time datetime 最后修改时间
create_user bigint 创建人id
update_user bigint 最后修改人id

其中,employee表中的status字段已经设置了默认值1,表示状态正常。

1.2代码开发

项目实战——苍穹外卖(Day2)_第3张图片

注意:当前端提交的数据和实体类中对应的属性差别比较大时,建议使用DTO来封装数据

由于上述传入参数和实体类有较大差别,所以自定义DTO类。

package com.sky.dto;

import lombok.Data;

import java.io.Serializable;

@Data
public class EmployeeDTO implements Serializable {

    private Long id;

    private String username;

    private String name;

    private String phone;

    private String sex;

    private String idNumber;

}

EmployeeController中创建新增员工方法

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

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

/**
     * 新增员工
     * @param employeeDTO
     */
    void save(EmployeeDTO employeeDTO);

在EmployeeServiceImpl中实现新增员工方法

建议使用实体类所以需要强制对象转换

	/**
     * 新增员工
     *
     * @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);//后续步骤定义
    }

在EmployeeMapper中声明insert方法

/**
     * 插入员工数据
     * @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);
1.3功能测试

功能测试实现方式:

  • 通过接口文档测试

  • 通前后端联调测试

接口文档测试:访问http://localhost:8080/doc.html,进入新增员工接口

项目实战——苍穹外卖(Day2)_第4张图片

响应码:401 报错

报错原因:由于JWT令牌校验失败,导致EmployeeController的save方法没有被调用

解决方法:调用员工登录接口获得一个合法的JWT令牌

使用admin用户登录获取令牌

添加令牌:

将合法的JWT令牌添加到全局参数中

文档管理-->全局参数设置-->添加参数

前后端联调测试:

启动nginx,访问 http://localhost

登录-->员工管理-->添加员工

注意:由于开发阶段前端和后端是并行开发的,后端完成某个功能后,此时前端对应的功能可能还没有开发完成, 导致无法进行前后端联调测试。所以在开发阶段,后端测试主要以接口文档测试为主。

1.4代码完善

问题一

描述:录入的用户名已存,抛出的异常后没有处理

分析:

新增username=zhangsan的用户,若employee表中之前已存在。

发现,username已经添加了唯一约束,不能重复。

解决:

通过全局异常处理器来处理。

进入到sky-server模块,com.sky.hander包下,GlobalExceptionHandler.java添加方法

/**
     * 处理SQL异常
     * @param ex
     * @return
     */
    @ExceptionHandler
    public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
        //Duplicate entry 'zhangsan' for key 'employee.idx_username'
        String message = ex.getMessage();
        if(message.contains("Duplicate entry")){
            String[] split = message.split(" ");
            String username = split[2];
            String msg = username + MessageConstant.ALREADY_EXISTS;
            return Result.error(msg);
        }else{
            return Result.error(MessageConstant.UNKNOWN_ERROR);
        }
    }

再次,接口测试:

项目实战——苍穹外卖(Day2)_第5张图片

问题二:

描述:新增员工时,创建人id和修改人id设置为固定值

/**
     * 新增员工
     *
     * @param employeeDTO
     */
    public void save(EmployeeDTO employeeDTO) {
        Employee employee = new Employee();
        //................
        //当前设置的id为固定值10//
        employee.setCreateUser(10L);
        employee.setUpdateUser(10L);
        //
        //.................................

        employeeMapper.insert(employee);//后续步骤定义
    }

解决:

通过某种方式动态获取当前登录员工的id。

项目实战——苍穹外卖(Day2)_第6张图片

员工登录成功后会生成JWT令牌并响应给前端,后续请求中,前端会携带JWT令牌,通过JWT令牌可以解析出当前登录员工id。

思考:解析出登录员工id后,如何传递给Service的save方法?

通过ThreadLocal进行传递。

ThreadLocal

介绍:

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

常用方法:

  • public void set(T value) 设置当前线程的线程局部变量的值

  • public T get() 返回当前线程所对应的线程局部变量的值

  • public void remove() 移除当前线程的线程局部变量

对ThreadLocal有了一定认识后,接下来继续解决问题二

项目实战——苍穹外卖(Day2)_第7张图片

初始工程中已经封装了 ThreadLocal 操作的工具类:

在sky-common模块

package com.sky.context;

public class BaseContext {

    public static ThreadLocal threadLocal = new ThreadLocal<>();

    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    public static Long getCurrentId() {
        return threadLocal.get();
    }

    public static void removeCurrentId() {
        threadLocal.remove();
    }

}

在拦截器中解析出当前登录员工id,并放入线程局部变量中:

在sky-server模块中,拦截器:

package com.sky.interceptor;

/**
 * jwt令牌校验的拦截器
 */
@Component
@Slf4j
public class JwtTokenAdminInterceptor 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 {
        
		//.............................
       
        //2、校验令牌
        try {
            //.................
            Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
            Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
            log.info("当前员工id:", empId);
            /将用户id存储到ThreadLocal
            BaseContext.setCurrentId(empId);
            
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //......................
        }
    }
}

在Service中获取线程局部变量中的值:

	/**
     * 新增员工
     *
     * @param employeeDTO
     */
    public void save(EmployeeDTO employeeDTO) {
        //.............................

        //设置当前记录创建人id和修改人id
        employee.setCreateUser(BaseContext.getCurrentId());//目前写个假数据,后期修改
        employee.setUpdateUser(BaseContext.getCurrentId());

        employeeMapper.insert(employee);
    }
1.5 代码提交

点击提交:

项目实战——苍穹外卖(Day2)_第8张图片

继续push:

项目实战——苍穹外卖(Day2)_第9张图片

2. 员工分页查询

2.1 需求分析和设计

系统中的员工很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。而在我们的分页查询页面中, 除了分页条件以外,还有一个查询条件 "员工姓名"。

查询员工原型:

项目实战——苍穹外卖(Day2)_第10张图片

业务规则

  • 根据页码展示员工信息

  • 每页展示10条数据

  • 分页查询时可以根据需要,输入员工姓名进行查询

 接口设计

项目实战——苍穹外卖(Day2)_第11张图片

注意事项:

  • 请求参数类型为Query,不是json格式提交,在路径后直接拼接。/admin/employee/page?name=zhangsan

  • 返回数据中records数组中使用Employee实体类对属性进行封装。

2.2 代码开发

1.设计DTO类

根据请求参数进行封装,在sky-pojo模块中

package com.sky.dto;

import lombok.Data;

import java.io.Serializable;

@Data
public class EmployeePageQueryDTO implements Serializable {

    //员工姓名
    private String name;

    //页码
    private int page;

    //每页显示记录数
    private int pageSize;

}

2.封装PageResult

后面所有的分页查询,统一都封装为PageResult对象。

package com.sky.result;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

/**
 * 封装分页查询结果
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {

    private long total; //总记录数

    private List records; //当前页数据集合

}

员工信息分页查询后端返回的对象类型为: Result

package com.sky.result;

import lombok.Data;

import java.io.Serializable;

/**
 * 后端统一返回结果
 * @param 
 */
@Data
public class Result implements Serializable {

    private Integer code; //编码:1成功,0和其它数字为失败
    private String msg; //错误信息
    private T data; //数据

    public static  Result success() {
        Result result = new Result();
        result.code = 1;
        return result;
    }

    public static  Result success(T object) {
        Result result = new Result();
        result.data = object;
        result.code = 1;
        return result;
    }

    public static  Result error(String msg) {
        Result result = new Result();
        result.msg = msg;
        result.code = 0;
        return result;
    }

}

3.Controller层

/**
     * 员工分页查询
     * @param employeePageQueryDTO
     * @return
     */
    @GetMapping("/page")
    @ApiOperation("员工分页查询")
    public Result page(EmployeePageQueryDTO employeePageQueryDTO){
        log.info("员工分页查询,参数为:{}", employeePageQueryDTO);
        PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);//后续定义
        return Result.success(pageResult);
    }

4.Service层接口

/**
     * 分页查询
     * @param employeePageQueryDTO
     * @return
     */
    PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO);

5.Service层实现类

	/**
     * 分页查询
     *
     * @param employeePageQueryDTO
     * @return
     */
    public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
        // select * from employee limit 0,10
        //开始分页查询
        PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());

        Page page = employeeMapper.pageQuery(employeePageQueryDTO);//后续定义

        long total = page.getTotal();
        List records = page.getResult();

        return new PageResult(total, records);
    }

注意:此处使用 mybatis 的分页插件 PageHelper 来简化分页代码的开发。底层基于 mybatis 的拦截器实现。

故在pom.xml文中添加依赖(初始工程已添加)


   com.github.pagehelper
   pagehelper-spring-boot-starter
   ${pagehelper}

6.Mapper层

/**
     * 分页查询
     * @param employeePageQueryDTO
     * @return
     */
    Page pageQuery(EmployeePageQueryDTO employeePageQueryDTO);

在 src/main/resources/mapper/EmployeeMapper.xml 中编写SQL:

2.3 功能测试

项目实战——苍穹外卖(Day2)_第12张图片

项目实战——苍穹外卖(Day2)_第13张图片

2.4 代码完善

问题描述:操作时间字段显示有问题。

解决方式:

1). 方式一

在属性上加上注解,对日期进行格式化

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;

但这种方式,需要在每个时间属性上都要加上该注解,使用较麻烦,不能全局处理。

2). 方式二(推荐 )

在WebMvcConfiguration中扩展SpringMVC的消息转换器,统一对日期类型进行格式处理

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

添加后,再次测试

项目实战——苍穹外卖(Day2)_第14张图片

时间格式定义,sky-common模块中

package com.sky.json;

public class JacksonObjectMapper extends ObjectMapper {

	//.......
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
    //.......

    }
}

3. 启用禁用员工账号

3.1 需求分析设计

在员工管理列表页面,可以对某个员工账号进行启用或者禁用操作。账号禁用的员工不能登录系统,启用后的员工可以正常登录。如果某个员工账号状态为正常,则按钮显示为 "禁用",如果员工账号状态为已禁用,则按钮显示为"启用"。

启禁用员工原型:

项目实战——苍穹外卖(Day2)_第15张图片

业务规则:

  • 可以对状态为“启用” 的员工账号进行“禁用”操作

  • 可以对状态为“禁用”的员工账号进行“启用”操作

  • 状态为“禁用”的员工账号不能登录系统

接口设计

项目实战——苍穹外卖(Day2)_第16张图片

1). 路径参数携带状态值。

2). 同时,把id传递过去,明确对哪个用户进行操作。

3). 返回数据code状态是必须,其它是非必须。

3.2 代码开发

Controller层

在sky-server模块中,根据接口设计中的请求参数形式对应的在 EmployeeController 中创建启用禁用员工账号的方法:

/**
     * 启用禁用员工账号
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("启用禁用员工账号")
    public Result startOrStop(@PathVariable Integer status,Long id){
        log.info("启用禁用员工账号:{},{}",status,id);
        employeeService.startOrStop(status,id);//后绪步骤定义
        return Result.success();
    }

Service层接口

	/**
     * 启用禁用员工账号
     * @param status
     * @param id
     */
    void startOrStop(Integer status, Long id);

Service层实现类

在 EmployeeServiceImpl 中实现启用禁用员工账号的业务方法:

	/**
     * 启用禁用员工账号
     *
     * @param status
     * @param id
     */
    public void startOrStop(Integer status, Long id) {
        Employee employee = Employee.builder()
                .status(status)
                .id(id)
                .build();

        employeeMapper.update(employee);
    }

Mapper层

在 EmployeeMapper 接口中声明 update 方法:

/**
     * 根据主键动态修改属性
     * @param employee
     */
    void update(Employee employee);

        update employee
        
            name = #{name},
            username = #{username},
            password = #{password},
            phone = #{phone},
            sex = #{sex},
            id_Number = #{idNumber},
            update_Time = #{updateTime},
            update_User = #{updateUser},
            status = #{status},
        
        where id = #{id}
    
3.3 功能测试

项目实战——苍穹外卖(Day2)_第17张图片

项目实战——苍穹外卖(Day2)_第18张图片

点击启用:

项目实战——苍穹外卖(Day2)_第19张图片

3.4 代码提交

项目实战——苍穹外卖(Day2)_第20张图片

4. 编辑员工

4.1 需求分析与设计

在员工管理列表页面点击 "编辑" 按钮,跳转到编辑页面,在编辑页面回显员工信息并进行修改,最后点击 "保存" 按钮完成编辑操作。

员工列表原型:

项目实战——苍穹外卖(Day2)_第21张图片

修改页面原型

注:点击修改时,数据应该正常回显到修改页面。

项目实战——苍穹外卖(Day2)_第22张图片

接口设计

根据上述原型图分析,编辑员工功能涉及到两个接口:

  • 根据id查询员工信息

  • 编辑员工信息

1). 根据id查询员工信息

项目实战——苍穹外卖(Day2)_第23张图片

2). 编辑员工信息

项目实战——苍穹外卖(Day2)_第24张图片

4.2 代码开发
4.2.1 回显员工信息功能

Controller层

在 EmployeeController 中创建 getById 方法:

/**
     * 根据id查询员工信息
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @ApiOperation("根据id查询员工信息")
    public Result getById(@PathVariable Long id){
        Employee employee = employeeService.getById(id);
        return Result.success(employee);
    }

Service层接口

    /**
     * 根据id查询员工
     * @param id
     * @return
     */
    Employee getById(Long id);

Service层实现类

在 EmployeeServiceImpl 中实现 getById 方法:

	/**
     * 根据id查询员工
     *
     * @param id
     * @return
     */
    public Employee getById(Long id) {
        Employee employee = employeeMapper.getById(id);
        employee.setPassword("****");
        return employee;
    }

Mapper层

在 EmployeeMapper 接口中声明 getById 方法:

/**
     * 根据id查询员工信息
     * @param id
     * @return
     */
    @Select("select * from employee where id = #{id}")
    Employee getById(Long id);
4.2.2 修改员工信息功能

Controller层

/**
     * 编辑员工信息
     * @param employeeDTO
     * @return
     */
    @PutMapping
    @ApiOperation("编辑员工信息")
    public Result update(@RequestBody EmployeeDTO employeeDTO){
        log.info("编辑员工信息:{}", employeeDTO);
        employeeService.update(employeeDTO);
        return Result.success();
    }

Service层接口

    /**
     * 编辑员工信息
     * @param employeeDTO
     */
    void update(EmployeeDTO employeeDTO);

Service层实现类

/**
     * 编辑员工信息
     *
     * @param employeeDTO
     */
    public void update(EmployeeDTO employeeDTO) {
        Employee employee = new Employee();
        BeanUtils.copyProperties(employeeDTO, employee);

        employee.setUpdateTime(LocalDateTime.now());
        employee.setUpdateUser(BaseContext.getCurrentId());

        employeeMapper.update(employee);
    }

Mapper层

在实现启用禁用员工账号功能时,已实现employeeMapper.update(employee),在此不需写Mapper层代码。

4.3 功能测试

分别测试根据id查询员工信息和编辑员工信息两个接口

1). 根据id查询员工信息

查询employee表中的数据,以id=4的记录为例

项目实战——苍穹外卖(Day2)_第25张图片

2). 编辑员工信息

修改id=4的员工信息,namezhangsan改为张三丰username张三改为zhangsanfeng

项目实战——苍穹外卖(Day2)_第26张图片

查看employee表数据

前后端联调测试

项目实战——苍穹外卖(Day2)_第27张图片

对员工姓名为杰克的员工数据修改,点击修改,数据已回显

项目实战——苍穹外卖(Day2)_第28张图片

修改后,点击保存 项目实战——苍穹外卖(Day2)_第29张图片

4.4 代码提交

项目实战——苍穹外卖(Day2)_第30张图片

5.导入分类模块功能代码

5.1 需求分析与设计

后台系统中可以管理分类信息,分类包括两种类型,分别是 菜品分类套餐分类

先来分析菜品分类相关功能。

新增菜品分类:当我们在后台系统中添加菜品时需要选择一个菜品分类,在移动端也会按照菜品分类来展示对应的菜品。

菜品分类分页查询:系统中的分类很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。

根据id删除菜品分类:在分类管理列表页面,可以对某个分类进行删除操作。需要注意的是当分类关联了菜品或者套餐时,此分类不允许删除。

修改菜品分类:在分类管理列表页面点击修改按钮,弹出修改窗口,在修改窗口回显分类信息并进行修改,最后点击确定按钮完成修改操作。

启用禁用菜品分类:在分类管理列表页面,可以对某个分类进行启用或者禁用操作。

分类类型查询:当点击分类类型下拉框时,从数据库中查询所有的菜品分类数据进行展示。

分类管理原型:

项目实战——苍穹外卖(Day2)_第31张图片

业务规则:

  • 分类名称必须是唯一的

  • 分类按照类型可以分为菜品分类和套餐分类

  • 新添加的分类状态默认为“禁用”

接口设计

根据上述原型图分析,菜品分类模块共涉及6个接口。

  • 新增分类

  • 分类分页查询

  • 根据id删除分类

  • 修改分类

  • 启用禁用分类

  • 根据类型查询分类

表设计

category表结构:

字段名 数据类型 说明 备注
id bigint 主键 自增
name varchar(32) 分类名称 唯一
type int 分类类型 1菜品分类 2套餐分类
sort int 排序字段 用于分类数据的排序
status int 状态 1启用 0禁用
create_time datetime 创建时间
update_time datetime 最后修改时间
create_user bigint 创建人id
update_user bigint 最后修改人id

5.2 代码导入

项目实战——苍穹外卖(Day2)_第32张图片

可按照mapper-->service-->controller依次导入,这样代码不会显示相应的报错。

5.2.1Mapper层

DishMapper.java

package com.sky.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface DishMapper {

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

}

SetmealMapper.java

package com.sky.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface SetmealMapper {

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

}

CategoryMapper.java  

package com.sky.mapper;

import com.github.pagehelper.Page;
import com.sky.dto.CategoryPageQueryDTO;
import com.sky.entity.Category;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface CategoryMapper {

    /**
     * 插入数据
     * @param category
     */
    @Insert("insert into category(type, name, sort, status, create_time, update_time, create_user, update_user)" +
            " VALUES" +
            " (#{type}, #{name}, #{sort}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
    void insert(Category category);

    /**
     * 分页查询
     * @param categoryPageQueryDTO
     * @return
     */
    Page pageQuery(CategoryPageQueryDTO categoryPageQueryDTO);

    /**
     * 根据id删除分类
     * @param id
     */
    @Delete("delete from category where id = #{id}")
    void deleteById(Long id);

    /**
     * 根据id修改分类
     * @param category
     */
    void update(Category category);

    /**
     * 根据类型查询分类
     * @param type
     * @return
     */
    List list(Integer type);
}

CategoryMapper.xml,进入到resources/mapper目录下





    

    
        update category
        
            
                type = #{type},
            
            
                name = #{name},
            
            
                sort = #{sort},
            
            
                status = #{status},
            
            
                update_time = #{updateTime},
            
            
                update_user = #{updateUser}
            
        
        where id = #{id}
    

    
5.2.2Service层

CategoryService.java

package com.sky.service;

import com.sky.dto.CategoryDTO;
import com.sky.dto.CategoryPageQueryDTO;
import com.sky.entity.Category;
import com.sky.result.PageResult;
import java.util.List;

public interface CategoryService {

    /**
     * 新增分类
     * @param categoryDTO
     */
    void save(CategoryDTO categoryDTO);

    /**
     * 分页查询
     * @param categoryPageQueryDTO
     * @return
     */
    PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO);

    /**
     * 根据id删除分类
     * @param id
     */
    void deleteById(Long id);

    /**
     * 修改分类
     * @param categoryDTO
     */
    void update(CategoryDTO categoryDTO);

    /**
     * 启用、禁用分类
     * @param status
     * @param id
     */
    void startOrStop(Integer status, Long id);

    /**
     * 根据类型查询分类
     * @param type
     * @return
     */
    List list(Integer type);
}

CategoryServiceImpl.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.context.BaseContext;
import com.sky.dto.CategoryDTO;
import com.sky.dto.CategoryPageQueryDTO;
import com.sky.entity.Category;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.mapper.CategoryMapper;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.result.PageResult;
import com.sky.service.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 分类业务层
 */
@Service
@Slf4j
public class CategoryServiceImpl implements CategoryService {

    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private SetmealMapper setmealMapper;

    /**
     * 新增分类
     * @param categoryDTO
     */
    public void save(CategoryDTO categoryDTO) {
        Category category = new Category();
        //属性拷贝
        BeanUtils.copyProperties(categoryDTO, category);

        //分类状态默认为禁用状态0
        category.setStatus(StatusConstant.DISABLE);

        //设置创建时间、修改时间、创建人、修改人
        category.setCreateTime(LocalDateTime.now());
        category.setUpdateTime(LocalDateTime.now());
        category.setCreateUser(BaseContext.getCurrentId());
        category.setUpdateUser(BaseContext.getCurrentId());

        categoryMapper.insert(category);
    }

    /**
     * 分页查询
     * @param categoryPageQueryDTO
     * @return
     */
    public PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO) {
        PageHelper.startPage(categoryPageQueryDTO.getPage(),categoryPageQueryDTO.getPageSize());
        //下一条sql进行分页,自动加入limit关键字分页
        Page page = categoryMapper.pageQuery(categoryPageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());
    }

    /**
     * 根据id删除分类
     * @param id
     */
    public void deleteById(Long id) {
        //查询当前分类是否关联了菜品,如果关联了就抛出业务异常
        Integer count = dishMapper.countByCategoryId(id);
        if(count > 0){
            //当前分类下有菜品,不能删除
            throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_DISH);
        }

        //查询当前分类是否关联了套餐,如果关联了就抛出业务异常
        count = setmealMapper.countByCategoryId(id);
        if(count > 0){
            //当前分类下有菜品,不能删除
            throw new DeletionNotAllowedException(MessageConstant.CATEGORY_BE_RELATED_BY_SETMEAL);
        }

        //删除分类数据
        categoryMapper.deleteById(id);
    }

    /**
     * 修改分类
     * @param categoryDTO
     */
    public void update(CategoryDTO categoryDTO) {
        Category category = new Category();
        BeanUtils.copyProperties(categoryDTO,category);

        //设置修改时间、修改人
        category.setUpdateTime(LocalDateTime.now());
        category.setUpdateUser(BaseContext.getCurrentId());

        categoryMapper.update(category);
    }

    /**
     * 启用、禁用分类
     * @param status
     * @param id
     */
    public void startOrStop(Integer status, Long id) {
        Category category = Category.builder()
                .id(id)
                .status(status)
                .updateTime(LocalDateTime.now())
                .updateUser(BaseContext.getCurrentId())
                .build();
        categoryMapper.update(category);
    }

    /**
     * 根据类型查询分类
     * @param type
     * @return
     */
    public List list(Integer type) {
        return categoryMapper.list(type);
    }
}
5.2.3 Controller层

CategoryController.java

package com.sky.controller.admin;

import com.sky.dto.CategoryDTO;
import com.sky.dto.CategoryPageQueryDTO;
import com.sky.entity.Category;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.CategoryService;
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/category")
@Api(tags = "分类相关接口")
@Slf4j
public class CategoryController {

    @Autowired
    private CategoryService categoryService;

    /**
     * 新增分类
     * @param categoryDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增分类")
    public Result save(@RequestBody CategoryDTO categoryDTO){
        log.info("新增分类:{}", categoryDTO);
        categoryService.save(categoryDTO);
        return Result.success();
    }

    /**
     * 分类分页查询
     * @param categoryPageQueryDTO
     * @return
     */
    @GetMapping("/page")
    @ApiOperation("分类分页查询")
    public Result page(CategoryPageQueryDTO categoryPageQueryDTO){
        log.info("分页查询:{}", categoryPageQueryDTO);
        PageResult pageResult = categoryService.pageQuery(categoryPageQueryDTO);
        return Result.success(pageResult);
    }

    /**
     * 删除分类
     * @param id
     * @return
     */
    @DeleteMapping
    @ApiOperation("删除分类")
    public Result deleteById(Long id){
        log.info("删除分类:{}", id);
        categoryService.deleteById(id);
        return Result.success();
    }

    /**
     * 修改分类
     * @param categoryDTO
     * @return
     */
    @PutMapping
    @ApiOperation("修改分类")
    public Result update(@RequestBody CategoryDTO categoryDTO){
        categoryService.update(categoryDTO);
        return Result.success();
    }

    /**
     * 启用、禁用分类
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("启用禁用分类")
    public Result startOrStop(@PathVariable("status") Integer status, Long id){
        categoryService.startOrStop(status,id);
        return Result.success();
    }

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

全部导入完毕后,进行编译

项目实战——苍穹外卖(Day2)_第33张图片

5.3 功能测试

分页查询:

项目实战——苍穹外卖(Day2)_第34张图片

 分类类型:

项目实战——苍穹外卖(Day2)_第35张图片

 启用禁用:

项目实战——苍穹外卖(Day2)_第36张图片

点击禁用

项目实战——苍穹外卖(Day2)_第37张图片

修改:

回显

项目实战——苍穹外卖(Day2)_第38张图片

修改后

项目实战——苍穹外卖(Day2)_第39张图片

新增:

项目实战——苍穹外卖(Day2)_第40张图片

点击确定,查询列表

项目实战——苍穹外卖(Day2)_第41张图片

删除:

项目实战——苍穹外卖(Day2)_第42张图片

5.4 代码提交

项目实战——苍穹外卖(Day2)_第43张图片

你可能感兴趣的:(苍穹外卖,java,学习,intellij-idea,spring,boot,mybatis,log4j)