boot实战-分类管理
分类管理功能
在移动端显示不同分类,用户可以点击查看不同菜品

公共字段自动填充(MP技术)
在上面已经实现的功能我们可以发现个问题,在前端给的数据里不能全部包含数据库中所有的列,造成其为空值,这就需要我们去手动给其赋值

在上面我们封装数据时候都手动设置了
employee.setUpdateTime(LocalDateTime.now());
employee.setUpdateUser(empId);
-------------
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
// 获得当前登录用户的id
Long empId =(Long) request.getSession().getAttribute("employee");
employee.setCreateUser(empId);
employee.setUpdateUser(empId);
任何添加修改的操作都会有这些字段要产生,这个称为公共字段,为了减少我们的代码量,MP给我们提供了公共字段自动填充的技术

1.在实体类中添加属性和填充策略
private Integer status;
@TableField(fill = FieldFill.INSERT)//新增的时候插入
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)//新增和更新的时候
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
2.编写数据对象处理器(实现接口)
/*
* 自定义算数据对象处理器
* */
@Component
@Slf4j
public class MyMetaObjecthandler implements MetaObjectHandler {
/**
* 插入操作,自动填充
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("公共字段自动填充[insert]....");
log.info(metaObject.toString());
metaObject.setValue("createTime", LocalDateTime.now());
metaObject.setValue("updateTime",LocalDateTime.now());
metaObject.setValue("creatUser",new Long(1));
metaObject.setValue("updateUser",new Long(1));
}
/**
* 更新操作自动填充
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
log.info("公共字段自动填充[update]....");
log.info(metaObject.toString());
metaObject.setValue("updateTime",LocalDateTime.now());
metaObject.setValue("updateUser",new Long(1));
}
}
那这里有一个问题就是这个类中我们无法获取session对象,那我们注释掉的
// Long empId = (Long)request.getSession().getAttribute("employee");
这个代码用什么替代呢
ThreadLocal


什么是ThreadLocal?

我们在过滤器中的dofilter方法中获取登录用户id值,并将其set为当前线程的局部变量的值,随后就可以在数据对象处理器中用get方法获取
实现步骤如下
1.编写BaseContext工具类,基于ThreadLocal封装的工具类
package com.ember.common;
/*
* 基于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.在过滤器中的doFilter方法调用BaseContext的set方法存入当前登录用户id

3.在数据对象处理器中调用BaseContext的get方法

新增分类
需求分析

功能框架搭建
就是完成功能对应的实体类,mapper,service,业务层实现类以及控制层controller
首先看数据库

/**
* 分类实体类
*/
@Data
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//类型 1 菜品分类 2 套餐分类
private Integer type;
//分类名称
private String name;
//顺序
private Integer sort;
//创建时间
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
//创建人
@TableField(fill = FieldFill.INSERT)
private Long createUser;
//修改人
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
//mapper层
@Mapper
public interface CategoryMapper extends BaseMapper<Category> {
}
//service
public interface CategoryService extends IService<Category> {
}
//service实现类
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
}
//控制层
/*
* 分类管理
* */
@Slf4j
@RestController
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
}
代码开发
首先去看前端发送的功能请求



分类信息分页查询
这个和之前的分页查询是类似的
首先查看请求

/**
* 分页查询
* @param page
* @param pageSize
* @return
*/
@GetMapping("/page")
public R<Page> page(int page,int pageSize){
Page<Category> pageInfo=new Page<>(page,pageSize);
//构建条件构造器(进行排序)
LambdaQueryWrapper<Category> queryWrapper=new LambdaQueryWrapper<>();
//添加排序条件,根据sort字段进行升序排序
queryWrapper.orderByAsc(Category::getSort);
//调用service进行查询
categoryService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
}
删除分类
需求分析

代码实现

/**
* 根据id删除分类
* @param id
* @return
*/
@DeleteMapping()
public R<String> deleteById(Long id){
categoryService.removeById(id);
return R.success("删除成功");
}
功能完善


因为我们要使用自己的remove方法(添加了删除前检验功能),所以需要在service层定义抽象方法,再到具体实现类中完成方法逻辑(以下只是逻辑,自定义异常还没完成)
public interface CategoryService extends IService<Category> {
public void remove(Long id);
}
----------------------------
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
@Autowired
private DishService dishService;
@Autowired
private SetmealService setmealService;
/**
* 根据id删除分类,删除前需要进行判断
* @param id
*/
@Override
public void remove(Long id) {
LambdaQueryWrapper<Dish> dishLambdaQueryWrapper=new LambdaQueryWrapper<>();
//添加查询条件,根据分类id进行查询
dishLambdaQueryWrapper.eq(Dish::getCategoryId,id);
int count=dishService.count(dishLambdaQueryWrapper);
// 查询当前分类是否关联了菜品,如果已经关联,抛出业务异常
if(count>0){
// 已关联抛出业务异常
throw
}
// 查询当前分类是否关联了套餐,如果已经关联,抛出业务异常
LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper=new LambdaQueryWrapper<>();
setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id);
int count2=setmealService.count(setmealLambdaQueryWrapper);
if(count2>0){
// 已关联抛出业务异常
throw
}
// 正常删除
super.removeById(id);
}
}
自定义业务异常
在全局包下定义异常类
/*
* 自定义业务异常
* */
public class CustomException extends RuntimeException{
public CustomException(String message){
super(message);
}
}
在全局异常管理类中管理该异常

再到service实现类中补全抛出自定义业务异常
// 已关联抛出业务异常
throw new CustomException("当前分类关联了套餐,不能删除!");
最后完成controller层方法的调用
/**
* 根据id删除分类
* @param id
* @return
*/
@DeleteMapping()
public R<String> deleteById(Long id){
categoryService.remove(id);
return R.success("删除成功");
}
测试成功

修改分类
需求分析
和之前的员工编辑一摸一样几乎

代码实现

/**
* 根据id修改分类信息
* @param category
* @return
*/
@PutMapping
public R<String> update(@RequestBody Category category){
categoryService.updateById(category);
return R.success("修改成功");
}
测试


浙公网安备 33010602011771号