前后端分离异常统一处理

作为一个程序员,虽然技术不厉害,但是都有一个向上的心,原来一直负责业务开发,梳理业务、设计流程、开发代码,最近开始接触一些架构类的设计和思路

全国医改在即,项目组接了一个医疗改革相关的供应商项目,主要是针对物流方向的。

技术架构:领导要求用springcloud但是新来的成员都没有相关开发经验,项目负责人直接在网上扒了一套微服务的代码(个人感觉不太成熟),好多东西不太全,

所以需要重新整理,由于项目负责人比较忙,自己有迫切的想要了解一些东西,所以针对架构层次的代码学习了一下,

自己原来只做业务,从不关心架构的设计是否合理优美,甚至在业务方向已经做到管理层次,后来跳槽离职后才发现自己技术的短板,所以一直在补充学习

其实只需要架构师搭建微服务架构即可,项目组成员还是针对不同的功能模块进行业务开发,和原来的SSM没有本质区别,只是增加了一些新的注解,和组件的使用

这里就不对微服务的组件进行介绍了,只是针对自己部署的异常处理进行记录——只是个人理解,如有好的设计欢迎指正

问题描述

技术架构是前后端分离,想着统一返处理回值(包括正常结果和异常结果),但是架构代码只是做了一个自己的返回类Map类型,如下

package com.bootdo.clouddocommon.utils;

import java.util.HashMap;
import java.util.Map;

public class R extends HashMap<String, Object> {
    private static final long serialVersionUID = 1L;
    public R() {
        put("code", 0);
        put("msg", "操作成功");
    }
    public static R error() {
        return error(500, "操作失败");
    }
    public static R operate(boolean b){
        if(b){
            return R.ok();
        }
        return R.error();
    }
    public static R error(String msg) {
        return error(500, msg);
    }
    public static R error(int code, String msg) {
        R r = new R();
        r.put("code", code);
        r.put("msg", msg);
        return r;
    }
    public static R ok(String msg) {
        R r = new R();
        r.put("msg", msg);
        return r;
    }
    public static R ok(Map<String, Object> map) {
        R r = new R();
        r.putAll(map);
        return r;
    }
    public static R ok() {
        return new R();
    }
    public static R error401() {
        return error(401, "你还没有登录");
    }
    public static R error403() {
        return error(403, "你没有访问权限");
    }
    public static R data(Object data){
        return R.ok().put("data",data);
    }
    public static R page(Object page){
        return R.ok().put("page",page);
    }
    @Override
    public R put(String key, Object value) {
        super.put(key, value);
        return this;
    }
}

这种这种类封装方式很好的处理的所有Controller类的返回结果 例如;

    @Log("停用记录")
    @ApiOperation(value = "停用信息记录")
    @PutMapping("/stop")
    R stop(@RequestBody List<Long> idList) {

        return R.operate(consumeMaterialService.stop(idList,getUser()) > 0);
    }
  @Log("获取耗材信息列表(无分页)")
    @ApiOperation(value = "获取耗材信息列表(无分页)")
    @ApiImplicitParam(name = "params", value = "map参数集合(基础的参数格式——可在结构内增加其他过滤条件字段)", example = "{consumeName:10}")
    @GetMapping("/allList")
    R list(@RequestParam Map<String, Object> params) {
        List<ConsumeMaterialDO> list = consumeMaterialService.list(params);
        return R.data(list);

    }

这种方式特点

1、很好的统一了Controller层的返回结果

2、没有一套错误编码和对应的信息,需要硬编码的形式在代码提现,例如:(该问题可以通过增加一个错误信息的枚举类来解决——下文中会说明)

R findMaterialBySupplierIdNotAddList(@RequestParam Map<String, Object> params){
        if(params.isEmpty()){
            return R.error("30032",”"医院ID和供应商ID不能为空");//可以只写错误信息,也可以加上编码
        }else{
            Long id=new Long(params.get("hospitalId").toString());
            if(id==null||id==0){
                return R.error("医院ID不能为空");
            }
            Long sid=new Long(params.get("supplierId").toString());
            if(sid==null||sid==0){
                return R.error("供应商ID不能为空");
            }
        }
        //查询列表数据
        Query query = new Query(params);
        List<ConsumeMaterialDO> materialList = supplierService.findMaterialBySupplierIdNotAddList(query);
        int total = supplierService.findMaterialBySupplierIdNotAddCount(query);
        PageUtils pageUtils = new PageUtils(materialList, total);
        //返回状态字典
        List<SysDictDO> statusList = initDataService.getSysDictByType("status");
        //返回耗材状态
        List<SysDictDO> measurementStatusList = initDataService.getSysDictByType("unit");
        return R.ok().put("page",pageUtils).put("suppliermaterialstatusoptions",statusList).put("measurementstatusoptions",measurementStatusList);
    }

3、没有办法处理service层的异常返回,因为service 层返回的都是具体的实体或者整数

因为原来做过的项目中有过相关的异常处理——记得是定义一个统一的异常接收类对返回值结构进行处理,其他地方直接抛出异常即可,当然需要定义一套错误信息枚举类,用于统一返回信息内容

随意根据自己的理解和经验,查找相关代码做了一套异常处理的代码,代码和原理很简单

参考链接:https://segmentfault.com/a/1190000016576329

1、首先在原来的基础上增加一个错误信息的枚举类——代码比较多删减了一部分,可以根据自己的需求添加

package com.bootdo.clouddocommon.constants;

/**
 * 异常处理状态码
 */
public enum ResultCode {

    SUCCESS(0, "请求成功"),
    Unknown_Exception(-1, "未知异常"),

    USER_NOT_FOUND(10001, "没有找到此用户"),
    USERNAME_NOT_BLANK(10002, "用户名不能为空"),
    USERNAME_EXIST(10003, "用户名已经存在"),
    USERTYPE_ERROR(100031, "用户类型不正确"),   

    DEVICE_ID_EMPTY(10052,"设备ID:deviceId不能为空"),
    DELETE_CONNECT_ERROR(10053,"删除connect出错");

    private int code;
    private String message;

    ResultCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

2、添加一个自定义的异常类用于抛出:主要是将自己的错误编码和信息整合进去——原生的异常类也是可以的,只是好像没有自定的编码返回(自定义的异常类也需要集成原生的异常类——红色部分——有兴趣的同学可以看一下源码)

package com.bootdo.clouddoadmin.config;

import com.bootdo.clouddocommon.constants.ResultCode;
/**
 * 功能描述: <br>
 * 〈异常类封装——定义抛出的异常类〉

 * @return:
 * @since: 1.0.0
 * @Author:
 * @Date:
 */
public class DomainException extends RuntimeException {
    private int errCode = ResultCode.Unknown_Exception.getCode();

    public DomainException() {
        super(ResultCode.Unknown_Exception.getMessage());
    }

    public DomainException(ResultCode resultCode) {
        super(resultCode.getMessage());
        this.errCode = resultCode.getCode();
    }

    public int getErrCode() {
        return errCode;
    }

    public void setErrCode(int errCode) {
        this.errCode = errCode;
    }
}

3、添加统一的异常返回处理——RestControllerAdvice(ControllerAdvice)拦截异常并统一处理

package com.bootdo.clouddoadmin.config;

import com.bootdo.clouddocommon.utils.R;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
/**
 * 功能描述: <br>
 * 〈统一异常处理返回〉

 * @return:
 * @since: 1.0.0
 * @Author:
 * @Date:
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = DomainException.class)
    public R domainExceptionHandler(HttpServletRequest req,
                                    DomainException e) throws Exception {
        e.printStackTrace();
        return   R.error(e.getErrCode(), e.getMessage());
    }
}

这样整体就设计完了,无论是在service或者controller中都可以抛出异常,然后经过处理成为统一格式的返回值

例如:

throw new DomainException(ResultCode.CODE_EMPTY);

经测试是有效的——结果截图就不再展示了

原文地址:https://www.cnblogs.com/yutf/p/11493454.html

时间: 2024-08-26 11:35:03

前后端分离异常统一处理的相关文章

[转]从MVC到前后端分离

从MVC到前后端分离 来源:csdn 发布时间:2015-10-26 阅读次数:1680 1. 理解MVC MVC是一种经典的设计模式,全名为Model-View-Controller,即模型-视图-控制器. 其中,模型是用于封装数据的载体,例如,在Java中一般通过一个简单的POJO(Plain Ordinary Java Object)来表示,其本质是一个普通的Java Bean,包含一系列的成员变量及其getter/setter方法.对于视图而言,它更加偏重于展现,也就是说,视图决定了界面

从 MVC 到前后端分离——转自:OSChina 黄勇

转自:OSChina 黄勇 从 MVC 到前后端分离 1 理解 MVC MVC 是一种经典的设计模式,全名为 Model-View-Controller,即 模型-视图-控制器. 其中,模型 是用于封装数据的载体,例如,在 Java 中一般通过一个简单的 POJO(Plain Ordinary Java Object)来表示,其本质是一个普通的 Java Bean,包含一系列的成员变量及其 getter/setter 方法.对于 视图 而言,它更加偏重于展现,也就是说,视图决定了界面到底长什么样

[转] 前后端分离开发模式的 mock 平台预研

引入 mock(模拟): 是在项目测试中,对项目外部或不容易获取的对象/接口,用一个虚拟的对象/接口来模拟,以便测试. 背景 前后端分离 前后端仅仅通过异步接口(AJAX/JSONP)来编程 前后端都各自有自己的开发流程,构建工具,测试集合 关注点分离,前后端变得相对独立并松耦合 开发流程 后台编写和维护接口文档,在 API 变化时更新接口文档 后台根据接口文档进行接口开发 前端根据接口文档进行开发 开发完成后联调和提交测试 面临问题 没有统一的文档编写规范,导致文档越来越乱,无法维护和阅读 开

从MVC到前后端分离

摘要:MVC模式早在上个世纪70年代就诞生了,直到今天它依然存在,可见生命力相当之强.MVC模式最早用于Smalltalk语言中,最后在其它许多开发语言中都得到了很好的应用,例如,Java中的Struts.Spring MVC等框架. 1. 理解MVC MVC是一种经典的设计模式,全名为Model-View-Controller,即模型-视图-控制器. 其中,模型是用于封装数据的载体,例如,在Java中一般通过一个简单的POJO(Plain Ordinary Java Object)来表示,其本

关于大型网站技术演进的思考(十六)--网站静态化处理—前后端分离—下(8)

我第一次听说nodejs技术大概是在2009年年末,不过我真正认真在网络上进一步了解nodejs还是在2010年年中,当时对nodejs的认识和我现在对nodejs的认识有着天壤的区别,开始想了解nodejs我只是为了感慨谷歌公司开发的V8引擎居然如此强大,它不仅仅可以作为chrome浏览器的javascript内核运行平台,居然还能为服务端使用javascript语言作为平台,通过对nodejs的了解让我认识到chrome浏览器是如此的优秀,但是如此相对的是我并不认为javascript作为服

从 MVC 到前后端分离

从 MVC 到前后端分离 1 理解 MVC MVC 是一种经典的设计模式,全名为 Model-View-Controller,即 模型-视图-控制器. 其中,模型 是用于封装数据的载体,例如,在 Java 中一般通过一个简单的 POJO(Plain Ordinary Java Object)来表示,其本质是一个普通的 Java Bean,包含一系列的成员变量及其 getter/setter 方法.对于 视图 而言,它更加偏重于展现,也就是说,视图决定了界面到底长什么样子,在 Java 中可通过

【转】关于大型网站技术演进的思考(十六)--网站静态化处理—前后端分离—下(8)

我第一次听说nodejs技术大概是在2009年年末,不过我真正认真在网络上进一步了解nodejs还是在2010年年中,当时对nodejs的认识和我现在对nodejs的认识有着天壤的区别,开始想了解nodejs我只是为了感慨谷歌公司开发的V8引擎居然如此强大,它不仅仅可以作为chrome浏览器的javascript内核运行平台,居然还能为服务端使用javascript语言作为平台,通过对nodejs的了解让我认识到chrome浏览器是如此的优秀,但是如此相对的是我并不认为javascript作为服

REST风格框架实战:从MVC到前后端分离(附完整Demo)

既然MVC模式这么好,难道它就没有不足的地方吗?我认为MVC至少有以下三点不足:每次请求必须经过“控制器->模型->视图”这个流程,用户才能看到最终的展现的界面,这个过程似乎有些复杂:实际上视图是依赖于模型的,换句话说,如果没有模型,视图也无法呈现出最终的效果:渲染视图的过程是在服务端来完成的,最终呈现给浏览器的是带有模型的视图页面,性能无法得到很好的优化. 为了使数据展现过程更加直接,并且提供更好的用户体验,我们有必要对MVC模式进行改进.不妨这样来尝试:首先从浏览器发送AJAX请求,然后服

前后端分离springmvc和RESTful理解

1. 理解MVC MVC是一种经典的设计模式,全名为Model-View-Controller,即模型-视图-控制器. 其中,模型是用于封装数据的载体,例如,在Java中一般通过一个简单的POJO(Plain Ordinary Java Object)来表示,其本质是一个普通的Java Bean,包含一系列的成员变量及其getter/setter方法.对于视图而言,它更加偏重于展现,也就是说,视图决定了界面到底长什么样子,在Java中可通过JSP来充当视图,或者通过纯HTML的方式进行展现,而后