SpringBoot + Vue前后端分离开发:全局异常处理及统一结果封装

简介: SpringBoot + Vue前后端分离开发:全局异常处理及统一结果封装的实现

SpringBoot + Vue前后端分离开发:全局异常处理及统一结果封装

文章目录

  • SpringBoot + Vue前后端分离开发:全局异常处理及统一结果封装
  • 前后端分离开发中的异常处理
  • 统一结果封装
  • 后端全局异常捕获及处理
  • 前端axios后置拦截器

前后端分离开发中的异常处理

  在我们的前后端分离项目中,有时候不可避免发生后端服务报错抛出异常的情况,如果不配置全局异常处理机制,就会默认返回tomcat或者nginx的5XX页面,对普通用户来说,不太友好,用户也不懂什么情况。这时候需要我们程序员设计返回一个友好简单的格式给前端,然后再由前端给用户返回能够使其理解的报错信息,而不是抛一个java exception给用户。

  后端给前端返回错误信息,前端需要能接收到此错误信息并告知用户,也即前端也需要进行异常处理,在Vue项目中,前端都是用axios向后端发送请求,前端需要配置全局axios拦截器,拦截后端给我们返回的http response,判断请求是否成功,失败的话则返回相应错误信息

  在上述前后端交互的过程中,有必要统一一个结果返回封装类,这样前后端交互的时候有个统一的标准,约定结果返回的数据是正常的或者遇到异常了。否则后端返回的数据五花八门,前端也无法判断请求是否成功了

统一结果封装

  统一结果封装是由前后端协商共同确定的,对于不同的项目可能封装类不同。

  在此我们用一个简单的统一结果封装类来演示这个前后端交互的重要环节。一般来说,统一结果封装类里面有几个要素必要的:

  • 请求是否成功,可用code表示(如200表示成功,400表示异常)
  • 请求结果消息message
  • 请求结果数据data

  这里我们用一个Result类来表示统一结果封装类,那么Result类里肯定有以下三个属性了:

1.png

  Result里应该有哪些方法呢?请求只有成功和失败两种情况,Result里应定义静态方法,用以生成Result对象返回给前端,参数即为Result对象的3个属性,于是我们定义以下两个方法:

2.png

  光有这两个方法还不够,因为这两个方法并不是特别方便使用。对于大部分请求成功的情况,code就是200,请求成功的message其实并不重要,data才是前端需要的,也就是说,在大部分请求成功的情况下,我们只要把data传给前端就行,创建Result的方法,参数只要一个,那就是data,code直接为200,message为操作成功就行。于是我们定义一个succ的重载方法,能让我们更方便的使用结果封装:

3.png

  对于大部分请求失败的情况也是一样,一般请求失败时,后端都不会向前端返回data,请求失败时异常的报错信息message才是前端需要的,code也可以直接定义为400,因为400代表http中的bad request,即请求失败。于是我们定义一个fail的重载方法:

4.png

  此时,统一结果封装类我们就定义完成了,它的完整代码如下:

@Data
public class Result implements Serializable {
    private int code;
    private String msg;
    private Object data;
    public static Result succ(Object data) {
        return succ(200, "操作成功", data);
    }
    public static Result fail(String msg) {
        return fail(400, msg, null);
    }
    public static Result succ (int code, String msg, Object data) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(data);
        return result;
    }
    public static Result fail (int code, String msg, Object data) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        result.setData(data);
        return result;
    }
}

  需注意的是,Result类实现了Serializable接口,是为了可序列化,能转成JSON等进行网络传输,传到前端

后端全局异常捕获及处理

  我们可以定义一个叫GlobalExceptionHandler的类来捕获和处理全局异常,该类需要使用@RestControllerAdvice注解

  @RestControllerAdvice注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中。@RestControllerAdvice 是组件注解,他使得其实现类能够被classpath扫描自动发现。@RestControllerAdvice注解主要配合@ExceptionHandler使用,统一处理异常情况。

  即@RestControllerAdvice注解定义全局控制器异常处理

  我们可以在该类中定义多个重载的handler方法,用于捕获并处理异常,handler的方法参数为各类不同的异常,handler方法需使用@ExceptionHandler注解,该注解的元素value能指定捕获的是哪类异常 ,如@ExceptionHandler(value = RuntimeException.class)表示捕获运行时异常。用@ExceptionHandler注解标记的这个异常的处理,是全局的,所有与value值相同类型的异常,都会跑到这个地方处理。

  handler方法还需使用@ResponseStatus注解,可以通过@ResponseStatus注解和自定义异常配合使用,来返回自定义响应状态码和自定义错误信息给客户端。即@ResponseStatus注解配合@ExceptionHandler注解使用,这里我们主要是需要用它来设置不同异常所对应的http状态码。@ResponseStatus注解中有两个参数,value属性设置异常的状态码,reaseon是异常的描述。

  GlobalExceptionHandler全局异常处理类的完整代码例子如下:

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = RuntimeException.class)
    public Result handler(RuntimeException e) {
        log.error("运行时异常:----------------{}", e.getMessage());
        return Result.fail(e.getMessage());
    }
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ExceptionHandler(value = AccessDeniedException.class)
    public Result handler(AccessDeniedException e) {
        log.info("security权限不足:----------------{}", e.getMessage());
        return Result.fail("权限不足");
    }
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Result handler(MethodArgumentNotValidException e) {
        log.info("实体校验异常:----------------{}", e.getMessage());
        BindingResult bindingResult = e.getBindingResult();
        ObjectError objectError = bindingResult.getAllErrors().stream().findFirst().get();
        return Result.fail(objectError.getDefaultMessage());
    }
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = IllegalArgumentException.class)
    public Result handler(IllegalArgumentException e) {
        log.error("Assert异常:----------------{}", e.getMessage());
        return Result.fail(e.getMessage());
    }
}

  由于项目中不同的异常众多,我们也可以自定义异常类,并在GlobalExceptionHandler中添加对自定义异常的捕获,举个例子,我们可以自定义一个登陆验证码异常:

public class CaptchaException extends AuthenticationException {
    public CaptchaException(String msg) {
        super(msg);
    }
}

  然后在全局异常处理中加入对该自定义异常的处理:

@ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = CaptchaException.class)
    public Result handler(CaptchaException e) {
        log.error("登录验证码异常:----------------{}", e.getMessage());
        return Result.fail(e.getMessage());
    }

  注意,Java中的异常Exception都是Throwable的子类,Throwable中定义了getMessage()方法,用以返回异常的具体信息:

5.png

  例子中的MethodArgumentNotValidException继承了BindException,这个异常是spring实体校验中定义的,该异常有一个BindingResult属性,BindingResult用在实体类校验信息返回结果绑定,BindingResult类继承了spring validation中的Errors类,Errors类用于存储并公开有关特定对象的数据绑定和验证错误的信息。bindingResult.hasErrors()可判断是否校验通过,Errors类中有getAllErrors()方法,用于获取全局和Field字段中的所有错误。ObjectError类用于封装object error

前端axios后置拦截器

  在Vue的src目录下创建axios.js文件,用以配置axios,前端使用axios后置拦截器拦截http response,获取后端返回的信息

  axios.js的完整代码示例如下:

import axios from "axios";
import router from "./router";
import Element from "element-ui"
axios.defaults.baseURL = "http://localhost:8082"
const request = axios.create({
    timeout: 5000,
    headers: {
        'Content-Type': "application/json; charset=utf-8"
    }
})
// 后置拦截
request.interceptors.response.use(response => {
        console.log("response ->" + response)
        // 这里是response的拦截
        let res = response.data
        if (res.code === 200) {
            return response
        } else {
            Element.Message.error(!res.msg ? '系统异常' : res.msg)
            // 拒绝流程继续往下走
            return Promise.reject(response.data.msg)
        }
    },
    // 如果业务中出现异常
    error => {
        // 先看后端返没返报错信息,返了就用后端的
        if (error.response.data) {
            error.message = error.response.data.msg
        }
        // 401没权限
        if (error.response.status === 401) {
            router.push("/login")
        }
        Element.Message.error(error.message, {duration:3000})
        return Promise.reject(error)
    }
)
export default request

  后置拦截器中有response => {...}error => {...},分别表示对响应数据和错误请求的处理,对于响应数据,若其code为200,说明请求成功,则返回response。否则进入异常处理,这里用element-UI来弹出错误信息,若响应数据的msg为空,则错误信息为系统异常,否则错误信息就是响应数据中的异常信息,调用Promise.reject拒绝后续流程。对于错误请求的处理也是类似的

目录
相关文章
|
2月前
|
前端开发 安全 Java
基于springboot+vue开发的会议预约管理系统
一个完整的会议预约管理系统,包含前端用户界面、管理后台和后端API服务。 ### 后端 - **框架**: Spring Boot 2.7.18 - **数据库**: MySQL 5.6+ - **ORM**: MyBatis Plus 3.5.3.1 - **安全**: Spring Security + JWT - **Java版本**: Java 11 ### 前端 - **框架**: Vue 3.3.4 - **UI组件**: Element Plus 2.3.8 - **构建工具**: Vite 4.4.5 - **状态管理**: Pinia 2.1.6 - **HTTP客户端
344 4
基于springboot+vue开发的会议预约管理系统
|
6月前
|
JavaScript 前端开发 Java
制造业ERP源码,工厂ERP管理系统,前端框架:Vue,后端框架:SpringBoot
这是一套基于SpringBoot+Vue技术栈开发的ERP企业管理系统,采用Java语言与vscode工具。系统涵盖采购/销售、出入库、生产、品质管理等功能,整合客户与供应商数据,支持在线协同和业务全流程管控。同时提供主数据管理、权限控制、工作流审批、报表自定义及打印、在线报表开发和自定义表单功能,助力企业实现高效自动化管理,并通过UniAPP实现移动端支持,满足多场景应用需求。
630 1
|
7月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
504 7
|
3月前
|
前端开发 JavaScript Java
基于springboot+vue开发的校园食堂评价系统【源码+sql+可运行】【50809】
本系统基于SpringBoot与Vue3开发,实现校园食堂评价功能。前台支持用户注册登录、食堂浏览、菜品查看及评价发布;后台提供食堂、菜品与评价管理模块,支持权限控制与数据维护。技术栈涵盖SpringBoot、MyBatisPlus、Vue3、ElementUI等,适配响应式布局,提供完整源码与数据库脚本,可直接运行部署。
234 6
基于springboot+vue开发的校园食堂评价系统【源码+sql+可运行】【50809】
|
7月前
|
人工智能 Java 数据库
飞算 JavaAI:革新电商订单系统 Spring Boot 微服务开发
在电商订单系统开发中,传统方式耗时约30天,需应对复杂代码、调试与测试。飞算JavaAI作为一款AI代码生成工具,专注于简化Spring Boot微服务开发。它能根据业务需求自动生成RESTful API、数据库交互及事务管理代码,将开发时间缩短至1小时,效率提升80%。通过减少样板代码编写,提供规范且准确的代码,飞算JavaAI显著降低了开发成本,为软件开发带来革新动力。
|
8月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot返回Json数据及数据封装——封装统一返回的数据结构
本文介绍了在Spring Boot中封装统一返回的数据结构的方法。通过定义一个泛型类`JsonResult<T>`,包含数据、状态码和提示信息三个属性,满足不同场景下的JSON返回需求。例如,无数据返回时可设置默认状态码"0"和消息"操作成功!",有数据返回时也可自定义状态码和消息。同时,文章展示了如何在Controller中使用该结构,通过具体示例(如用户信息、列表和Map)说明其灵活性与便捷性。最后总结了Spring Boot中JSON数据返回的配置与实际项目中的应用技巧。
685 0
|
4月前
|
JSON Java 数据格式
Spring Boot返回Json数据及数据封装
在Spring Boot中,接口间及前后端的数据传输通常使用JSON格式。通过@RestController注解,可轻松实现Controller返回JSON数据。该注解是Spring Boot新增的组合注解,结合了@Controller和@ResponseBody的功能,默认将返回值转换为JSON格式。Spring Boot底层默认采用Jackson作为JSON解析框架,并通过spring-boot-starter-json依赖集成了相关库,包括jackson-databind、jackson-datatype-jdk8等常用模块,简化了开发者对依赖的手动管理。
534 3
|
8月前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
753 79
|
5月前
|
监控 数据可视化 JavaScript
springboot + vue的MES系统生产计划管理源码
MES系统(制造执行系统)的生产计划管理功能是其核心模块之一,涵盖生产计划制定与优化、调度排程、进度监控反馈、资源管理调配及可视化报告五大方面。系统基于SpringBoot + Vue-Element-Plus-Admin技术栈开发,支持多端应用(App、小程序、H5、后台)。通过实时数据采集与分析,MES助力企业优化生产流程,适用于现代化智能制造场景。
289 1
|
6月前
|
供应链 JavaScript BI
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
这是一款专为小微企业打造的 SaaS ERP 管理系统,基于 SpringBoot+Vue+ElementUI+UniAPP 技术栈开发,帮助企业轻松上云。系统覆盖进销存、采购、销售、生产、财务、品质、OA 办公及 CRM 等核心功能,业务流程清晰且操作简便。支持二次开发与商用,提供自定义界面、审批流配置及灵活报表设计,助力企业高效管理与数字化转型。
609 2
ERP系统源码,基于SpringBoot+Vue+ElementUI+UniAPP开发
下一篇
oss云网关配置