1、公共字段自动填充
问题分析
我们已经完成了后台系统的员工管理功能开发,在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工时需要设置修改时间和修改人等字段。这些字段属于公共字段,也就是很多表中都有这些字段。可以使用Mybatis Plus提供的公共字段自动填充功能,对这些公共字段在某个地方统一处理。
代码实现
Mybatis Plus公共字段自动填充,也就是在插入或者更新的时候为指定字段赋予指定的值,使用它的好处就是可以统一对这些字段进行处理,避免了重复代码。
实现步骤:
1、在实体类的属性上加入@TableField注解,指定自动填充的策略
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
2、按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现MetaObjectHandler接口
@Slf4j
@Component
public class MyMateObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("insertFill"+metaObject.toString());
Date date = new Date();
metaObject.setValue("createTime",date);
metaObject.setValue("updateTime",date);
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("updateFill"+metaObject.toString());
metaObject.setValue("updateTime",new Date());
}
}
功能完善
我们可以在LoginCheckFilter的preHandle方法中获取当前登录用户id,并调用ThreadLocal的set方法来设置当前线程的线程局部变量的值(用户id),然后在MyMetaObjectHandler的updateFill方法中调用ThreadLocal的get方法来获得当前线程所对应的线程局部变量的值
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();
}
public static void removeCurrentId(){
threadLocal.remove();
}
}
在登录拦截器的preHandle方法中保存当前id,为了缓解服务器的内存压力,我们可以在postHandle方法中移除当前线程id。
public class LoginCheckInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Long id = (Long) request.getSession().getAttribute("employee");
if(id==null){
response.getWriter().write(JSON.toJSONString(Result.error("NOTLOGIN")));
return false;
}
BaseContext.setCurrentId(id);
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
BaseContext.removeCurrentId();
}
}
完整的MyMateObjectHandler类如下:
@Component
public class MyMateObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
Date date = new Date();
metaObject.setValue("createTime",date);
metaObject.setValue("updateTime",date);
metaObject.setValue("createUser",BaseContext.getCurrentId());
metaObject.setValue("updateUser",BaseContext.getCurrentId());
}
@Override
public void updateFill(MetaObject metaObject) {
metaObject.setValue("updateTime",new Date());
metaObject.setValue("updateUser",BaseContext.getCurrentId());
}
}
2、新增分类
需求分析
后台系统中可以管理分类信息,分类包括两种类型,分别是菜品分类和套餐分类。当我们在后台系统中添加菜品时需要选择一个菜品分类,当我们在后台系统中添加一个套餐时需要选择一个套餐分类,在移动端也会按照菜品分类和套餐分类来展示对应的菜品和套餐。
实体类
@Data
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
private Integer type; //类型 1 菜品分类 2 套餐分类
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;//是否删除
}
代码开发
这里的CategoryMapper,CategoryService,CategoryServiceImpl,CategoryController省略
@PostMapping
public Result<String> add(@RequestBody Category category){
categoryService.save(category);
return Result.success("分类添加成功");
}
3、菜品分页查询
需求分析
前端接口
const getCategoryPage = (params) => {
return $axios({
url: '/category/page',
method: 'get',
params
})
}
代码开发
@GetMapping("/page")
public Result<Page> page(
@RequestParam(value = "page", defaultValue = "1") Integer page,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
log.info("page={},pageSize={}",page,pageSize);
Page<Category> pageInfo = new Page<>(page, pageSize);
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByAsc(Category::getSort);
categoryService.page(pageInfo,queryWrapper);
return Result.success(pageInfo);
}
4、删除分类
需求分析
在分类管理列表页面,可以对某个分类进行删除操作。需要注意的是当分类关联了菜品或者套餐时,此分类不允许删除。
前端接口:
const deleCategory = (ids) => {
return $axios({
url: '/category',
method: 'delete',
params: { id }
})
}
代码开发
由于我们需要查找菜品的分类和套餐的分类,要编写两张表的实体类
Dish实体类:
@Data
public class Dish implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//菜品名称
private String name;
//菜品分类id
private Long categoryId;
//菜品价格
private BigDecimal price;
//商品码
private String code;
//图片
private String image;
//描述信息
private String description;
//0 停售 1 起售
private Integer status;
//顺序
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;
}
Setmeal实体类:
@Data
public class Setmeal implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//分类id
private Long categoryId;
//套餐名称
private String name;
//套餐价格
private BigDecimal price;
//状态 0:停用 1:启用
private Integer status;
//编码
private String code;
//描述信息
private String description;
//图片
private String image;
@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,Service,ServiceImpl省略
@DeleteMapping
public Result<String> deleteCategory(Long id){
categoryService.remove(id);
return Result.success("删除成功");
}
@Override
public void remove(Long id) {
LambdaQueryWrapper<Dish> dishQueryWrapper = new LambdaQueryWrapper<>();
dishQueryWrapper.eq(Dish::getCategoryId,id);//根据分类查找菜品
if (dishService.count(dishQueryWrapper)>0){//判断关联菜品数量
throw new DishException("分类已关联菜品");
}
LambdaQueryWrapper<Setmeal> setmealQueryWrapper = new LambdaQueryWrapper<>();
setmealQueryWrapper.eq(Setmeal::getCategoryId,id);
if(setmealService.count(setmealQueryWrapper)>0){
throw new SetmealException("分类已关联套餐");
}
super.removeById(id);
}
两个自定义异常类:
public class DishException extends RuntimeException {
public DishException(String message){
super(message);
}
}
public class SetmealException extends RuntimeException{
public SetmealException(String message){
super(message);
}
}
并在全局异常处理器中捕获两个异常:
@ExceptionHandler(DishException.class)
public Result<String> exceptionHandler(DishException ex){
log.info("异常信息:{}",ex.getMessage());
return Result.error(ex.getMessage());
}
@ExceptionHandler(SetmealException.class)
public Result<String> exceptionHandler(SetmealException ex){
log.info("异常信息:{}",ex.getMessage());
return Result.error(ex.getMessage());
}
5、修改分类
代码开发
@PutMapping
public Result<String> updateCategory(@RequestBody Category category){
log.info("update category:{}",category);
categoryService.updateById(category);
return Result.success("分类修改成功");
}
标签:TableField,Long,public,瑞吉,FieldFill,private,外卖,id
From: https://www.cnblogs.com/godofball/p/17191691.html