1.公共字段自动填充

1.1 问题分析

在前面完成的员工管理功能开发,在新增员工或编辑员工时设置创建时间、创建人、更新时间和更新人。这些字段属于公共字段,也就是很多表中都有这些字段。

可以使用MybatisPlus提供的公共字段自动填充功能来统一处理。

1.2 代码实现

Mybatis Plus公共字段自动填充,也就是在插入或者更新时为指定的字段赋予指定的值。

实现步骤:

  1. 在实体类的属性上加入@TableField注解,指定自动填充的策略。
  2. 按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类实现MetaObjectHandler接口。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {

@Override
public void insertFill(MetaObject metaObject) {

metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime",LocalDateTime.now());
metaObject.setValue("createUser",BaseContext.getCurrentId());
metaObject.setValue("updateUser",BaseContext.getCurrentId());

}

@Override
public void updateFill(MetaObject metaObject) {

metaObject.setValue("updateTime",LocalDateTime.now());
metaObject.setValue("updateUser",BaseContext.getCurrentId());

long id = Thread.currentThread().getId();
log.info("线程id:{}",id);
}
}

1.3 功能完善

因为MetaObjectHandler类中无法获取HttpSession对象,所以无法通过session来获取登录用户id。

需要使用ThreadLocal来解决此问题。(它是JDK提供的一个类)

  • 客户端发送的每次http请求,对应的服务端都会分配一个新线程来处理,在此处理过程中涉及到下面类中的方法都属于相同一个线程。
    1. LoginCheckFilter的doFilter方法
    2. EmployeeController的更新方法
    3. MyMetaObjectHandler的updateFill方法

实现步骤:

  1. 编写BaseContext工具类,基于ThreadLocal封装的工具类。
  2. 在LoginCheckFilter的doFilter方法中调用BaseContext来设置当前登录用户的id
  3. 在MyMetaObjectHandler的方法中调用BaseContext获取登录用户的id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
*基于ThreadLocal封装工具类,用户保存和获取当前登录用户的id
*/
public class BaseContext {

private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

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

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

2.新增分类

2.1 需求分析

后台系统中可以管理分类信息,分别是菜品分类和套餐分类。

添加菜品时需要选择一个菜品分类,添加套餐时需要选择要一个套餐分类。

2.2 代码开发

  • 需要用到的类和接口
    • 实体类Category
    • Mapper接口CategoryMapper
    • 业务层接口CategoryService
    • 业务层实现类CategoryServiceImpl
    • 控制层CategoryController
  • 执行过程
    • 页面发送ajax请求,将新增分类窗口输入的数据以json形式提交到服务端。
    • 服务端Controller接收页面提交的数据并调用Service将数据进行保存。
    • Service调用Mapper操作数据库,保存数据。
1
2
3
4
5
@PostMapping
public R<String> save(@RequestBody Category category) {
categoryService.save(category);
return R.success("新增分类成功");
}

3.查询分类

3.1 需求分析

以分页的方式展示数据,根据type来排序。

3.2 代码开发

执行过程:

  1. 页面发送ajax请求,将分页的参数(page,pageSize)提交到服务端。
  2. 服务端Controller接收数据调用处理。
  3. 页面接收分页数据并展示到页面上。
1
2
3
4
@GetMapping("/page")
public R<Page> page(int page,int pageSize){
return R.success(categoryService.CategoryPage(page,pageSize));
}
1
2
3
4
5
6
7
8
9
@Override
public Page CategoryPage(int page, int pageSize) {

Page<Category> pageInfo = new Page<>(page,pageSize);
LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
wrapper.orderByAsc(Category::getSort);
page(pageInfo,wrapper);
return pageInfo;
}

4.删除分类

4.1 需求分析

在分类管理列表页面,可以对某个分类进行删除操作。

当分类关联了菜品或套餐时,此分类不允许删除。

4.2 代码开发

执行过程:

  1. 页面发送ajax请求,将参数(id)提交到服务端。
  2. 服务端Controller接受页面提交的数据并调用Service删除数据
  3. Service调用Mapper操作数据库
1
2
3
4
5
@DeleteMapping
public R<String> delete(Long id){
categoryService.removeById(id);
return R.success("分类信息删除成功");
}

4.3 功能完善

如果检查到删除的分类关联到菜品或套餐,则无法删除。

  • 完善基础类和接口

    • 实体类Dish和Setmeal
    • Mapper接口
    • Service接口
    • Service接口实现类
  • 执行过程

    • 根据id查询Dish和Setmeal表中categoryId是否有记录。
    • 如果没有,则抛出异常。
    • 新建特定的异常捕获,并作出相应的处理。
    1
    2
    3
    4
    5
    @DeleteMapping
    public R<String> delete(Long ids){
    categoryService.remove(ids);
    return R.success("分类信息删除成功");
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Override
    public void remove(Long id) {
    LambdaQueryWrapper<Dish> dishWrapper = new LambdaQueryWrapper<>();
    dishWrapper.eq(Dish::getCategoryId,id);
    int count1 = dishService.count(dishWrapper);
    //查询当前分类是否关联菜品
    if(count1 > 0){
    throw new CustomException("当前分类关联了菜品,不能删除");
    }
    //查询当前分类是否关联套餐
    LambdaQueryWrapper<Setmeal> setmealWrapper = new LambdaQueryWrapper<>();
    setmealWrapper.eq(Setmeal::getCategoryId,id);
    int count2 = setmealService.count(setmealWrapper);
    if(count2 > 0){
    throw new CustomException("当前分类关联了套餐,不能删除");
    }
    super.removeById(id);
    }
    1
    2
    3
    4
    5
    6
    public class CustomException extends RuntimeException{

    public CustomException(String message) {
    super(message);
    }
    }
    1
    2
    3
    4
    @ExceptionHandler(CustomException.class)
    public R<String> exceptionHander(CustomException ex) {
    return R.error(ex.getMessage());
    }

5.修改分类

5.1 需求分析

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

5.2 代码开发

1
2
3
4
5
@PutMapping
public R<String> update(@RequestBody Category category){
categoryService.updateById(category);
return R.success("修改分类信息成功");
}