01、公共字段自动填充
1、需求分析
创建时间、创建人、修改时间、修改人等字段,在处理业务时几乎都会使用。因此这些字段属于公共字段,而且很多表中都有这些字段,我们想要对这些字段进行统一处理
我们可以使用Mybatis Plus
提供的公共字段自动填充
功能
2、代码实现
1、在实体类的属性上接入@TableField
注解,指定自动填充的策略
@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、编写
BaseContext
工具类,基于ThreadLocal
封装的工具类目录:
common
package cn.mu00.reggie.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();
}
}
3、在LoginCheckFilter
的doFilter
方法中调用BaseContext
来设置当前登录用户的id
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
...
// 4、判断登陆状态,如果已登录,则直接放行
if (request.getSession().getAttribute("employee") != null){
// 调用BaseContext来设置当前登录用户的id
Long empId = (Long) request.getSession().getAttribute("employee");
BaseContext.setCurrentId(empId);
log.info("用户已登录,用户id为:{}", empId);
filterChain.doFilter(request, response);
return;
}
...
}
4、按照框架要求编写元数据对象处理器,在此类中统一为公共字段赋值,此类需要实现
MetaObjectHandler
接口目录:
common
在
MyMetaObjectHandler
的方法中调用BaseContext
获取登录用户的id
package cn.mu00.reggie.common;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* 自定义元数据对象处理器
*/
@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("createUser", BaseContext.getCurrentId());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
/**
* 更新操作,自动填充
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
log.info("公共字段自动填充【update】...");
log.info(metaObject.toString());
metaObject.setValue("updateTime", LocalDateTime.now());
metaObject.setValue("updateUser", BaseContext.getCurrentId());
}
}
5、删除EmployeeController
中关于创建时间、创建人、修改时间、修改人等字段
的设置,以及部分请求方法中没有使用的request
参数
02、新增分类
1、需求分析
- 请求地址:
http://localhost:8080/category
- 请求类型:
POST
- 请求参数:
name
、sort
、type
- 注:
type
:1-菜品分类、2-套餐分类
2、代码实现
01.Category实体类
package cn.mu00.reggie.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 分类
*/
@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;
}
02.CategoryMapper
package cn.mu00.reggie.mapper;
import cn.mu00.reggie.entity.Category;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CategoryMapper extends BaseMapper<Category> {
}
03.CategoryService
package cn.mu00.reggie.service;
import cn.mu00.reggie.entity.Category;
import com.baomidou.mybatisplus.extension.service.IService;
public interface CategoryService extends IService<Category> {
}
04.CategoryServiceImpl
package cn.mu00.reggie.service.impl;
import cn.mu00.reggie.entity.Category;
import cn.mu00.reggie.mapper.CategoryMapper;
import cn.mu00.reggie.service.CategoryService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService{
}
05.CategoryController
package cn.mu00.reggie.controller;
import cn.mu00.reggie.service.CategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 分类管理
*/
@Slf4j
@RestController
@RequestMapping("/category")
public class CategoryController {
@Autowired
private CategoryService categoryService;
}
06.新增分类方法
位置:CategoryController
/**
* 新增分类
* @param category
* @return
*/
@PostMapping
public R<String> save(@RequestBody Category category){
log.info("category: {}", category.toString());
categoryService.save(category);
return R.success("新增分类成功");
}
03、分类信息分页查询
1、需求分析
- 请求地址:
http://localhost:8080/category/page?page=页码&pageSize=每页数量
- 请求类型:
GET
- 请求参数:
page
、pageSize
- 注:
page
默认:1,pageSize
默认:10
2、代码实现
位置:CategoryController
/**
* 分类信息分页查询
* @param page
* @param pageSize
* @return
*/
@GetMapping("/page")
public R<Page<Category>> page(int page, int pageSize){
// 分页构造器
Page<Category> pageInfo = new Page<>(page, pageSize);
// 条件构造器
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
// 添加排序条件,根据sort进行排序
queryWrapper.orderByAsc(Category::getSort);
// 进行分页查询
categoryService.page(pageInfo, queryWrapper);
return R.success(pageInfo);
}
04、删除分类
1、需求分析
- 请求地址:
http://localhost:8080/category?id=分类id
- 请求类型:
DELETE
- 注:当分类关联了菜品或套餐时,不允许删除
2、代码实现
位置:CategoryController
/**
* 根据id删除分类
* @param id
* @return
*/
@DeleteMapping
public R<String> delete(Long id){
log.info("删除分类,id为:{}", id);
categoryService.removeById(id);
return R.success("分类信息删除成功");
}
3、功能完善
我们虽然实现了根据id删除分类的功能,但是并没有检查删除的分类是否关联了菜品或者套餐,所以我们需要进行功能完善
准备
01.Dish实体类
package cn.mu00.reggie.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
菜品
*/
@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;
}
02.DishMapper
package cn.mu00.reggie.mapper;
import cn.mu00.reggie.entity.Dish;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DishMapper extends BaseMapper<Dish> {
}
03.DishService
package cn.mu00.reggie.service;
import cn.mu00.reggie.entity.Dish;
import com.baomidou.mybatisplus.extension.service.IService;
public interface DishService extends IService<Dish> {
}
04.DishServiceImpl
package cn.mu00.reggie.service.impl;
import cn.mu00.reggie.entity.Dish;
import cn.mu00.reggie.mapper.DishMapper;
import cn.mu00.reggie.service.DishService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
}
05.Setmeal实体类
package cn.mu00.reggie.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 套餐
*/
@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;
}
06.SetmealMapper
package cn.mu00.reggie.mapper;
import cn.mu00.reggie.entity.Setmeal;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SetmealMapper extends BaseMapper<Setmeal> {
}
07.SetmealService
package cn.mu00.reggie.service;
import cn.mu00.reggie.entity.Setmeal;
import com.baomidou.mybatisplus.extension.service.IService;
public interface SetmealService extends IService<Setmeal> {
}
08.SetmealServiceImpl
package cn.mu00.reggie.service.impl;
import cn.mu00.reggie.entity.Setmeal;
import cn.mu00.reggie.mapper.SetmealMapper;
import cn.mu00.reggie.service.SetmealService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class SetmealServiceImpl extends ServiceImpl<SetmealMapper, Setmeal> implements SetmealService {
}
09.代码实现
1、改造
delete
方法位置:
CategoryController
/**
* 根据id删除分类
* @param id
* @return
*/
@DeleteMapping
public R<String> delete(Long id){
log.info("删除分类,id为:{}", id);
categoryService.remove(id);
return R.success("分类信息删除成功");
}
2、添加
remove
方法位置:
CategoryService
public void remove(Long id);
3、实现
remove
方法位置:
CategoryServiceImpl
/**
*根据id删除分类,删除之前需要进行判断
* @param id
*/
@Override
public void remove(Long id) {
LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
// 添加查询条件,根据分类id
dishLambdaQueryWrapper.eq(Dish::getCategoryId, id);
int dishCount = dishService.count(dishLambdaQueryWrapper);
// 查询当前分类是否关联菜品,如果已经关联,抛出一个业务异常
if (dishCount > 0){
// 已经关联菜品,抛出一个业务异常
throw new CustomException("当前分类下关联了菜品,不能删除");
}
// 查询当前分类是否关联套餐,如果已经关联,抛出一个业务异常
LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
// 添加查询条件,根据分类id
setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId, id);
int setmealCount = setmealService.count(setmealLambdaQueryWrapper);
if (setmealCount > 0){
// 已经关联套餐,抛出一个业务异常
throw new CustomException("当前分类下关联了套餐,不能删除");
}
// 正常删除分类
super.removeById(id);
}
4、创建业务异常
CustomException
目录:
common
package cn.mu00.reggie.common;
/**
* 自定义业务异常
*/
public class CustomException extends RuntimeException{
public CustomException(String message){
super(message);
}
}
5、在全局异常处理器GlobalExceptionHandler
中,捕获异常CustomException
/**
* 业务异常处理方法
* @return
*/
@ExceptionHandler(CustomException.class)
public R<String> exceptionHandler(CustomException ex){
log.error(ex.getMessage());
return R.error(ex.getMessage());
}
05、修改分类
1、需求分析
- 请求地址:
http://localhost:8080/category
- 请求类型:
PUT
- 请求参数:
id
、name
、sort
2、代码实现
位置:CategoryController
/**
* 根据id修改分类信息
* @param category
* @return
*/
@PutMapping
public R<String> update(@RequestBody Category category){
log.info("修改分类信息:{}", category.toString());
categoryService.updateById(category);
return R.success("分类信息修改成功");
}