> 文档中心 > 【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)

【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)


注:本文章基于黑马程序员相关视频及资料进行编写,代码简单,较容易理解,若有问题或者源码资料获取可以在评论区留言或者联系作者!

文章目录

  • 一、公共字段自动填充
  • 二、新增分类
  • 三、分类信息分页查询
  • 四、删除分类
  • 四、删除分类完善
  • 五、修改分类

一、公共字段自动填充

(1)问题分析:
前面我们已经完成了后台系统的员工管理功能的开发,在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工时需要设置修改时间和修改人等字段,这些字段属于公共字段,也就是很多表中都有这些字段,这时候我们可以使用mybatis plus提供的公共字段自动填充功能

Mybatis plus的公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值。使用它的好处就是可以统一对这些字段进行处理,避免了重复代码;

(2)实现步骤:

  1. 在实体类的属性上加入TableFiled注解。指定自动填充的策略;
  2. 按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口;

(3)编码实现
加入@Tablefiled注解:

@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;

因为在MyMetaObjectHandler 类中是无法使用HttpServletRequest类,所以是无法从session域汇总获取到用户id的,这里我们先将用户id写死验证功能是否正常运行;

编写元数据处理类继承MetaObjectHandler类并实现指定方法:

public class MyMetaObjectHandler implements MetaObjectHandler {    /*    * 插入操作,自动填充*/    @Override    public void insertFill(MetaObject metaObject) { log.info("公共字段自动填充[insert]"); metaObject.setValue("createTime", LocalDateTime.now()); metaObject.setValue("updateTime", LocalDateTime.now()); metaObject.setValue("createUser", new Long(1)); metaObject.setValue("updateUser", new Long(1)); log.info(metaObject.toString());    }

运行程序,新增用户,可以正常插入公共字段;
【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)

(4)公共字段填充功能完善:
客户端发送的每一次http请求,对应的都会在服务端分配一个新的线程来处理,在处理过程中涉及到下面类中的方法都是属于一个线程的:
1.LoginCheckFilter的doFilter方法
2.EmployeeController的update方法
3.MyMetaObjectHandler的updateFill方法;

ThreadLocal并不是一个Thread。而是Thread的局部变量。当使用ThreaLocal维护变量的时候,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都独立的改变自己副本,而不会影响到其它线程所对应的副本。ThreadLocal为每个线程都提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到相应的值,线程外则不能访问到

实现步骤:

  1. 编写BaseContext工具类,基于ThreadLocal封装的工具类
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();    }}
  1. 在LoginCheckFilter的doFilter方法中调用BaseContext来设置当前登录用户的id
//获取用户登录的id,传给ThreadLocal变量     Long empid = (Long) request.getSession().getAttribute("employee");     BaseContext.setCurrentId(empid);
  1. 在MyMetaObjectHandler的方法中调用BaseContext获取登录用户的id
 metaObject.setValue("createUser", BaseContext.getCurrentId()); metaObject.setValue("updateUser", BaseContext.getCurrentId());
  1. 运行项目,进行新增操作,能够自动进行公共字段的填入;
    【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)

二、新增分类

(1)需求分析:后台系统中可以管理分类信息,分裂包括两种类型,分别是菜品分类和套餐分类。当我们在后台系统中添加菜品时需要一个菜品分类,当我们在后台系统中添加一个套餐的时候需要选择一个套餐分类,在移动端也会按照菜品分类和套餐分类来展示对应的菜品和套餐;

(2)代码开发(大体框架)

  • 实体类Category(这里省略)
  • Mapper接口CategoryMapper
@mapperpublic interface CategoryMapper extends BaseMapper<Category> {}
  • 业务层接口CategoryService
public interface CategroyService extends IService<Category> {}
  • 业务层实现类CategoryServiceImpl
@Servicepublic class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {}
  • 控制层CategoryController
@RestController@RequestMapping("/category")public class CategoryController {    @Autowired    CategoryService categoryService;}

(3)CategoryController具体业务实现:接受前端传来的json数据,然后封装成为一个category对象,使用categoryService进行插入,由于数据库加了name唯一的索引,所以当插入一个已经存在的name值的时候,就会抛出异常,之前定义的全局异常处理器会返回错误信息给前端,后面成功返回代码不再执行;

@PostMapping    public R<String> save(@RequestBody Category category){ log.info("categroy"+category); categoryService.save(category); return R.success("新增分类成功");

(4)运行项目,检查插入功能,当插入重复值时,会提示错误信息,当输入不存在的信息时,能够成功插入;
【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)


三、分类信息分页查询

(1)需求分析:系统中的分类很多的时候,如果在一个页面中全部展示出来会显的比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据;

(2)程序执行流程;

  1. 页面发送ajax请求,将分页查询参数(page,pagesize)提交到服务器
  2. 服务端controller接受页面提交的数据并调用Service查询数据
  3. Service调用Mapper操作数据库,查询分页数据
  4. Controller将查询到的分页数据响应给页面
  5. 页面接受到查询到分页数据展示到页面上

(3)编写分页查询业务逻辑:

@GetMapping("/page")    public R<Page>  page(int page, int pageSize){ //分页构造器 Page<Category> pageInfo=new Page<>(page,pageSize); //条件构造器 LambdaQueryWrapper<Category> queryWrapper=new LambdaQueryWrapper<>(); //添加排序条件 queryWrapper.orderByAsc(Category::getSort); //进行分页的查询 categoryService.page(pageInfo,queryWrapper); return R.success(pageInfo);

(4)运行项目,访问分页查询,能够正常显示数据;
【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)


四、删除分类

(1)需求分析:
在分类管理页面,可以对某个分类进行删除操作,需要注意的是当分类关联了菜品或者套餐的时候,此分类不允许删除;

(2)执行流程:

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

四、删除分类完善

(1)功能完善:
前面我们已经实现了根据id删除分类的功能,但是并没有检查删除的分类是否关联了菜品或者套餐,所以我们需要进行功能完善;

(2)创建大体框架:
由于删除分类时需要判断当前分类下是否含有菜品和套餐,所以我们首先需要引入Dish和Setmeal的大体框架

  1. 实体类Dish和Setmeal
  2. Mapper接口DishMapper和SetmealMapper
  3. Service接口DishService和SetmealService
  4. Service实现类DishServiceImpl和SetmealServiceImpl

(2)在CategoryService中新建删除方法;

public interface CategoryService extends IService<Category> {    public void remove(Long id);}

(3)在CategoryServiceImpl中对方法进行业务逻辑的编写,首先对Setmeal表和Dish表进行查询,看是否含有与分类id相关联的字段,若有则抛出异常,若没有则进行删除操作;

 /*    * 根据id删除分类,删除之前需要进行判断*/    @Override    public void remove(Long id) { LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>(); //添加查询条件,根据分类id进行查询 dishLambdaQueryWrapper.eq(Dish::getCategoryId,id); int count1 = dishService.count(dishLambdaQueryWrapper); //判断当前分类是否关联了菜品,如果已经关联,抛出一个业务异常 if (count1>0){     //已经关联菜品,抛出一个业务异常     throw new CustomException("当前分类下关联了菜品,无法删除"); } //判断当前套餐是否关联了菜品,如果已经关联,抛出一个业务异常 LambdaQueryWrapper<Setmeal> SetmealLambdaQueryWrapper = new LambdaQueryWrapper<>(); SetmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id); int count2 = setmealService.count(SetmealLambdaQueryWrapper); if (count2>0){     //已经关联套餐,抛出一个业务异常     throw new CustomException("当前分类下关联了套餐,不能删除"); } //正常删除分类 super.removeById(id);    }

(4)编写一个异常处理类CustomException,用于处理删除分类操作抛出的异常;

public class CustomException extends RuntimeException {    public CustomException(String message){ super(message);    }}

(5)在GlobalExceptionHandler全局异常处理器上加入CustomException,并编写异常接受后的操作;

 @ExceptionHandler(CustomException.class)//处理此种异常方法    public R<String> exceptionHandler(CustomException ex){ log.info(ex.getMessage()); return R.error(ex.getMessage());    }

(6)运行项目,当删除含有菜品或者套餐的分类时,页面会反馈错误信息;
【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)

五、修改分类

修改分类功能较为简单,前端将修改后的分类的数据传给后端,后端通过数据库更新,修改数据;
【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)

   @PutMapping    public R<String> update( @RequestBody Category category){ log.info("修改分类信息:{}",category); categoryService.updateById(category); return R.success("修改分类信息成功");    }

【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)
【从零开始分析项目实战】09-分类管理业务开发(Mybatisplus公共字段自动填充功能的实现)


如果感觉内容写的还不错的话,一键三连不迷路!!!!
后面将会更新更多学习内容,一起学习吧!!!!!!
在这里插入图片描述