注:本文章基于黑马程序员相关视频及资料进行编写,代码简单,较容易理解,若有问题或者源码资料获取可以在评论区留言或者联系作者!
一、公共字段自动填充
(1)问题分析:
前面我们已经完成了后台系统的员工管理功能的开发,在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工时需要设置修改时间和修改人等字段,这些字段属于公共字段,也就是很多表中都有这些字段,这时候我们可以使用mybatis plus提供的公共字段自动填充功能
;
Mybatis plus的公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值。使用它的好处就是可以统一对这些字段进行处理,避免了重复代码;
(2)实现步骤:
- 在实体类的属性上加入TableFiled注解。指定自动填充的策略;
- 按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现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());
}
运行程序,新增用户,可以正常插入公共字段;
(4)公共字段填充功能完善:
客户端发送的每一次http请求,对应的都会在服务端分配一个新的线程来处理,在处理过程中涉及到下面类中的方法都是属于一个线程的:
1.LoginCheckFilter的doFilter方法
2.EmployeeController的update方法
3.MyMetaObjectHandler的updateFill方法;
ThreadLocal并不是一个Thread。而是Thread的局部变量。当使用ThreaLocal维护变量的时候,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都独立的改变自己副本,而不会影响到其它线程所对应的副本。ThreadLocal为每个线程都提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到相应的值,线程外则不能访问到
;
实现步骤:
- 编写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();
}
}
- 在LoginCheckFilter的doFilter方法中调用BaseContext来设置当前登录用户的id
//获取用户登录的id,传给ThreadLocal变量
Long empid = (Long) request.getSession().getAttribute("employee");
BaseContext.setCurrentId(empid);
- 在MyMetaObjectHandler的方法中调用BaseContext获取登录用户的id
metaObject.setValue("createUser", BaseContext.getCurrentId());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
- 运行项目,进行新增操作,能够自动进行公共字段的填入;
二、新增分类
(1)需求分析:后台系统中可以管理分类信息,分裂包括两种类型,分别是菜品分类和套餐分类。当我们在后台系统中添加菜品时需要一个菜品分类,当我们在后台系统中添加一个套餐的时候需要选择一个套餐分类,在移动端也会按照菜品分类和套餐分类来展示对应的菜品和套餐;
(2)代码开发(大体框架)
- 实体类Category(这里省略)
- Mapper接口CategoryMapper
@mapper
public interface CategoryMapper extends BaseMapper<Category> {
}
- 业务层接口CategoryService
public interface CategroyService extends IService<Category> {
}
- 业务层实现类CategoryServiceImpl
@Service
public 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)运行项目,检查插入功能,当插入重复值时,会提示错误信息,当输入不存在的信息时,能够成功插入;
三、分类信息分页查询
(1)需求分析:系统中的分类很多的时候,如果在一个页面中全部展示出来会显的比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据;
(2)程序执行流程;
- 页面发送ajax请求,将分页查询参数(page,pagesize)提交到服务器
- 服务端controller接受页面提交的数据并调用Service查询数据
- Service调用Mapper操作数据库,查询分页数据
- Controller将查询到的分页数据响应给页面
- 页面接受到查询到分页数据展示到页面上
(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)运行项目,访问分页查询,能够正常显示数据;
四、删除分类
(1)需求分析:
在分类管理页面,可以对某个分类进行删除操作,需要注意的是当分类关联了菜品或者套餐的时候,此分类不允许删除;
(2)执行流程:
- 页面发送Ajax请求,将参数id提交到服务端
- 服务端Controller接受页面提交的数据调用Service删除数据
- Service调用Mapper操作数据库
编码实现:
@DeleteMapping
public R<String> delete(Long ids){
categoryService.removeById(ids);
return R.success("分类信息删除成功");
}
四、删除分类完善
(1)功能完善:
前面我们已经实现了根据id删除分类的功能,但是并没有检查删除的分类是否关联了菜品或者套餐,所以我们需要进行功能完善;
(2)创建大体框架:
由于删除分类时需要判断当前分类下是否含有菜品和套餐,所以我们首先需要引入Dish和Setmeal的大体框架
- 实体类Dish和Setmeal
- Mapper接口DishMapper和SetmealMapper
- Service接口DishService和SetmealService
- 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)运行项目,当删除含有菜品或者套餐的分类时,页面会反馈错误信息;
五、修改分类
修改分类功能较为简单,前端将修改后的分类的数据传给后端,后端通过数据库更新,修改数据;
@PutMapping
public R<String> update( @RequestBody Category category){
log.info("修改分类信息:{}",category);
categoryService.updateById(category);
return R.success("修改分类信息成功");
}
如果感觉内容写的还不错的话,一键三连不迷路!!!!
后面将会更新更多学习内容,一起学习吧!!!!!!