自定义业务异常处理类加入全局处理器中

news2025/1/11 0:35:30

自定义业务异常处理类并将其加入全局异常处理器,从而避免业务层直接处理异常造成代码污染,达到业务清晰简洁。

 描述

在进行分类模块开发时,删除某个分类时当分类关联了菜品和套餐时,是不允许删除的。我们在管理端删除的时候会提示异常,我们使用自定义业务异常处理类并将其加入全局异常处理器,从而避免业务层直接处理异常造成代码污染,达到业务清晰简洁。

删除分类

删除分类需要注意的是当分类关联了菜品和套餐时,不允许删除。

1 基础删除,不检查关联的菜品

请求:

  • 如果忘了加注解@JsonFormat注解,会发生js获取主键时丢失精度,js只能读17位,而雪花算法Long类型是19位。

  • @JsonFormat(shape = JsonFormat.Shape.STRING)
    

代码:

    @DeleteMapping
    public R<String> page(Long ids){
        boolean success = categoryService.removeById(ids);
        if(success)return R.success("删除成功");
        else return R.error("删除失败");
    }


2 菜品和套餐的实体类,别忘了@JsonFormat

套餐:

/**
 * 套餐
 */
@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;
 
}

3 菜品和套餐的dao和service

建议自己写,很快,复制粘贴总会把实体类之类的写错。

@Mapper
public interface DishMapper extends BaseMapper<Dish> {
}
@Mapper
public interface SetmealMapper extends BaseMapper<Setmeal> {
}
public interface DishService extends IService<Dish> {
}
public interface SetmealService extends IService<Setmeal> {
}
@Service
@Slf4j
public class DishServiceImpl extends ServiceImpl<DishMapper,Dish> implements DishService {
}
 
@Service
@Slf4j
public class SetmealServiceImpl extends ServiceImpl<SetmealMapper,Setmeal> implements SetmealService {
}

4 检查后删除,业务异常捕获

目标:当分类关联了菜品和套餐时,不允许删除。

跟进到IService的remove方法,通过比较器wrapper删除,参数改成Integer的话算重载,可以改:

代码实现:

我前面自己写的时候,没有用异常捕获,是在业务层根据不同情况返回不同数字,然后controller根据数字R.error("错误原因") 。用异常捕获也能实现,两种效果都一样,用异常捕获更规范

service:

    @Override
    public Integer remove(Long id){
        LambdaQueryWrapper<Setmeal> wrapper1=new LambdaQueryWrapper<>();
        wrapper1.eq(Setmeal::getCategoryId,id);
        LambdaQueryWrapper<Dish> 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<String> 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<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 count1 = dishService.count(dishLambdaQueryWrapper);
 
        //查询当前分类是否关联了菜品,如果已经关联,抛出一个业务异常
        if(count1 > 0){
            //已经关联菜品,抛出一个业务异常
            throw new CustomException("当前分类下关联了菜品,不能删除");
        }
 
        //查询当前分类是否关联了套餐,如果已经关联,抛出一个业务异常
        LambdaQueryWrapper<Setmeal> 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<String> 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<String> 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<String> exceptionHandler(CustomException ex){
        log.error(ex.getMessage());
 
        return R.error(ex.getMessage());
    }
 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1226633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决在pycharm中使用matplotlib画图问题

第一&#xff0c;再导入包后直接绘图出现&#xff1a; AttributeError: module backend_interagg has no attribute FigureCanvas表明版本不兼容&#xff0c;我们需要加入&#xff1a;matplotlib.use(‘TkAgg’) 导入函数就变成了&#xff1a; import matplotlib matplotlib.…

AtCoder Beginner Contest 329 题解A~F

A - Spread 输入字符串&#xff0c;字符之间加上空格输出 B - Next 输出数组当中第二大的数 C - Count xxx 统计每个字符出现过的最长长度&#xff0c;再累加即可 #include<bits/stdc.h> #pragma GCC optimize("Ofast") #define INF 0x3f3f3f3f #define I…

Java Web——Web开发介绍

什么是Web开发 Web开发是一种创建和维护全球广域网&#xff08;World Wide Web&#xff09;上的网站和应用的技术。全球广域网也称为万维网(www World Wide Web)&#xff0c;是一个能够通过浏览器访问的互联网上的巨大信息库。 Web开发的目标是创建功能齐全、易于使用和安全的…

资深测试总结,现在软件测试有未来吗?“你“的底气在哪里?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、为什么会有 “…

基于鼠群算法优化概率神经网络PNN的分类预测 - 附代码

基于鼠群算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于鼠群算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于鼠群优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

Android问题笔记四十六:解决open failed: EACCES (Permission denied) 问题

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列点击跳转>ChatGPT和AIGC &#x1f449;关于作者 专…

低代码在ERP中的理解与应用:提升开发效率与业务灵活性

企业资源规划&#xff08;ERP&#xff09;指通过融合不同部门的信息和流程&#xff0c;提升企业效率、融洽运营的管理体系。ERP系统通过提供一套集成化应用程序&#xff0c;助力企业管理工作流程&#xff0c;包含选购、库存、销售、生产规划等。 低代码&#xff08;Low-Code&a…

皮肤性病科专家谭巍主任提出HPV转阴后饮食七点建议

HPV转阴是每一位感染者都期盼的&#xff0c;因为转阴所以健康&#xff0c;只有转为阴性才意味着不具备传染性&#xff0c;从此也不必再害怕将病毒传染给家人的风险&#xff0c;也不必再担忧持续感染而引发的健康风险。总之&#xff0c;HPV转阴是预示感染者恢复健康与否的主要标…

Windows安装多个版本的Java

在做持续集成CI/CD时&#xff0c;需要用到Jenkins&#xff0c;本人爱好使用各种最新版&#xff0c;down下来之后发现&#xff0c;新版只支持Java11以上的版本了&#xff01;&#xff01; 苦苦找了很久&#xff0c;找不到正规Java8版本的Jenkins安装包&#xff01; 干脆换个思路…

【win32_001】win32命名规、缩写、窗口

整数类型 bool类型 使用注意&#xff1a; 一般bool 的false0&#xff1b;true1 | 2 | …|n false是为0&#xff0c;true是非零 不建议这样用&#xff1a; if (result TRUE) // Wrong! 因为result不一定只返回1&#xff08;true&#xff09;&#xff0c;当返回2时&#xff0c…

【C++】:继承

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关C继承的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…

【机器学习基础】正则化

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;后面的内容会越来越有意思~ ⭐特别提醒&#xff1a;针对机器学习&#xff0c;特别开始专栏&#xff1a;机器学习python实战 欢迎订阅&am…

AI工具合集

网站&#xff1a;未来百科 | 为发现全球优质AI工具产品而生 (6aiq.com) 如今&#xff0c;AI技术涉及到了很多领域&#xff0c;比如去水印、一键抠图、图像处理、AI图像生成等等。站长之家之前也分享过一些&#xff0c;但是在网上要搜索找到它们还是费一些功夫。 今天发现了一…

qsort函数使用方法总结

目录 一、qsort函数原型 二、compar参数 三、各种类型的qsort排序 1. int 数组排序 2. 结构体排序 3. 字符串指针数组排序 4. 字符串二维数组排序 四、回调函数 1. 什么是回调函数 2. 为什么要用回调函数&#xff1f; 3. 怎么使用回调函数&#xff1f; 4.下面是…

Linux | C语言中volatile关键字的理解

目录 前言 一、代码引入 二、现象解释 三、具体引用 前言 本章主要讲解介绍volatile关键的作用与使用场合&#xff1b;深刻理解volatile关键字&#xff1b;本文你需要有信号相关的基础知识&#xff1b; Linux | 信号-CSDN博客 一、代码引入 首先&#xff0c;我们来查看下面…

CICD 持续集成与持续交付(2)

目录 gitlab 部署 jenkins 部署 配置 实时触发 自动化构建docker镜像 通过ssh插件交付任务 添加jenkins节点 RBAC pipeline jenkins结合ansible参数化构建 安装ansible 新建gitlab项目 jenkins新建项目playbook gitlab 部署 虚拟机最小需求&#xff1a;4G内存 4核cpu 下载&…

年货FPS大作,艾尔莎EA B450M-E和你玩转《使命召唤20》

说到动视旗下的《使命召唤》系列&#xff0c;相信大家都不陌生&#xff0c;它以出色爽快的游戏体验以及精良的画面著称&#xff0c;而且每年一部的更新节奏也是如今为数不多的“年货”游戏之一了。时至今日&#xff0c;该系列已经来到了第20部作品&#xff0c;也就是《使命召唤…

第20章 数据库编程

通过本章需要理解JDBC的核心设计思想以及4种数据库访问机制&#xff0c;理解数据库连接处理流程&#xff0c;并且可以使用JDBC进行Oracle数据库的连接&#xff0c;理解工厂设计模式在JDBC中的应用&#xff0c;清楚地理解DriverManager类的作用&#xff0c;掌握Connection、Prep…

简历技术栈redis点

熟悉Redis常见的数据类型以及缓存问题&#xff0c;如缓存穿透、雪崩 、击穿等 Redis五种数据类型 Redis常用命令 查看所有 keys * 字符串类型string 常用命令 举例&#xff1a; 放置一个字符串数据到redis中&#xff0c;先为数据定义一个名称&#xff0c;比如name,age等&am…

⑩⑤【DB】详解MySQL存储过程:变量、游标、存储函数、循环,判断语句、参数传递..

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ MySQL存储过程 1. 介绍2. 使用3. 变量①系统变…