自定义业务异常处理类并将其加入全局异常处理器,从而避免业务层直接处理异常造成代码污染,达到业务清晰简洁。
在进行分类模块开发时,删除某个分类时当分类关联了菜品和套餐时,是不允许删除的。我们在管理端删除的时候会提示异常,我们使用自定义业务异常处理类并将其加入全局异常处理器,从而避免业务层直接处理异常造成代码污染,达到业务清晰简洁。
删除分类需要注意的是当分类关联了菜品和套餐时,不允许删除。
请求:
如果忘了加注解@JsonFormat注解,会发生js获取主键时丢失精度,js只能读17位,而雪花算法Long类型是19位。
@JsonFormat(shape = JsonFormat.Shape.STRING)
代码:
@DeleteMapping
public R page(Long ids){
boolean success = categoryService.removeById(ids);
if(success)return R.success("删除成功");
else return R.error("删除失败");
}
套餐:
/**
* 套餐
*/
@Data
public class Setmeal implements Serializable {
private static final long serialVersionUID = 1L;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
//分类id
@JsonFormat(shape = JsonFormat.Shape.STRING)
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)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long updateUser;
}
菜品:
/**
菜品
*/
@Data
public class Dish implements Serializable {
private static final long serialVersionUID = 1L;
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long id;
//菜品名称
private String name;
//菜品分类id
@JsonFormat(shape = JsonFormat.Shape.STRING)
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)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
@JsonFormat(shape = JsonFormat.Shape.STRING)
private Long updateUser;
}
建议自己写,很快,复制粘贴总会把实体类之类的写错。
@Mapper
public interface DishMapper extends BaseMapper {
}
@Mapper
public interface SetmealMapper extends BaseMapper {
}
public interface DishService extends IService {
}
public interface SetmealService extends IService {
}
@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl implements DishService {
}
@Service
@Slf4j
public class SetmealServiceImpl extends ServiceImpl implements SetmealService {
}
目标:当分类关联了菜品和套餐时,不允许删除。
跟进到IService的remove方法,通过比较器wrapper删除,参数改成Integer的话算重载,可以改:
代码实现:
我前面自己写的时候,没有用异常捕获,是在业务层根据不同情况返回不同数字,然后controller根据数字R.error("错误原因") 。用异常捕获也能实现,两种效果都一样,用异常捕获更规范。
service:
@Override
public Integer remove(Long id){
LambdaQueryWrapper wrapper1=new LambdaQueryWrapper<>();
wrapper1.eq(Setmeal::getCategoryId,id);
LambdaQueryWrapper wrapper2=new LambdaQueryWrapper<>();
wrapper2.eq(Dish::getCategoryId,id);
log.info("套餐查询:{}",setmealService.getMap(wrapper1));log.info("菜品查询:{}",dishService.getMap(wrapper2));
//查到有菜品或套餐使用这个分类
if(setmealService.count(wrapper1)>0) return -1;
if(dishService.count(wrapper2)>0) return -2;
return categoryDao.deleteById(id)>0?1:0;
}
@DeleteMapping
public R remove(Long ids){
log.info("要删除的id:{}",ids);
int success = -3;success=categoryService.remove(ids);
log.info("删除状态:{}",success);
if(success==1)return R.success("删除成功");
else if(success==0) return R.error("网络原因删除失败");
else if(success==-1) return R.error("有套餐正在使用此分类");
else if(success==-2)return R.error("有菜品正在使用此分类");
else return R.error("未知错误");
}
异常捕获方案:
service
@Service
public class CategoryServiceImpl extends ServiceImpl implements CategoryService{
@Autowired
private DishService dishService;
@Autowired
private SetmealService setmealService;
/**
* 根据id删除分类,删除之前需要进行判断
* @param id
*/
@Override
public void remove(Long id) {
LambdaQueryWrapper dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
//添加查询条件,根据分类id进行查询
dishLambdaQueryWrapper.eq(Dish::getCategoryId,id);
int count1 = dishService.count(dishLambdaQueryWrapper);
//查询当前分类是否关联了菜品,如果已经关联,抛出一个业务异常
if(count1 > 0){
//已经关联菜品,抛出一个业务异常
throw new CustomException("当前分类下关联了菜品,不能删除");
}
//查询当前分类是否关联了套餐,如果已经关联,抛出一个业务异常
LambdaQueryWrapper setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
//添加查询条件,根据分类id进行查询
setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id);
int count2 = setmealService.count();
if(count2 > 0){
//已经关联套餐,抛出一个业务异常
throw new CustomException("当前分类下关联了套餐,不能删除");
}
//正常删除分类
super.removeById(id);
}
}
controller
@DeleteMapping
public R delete(Long id){
log.info("删除分类,id为:{}",id);
//categoryService.removeById(id);
if(categoryService.remove(ids)) return R.success("删除成功");
//这里也可以throw业务异常,但不建议,一般都是service抛出异常,controller返回R.error();
else return R.error("删除失败");
}
业务异常类:
/**
* 自定义业务异常类
*/
public class CustomException extends RuntimeException {
//带参构造方法,重新设置异常信息
public CustomException(String message){
super(message);
}
}
全局异常处理:
@RestControllerAdvice
//@ControllerAdvice(annotations = {RestController.class, Controller.class})
//@ResponseBody
@Slf4j
public class GlobalExceptionHandler {
/**
* 异常处理方法
* @return
*/
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public R exceptionHandler(SQLIntegrityConstraintViolationException ex){
log.error(ex.getMessage());
if(ex.getMessage().contains("Duplicate entry")){
String[] split = ex.getMessage().split(" ");
String msg = split[2] + "已存在";
return R.error(msg);
}
return R.error("未知错误");
}
/**
* 异常处理方法
* @return
*/
@ExceptionHandler(CustomException.class)
public R exceptionHandler(CustomException ex){
log.error(ex.getMessage());
return R.error(ex.getMessage());
}
}