boot实战-分类管理

这篇博客介绍了如何使用MyBatis Plus的公共字段自动填充功能,减少了代码重复。同时展示了分类管理功能的实现,包括分类的增删改查操作,并在删除分类时进行了业务校验,确保没有关联数据。此外,还引入了ThreadLocal来处理跨层传递的用户ID。
摘要由CSDN通过智能技术生成

分类管理功能

在移动端显示不同分类,用户可以点击查看不同菜品

image-20220520192253638

公共字段自动填充(MP技术)

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

image-20220520192807619

在上面我们封装数据时候都手动设置了

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给我们提供了公共字段自动填充的技术

image-20220520193518927

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

image-20220520201008643

image-20220520201124216

什么是ThreadLocal?

image-20220520204208301

我们在过滤器中的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

image-20220520210023241

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

image-20220520210104184

新增分类

需求分析

image-20220520211721814

功能框架搭建

就是完成功能对应的实体类,mapper,service,业务层实现类以及控制层controller

首先看数据库

image-20220520212622724

/**
 * 分类实体类
 */
@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;
}

代码开发

首先去看前端发送的功能请求

image-20220520214113142

image-20220520214123418

image-20220520214413565

分类信息分页查询

这个和之前的分页查询是类似的

首先查看请求

image-20220520220317167

/**
 * 分页查询
 * @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);

}

删除分类

需求分析

image-20220520221932669

代码实现

image-20220520222135410

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

}

功能完善

image-20220520224819584

image-20220520230334306

因为我们要使用自己的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);
    }

}

在全局异常管理类中管理该异常

image-20220520233951344

再到service实现类中补全抛出自定义业务异常

//            已关联抛出业务异常
            throw new CustomException("当前分类关联了套餐,不能删除!");

最后完成controller层方法的调用

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

测试成功

image-20220520234441979

修改分类

需求分析

和之前的员工编辑一摸一样几乎

image-20220520234731064

代码实现

image-20220520235123847

/**
 * 根据id修改分类信息
 * @param category
 * @return
 */
@PutMapping
public R<String> update(@RequestBody Category category){

    categoryService.updateById(category);
    
    return R.success("修改成功");
}

测试

image-20220520235841270

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值