Spring Boot后端返还JSON数据 + 统一异常处理(返还JSON错误)

2023-12-24 14:20

本文主要是介绍Spring Boot后端返还JSON数据 + 统一异常处理(返还JSON错误),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 背景

现在项目都是前后端分离,前后端通过JSON交换数据,这时,后端就需要提供健全的api接口供前端调用。本文主要介绍自己封装的JsonResult与Spring Boot的统一异常处理,项目地址在这里。

2 JsonResult

JsonResult是自己封装的一个返还Json,主要由返还码、返还信息,以及返还数据构成,其中提供了静态方法success、failed可供controller层直接调用。废话不多说,直接上代码供大家参考。

package com.lm.common;import org.apache.commons.lang3.builder.ToStringBuilder;import java.io.Serializable;
import java.util.Objects;/*** @author lming.41032@gmail.com* @date 18-11-7 下午12:25*/
public class JsonResult implements Serializable {private static final long serialVersionUID = 5598308977637490090L;private int status;private String message;private Object data;public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public void setData(Object data) {this.data = data;}public Object getData() {return data;}public static JsonResult success() {return success(null);}public static JsonResult success(Object data) {JsonResult jsonResult = new JsonResult();jsonResult.setStatus(200);jsonResult.setMessage("SUCCESS");if (data != null) {jsonResult.setData(data);}return jsonResult;}public static JsonResult failed() {return failed("FAILED");}public static JsonResult failed(String message) {JsonResult jsonResult = new JsonResult();jsonResult.setStatus(500);jsonResult.setMessage(message);return jsonResult;}@Overridepublic boolean equals(Object o) {if (this == o) {return true;}if (!(o instanceof JsonResult)) {return false;}JsonResult result = (JsonResult) o;return status == result.status &&Objects.equals(message, result.message) &&Objects.equals(data, result.data);}@Overridepublic int hashCode() {return Objects.hash(status, message, data);}@Overridepublic String toString() {return new ToStringBuilder(this).append("status", status).append("message", message).append("data", data).toString();}}

以下就是一个模拟登录成功返还的Json信息.

{"status":200,"message":"SUCCESS","data":{"id":1,"userName":"lmm","password":"123"}
}

3 统一异常处理(返还Json)

在前后端分离项目中,无论后台程序出现了什么问题,我们都要返还一个错误的Json信息。这个错误的信息可以包括错误码,错误信息等,这样不仅仅方便前端处理,也方便后期运维、开发人员快速的定位到错误。下面就是一个错误的Json信息。

	{"status":700,"message":"用户不存在!","data":null}

首先我们需要定义一个基本异常,它主要包包含错误码,错误信息。我们也可以在这个基本异常中预先定义一些异常如参数错误、没有权限等。

package com.lm.common;/*** @author lming.41032@gmail.com* @date 18-11-7 上午11:46*/
public class BaseException extends Exception {private static final long serialVersionUID = -3392027101671055457L;public static final int ERROR_CODE_ILLEGAL_ARGUMENTS = 600;// 错误码private int code;//错误信息private String errorMessage;public BaseException(int code) {super("error code" + code);this.code = code;}public BaseException(int code, Throwable throwable) {super(throwable);this.code = code;}public BaseException(int code, String errorMessage) {super(errorMessage);this.code = code;this.errorMessage = errorMessage;}public int getCode() {return code;}public String getErrorMessage() {return errorMessage;}
}

一个系统由多个模块组成,每个模块中都可能会抛出各种各样的异常,这时我们就需要在模块中定义属于本模块中的异常,这些异常需继承BaseException。比如用户登录模块,可能就会抛出用户不存在、密码错误等异常,这时我们定义一个UserException异常,如下所示。

package com.lm.user;import com.lm.common.BaseException;/*** @author lming.41032@gmail.com* @date 18-11-7 上午11:53*/
public class UserException extends BaseException {public static final int ERROR_CODE_NOT_EXIT = 700;public static final int ERROR_CODE_PASSWORD_EEEOR = 701;public UserException(int code) {super(code);}
}

定义完异常后,我们需要对异常进行处理,这样后台抛出异常后,将直接返还错误Json。我们定义一个统一异常处理类(GlobalExceptionHandle),用@ControllerAdvice注解该类,用注解@ExceptionHandler来定义要处理的异常类型。用@ResponseBody来使返还的数据为Json格式。

package com.lm.dubboconsumer.common;import com.google.gson.Gson;
import com.lm.common.BaseException;
import com.lm.common.JsonResult;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Locale;/*** @author lming.41032@gmail.com* @date 18-11-7 下午12:17*/
@ControllerAdvice
public class GlobalExceptionHandle {private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandle.class);private final MessageSource messageSource;@Autowiredpublic GlobalExceptionHandle(MessageSource messageSource) {this.messageSource = messageSource;}@ExceptionHandler(value = Exception.class)@ResponseBodypublic JsonResult defaultErrorHandle(HttpServletRequest request, HttpServletResponse response,Exception e, Locale locale) throws IOException {JsonResult result = new JsonResult();int code = 500;String errorMessage = null;Throwable exception = e;if (exception instanceof BaseException) {code = ((BaseException) exception).getCode();errorMessage = ((BaseException) exception).getErrorMessage();} else if (exception instanceof MissingServletRequestParameterException) {code = BaseException.ERROR_CODE_ILLEGAL_ARGUMENTS;} else if (!(exception instanceof BaseException || exception instanceof MissingServletRequestParameterException)) {LOGGER.error("Unknown Exception, URI = " + request.getRequestURI(), e);} else {LOGGER.error("URI = {}, errorCode = {}, errorMessage = {}", request.getRequestURI(), code, errorMessage);}// 如果异常中包含了错误信息,则不会通过错误码获取定义的错误信息if (StringUtils.isBlank(errorMessage)) {String prefix = exception.getClass().getSimpleName();errorMessage = getMessage(prefix + "." + code, locale);if (errorMessage == null) {errorMessage = getMessage(Integer.toString(code), locale);}}result.setStatus(code);result.setMessage(errorMessage);return result;}private String getMessage(String key, Locale locale) {String errorMessage = null;try {errorMessage = messageSource.getMessage(key, null, locale);} catch (NoSuchMessageException exception) {LOGGER.debug("ErrorMessage|NotFound|{}", key);}return errorMessage;}
}

我们前面定义的异常都是都是只定义了错误码,至于错误信息,我们可以在项目resource下建一个error_codes.properties文件,其中=前面是我们自定义异常中的code,而=号右边的就是错误信息了。

500=系统错误,请稍后重试!
600=参数错误!
700=用户不存在!
701=用户已经存在!

error_codes.properties文件创建完后,需要在aplication.yml(aplication.properties)中设置一下。

spring:messages:basename: error_codescache-duration: 600s

4 测试

Service层

package com.lm.dubboprovider.user.impl;import com.lm.common.BaseException;
import com.lm.user.User;
import com.lm.user.UserException;
import com.lm.user.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;/*** @author lming.41032@gmail.com* @date 18-11-4 下午2:55*/
@Service
public class UserServiceImpl implements UserService {private static final String USERNAME = "lm";private static final String PASSWORD = "123";@Overridepublic Boolean login(String userName, String password) throws BaseException {if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)) {throw new BaseException(BaseException.ERROR_CODE_ILLEGAL_ARGUMENTS);}if (!userName.equals(USERNAME)) {throw new UserException(UserException.ERROR_CODE_NOT_EXIT);}if (USERNAME.equals(userName) && PASSWORD.equals(password)) {return true;}return false;}
}

Controller层

package com.lm.dubboconsumer.user;import com.lm.common.BaseException;
import com.lm.common.JsonResult;
import com.lm.user.User;
import com.lm.user.UserException;
import com.lm.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;/*** @author lming.41032@gmail.com* @date 18-11-5 下午5:10*/
@RestController
@RequestMapping("user")
public class UserRestController {private final UserService userService;@Autowiredpublic UserRestController(UserService userService) {this.userService = userService;}@GetMapping("login")public JsonResult login(HttpServletRequest request) throws UserException, BaseException {String userName = request.getParameter("username");String password = request.getParameter("password");Boolean flag = userService.login(userName, password);if (flag) {return JsonResult.success();} else {throw JsonResult.failed();}}
}

登录成功:
在这里插入图片描述
参数错误:
在这里插入图片描述
用户不存在:
在这里插入图片描述

5 总结

CSDN写博客一定要定时点击保存按钮。

这篇关于Spring Boot后端返还JSON数据 + 统一异常处理(返还JSON错误)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/532056

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定