文章目录

处理转发失败的情况全局参数同一返回格式操作消息对象AjaxResult返回值状态描述对象AjaxStatus返回值枚举接口层StatusCode

全局异常处理器自定义通用异常定一个自定义异常覆盖默认的异常处理自定义异常处理工具

在上一篇章时我们有了一个简单的gateway网关

[Spring Cloud] gateway简单搭建与请求转发-CSDN博客

现在我们需要根据这个网关进行一部分的改进

现在我们需要进一步的处理一些问题,来使得网关更加完善。 本篇文章的完整代码文件已放置在gitee。 杉极简/gateway网关阶段学习

处理转发失败的情况

正常情况下,我们请求了一个接口,并得到了一个结果,如下: 但是,我们依然要考虑,如果访问到一个不存在的接口,会得到什么样的结果? 如果不做任何修改的时候,我们会得到以下的结果: 但这不是我们想要的。 我们想要如下返回结果。 因此我们需要配置一个全局异常处理器来处理。 为达到这个目的,我们开始构建一些基础的功能,描述如下。

全局参数

我们需要去创建一个全部配置,如下所示: 这里统一存放着我们需要读取的配置,主要为全局使用的参数。具体配置方式如下所示: 在网关项目中创建一个config文件夹,用于存放网关的相关配置。(当然,能想做网关的人,应该都熟练的会使用Spring Boot了,在Spring Boot项目中,这都是一些较为基础的内容) 此时,我们先配置一个全局异常捕捉-打印堆栈异常的参数,用于本文的一些功能当中。

global:

# 全局异常捕捉-打印堆栈异常

printStackTrace: true

import lombok.Data;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.stereotype.Component;

/**

* @author fir

* @date 2023/7/28 17:53

*/

@Data

@Component

@ConfigurationProperties(prefix = "global")

public class GlobalConfig {

/**

* 全局异常捕捉-打印堆栈异常

*/

private boolean printStackTrace;

}

同一返回格式

创建一个result文件夹,用于存放统一返回值的相关配置 该部分比较基础,暂时只说明配置方式与代码。

操作消息对象AjaxResult

import java.io.Serializable;

import java.util.HashMap;

/**

* 操作消息-JSON

*

* @author fir

*/

public class AjaxResult extends HashMap implements Serializable {

private static final long serialVersionUID = 1L;

/**

* 状态码

*/

public static final String CODE_TAG = "code";

/**

* 返回内容

*/

public static final String MSG_TAG = "msg";

/**

* 数据对象

*/

public static final String DATA_TAG = "data";

/**

* 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。

*/

public AjaxResult() {

}

/**

* 初始化一个新创建的 AjaxResult 对象

*

* @param code 状态码

* @param msg 状态描述

*/

public AjaxResult(int code, String msg) {

super.put(CODE_TAG, code);

super.put(MSG_TAG, msg);

}

/**

* 初始化一个新创建的 AjaxResult 对象

*

* @param code 状态码

* @param msg 状态描述

* @param data 数据对象

*/

public AjaxResult(int code, String msg, Object data) {

super.put(CODE_TAG, code);

super.put(MSG_TAG, msg);

if (data != null) {

super.put(DATA_TAG, data);

}

}

/**

* 返回成功消息

*

* @return 成功消息

*/

public static AjaxResult success() {

AjaxStatus success = AjaxStatus.SUCCESS;

return AjaxResult.success(success.getCode(), success.getMsg());

}

/**

* 返回成功数据

*

* @return 成功消息

*/

public static AjaxResult success(Object data) {

AjaxStatus success = AjaxStatus.SUCCESS;

return AjaxResult.success(success.getMsg(), data);

}

/**

* 返回成功数据

*

* @return 成功消息

*/

public static AjaxResult success(AjaxStatus success) {

return AjaxResult.success(success.getMsg(), new HashMap<>(0));

}

/**

* 返回成功消息

*

* @param code 状态吗

* @param msg 状态描述

* @return 消息体

*/

public static AjaxResult success(Integer code, String msg) {

return new AjaxResult(code, msg);

}

/**

* 返回成功消息

*

* @param msg 状态描述

* @param data 数据对象

* @return 成功消息

*/

public static AjaxResult success(String msg, Object data) {

AjaxStatus success = AjaxStatus.SUCCESS;

return new AjaxResult(success.getCode(), msg, data);

}

/**

* 返回特定状态描述

*

* @param statusCode 特定的枚举结果

* @param data 数据对象

* @return 请求结果

*/

public static AjaxResult success(StatusCode statusCode, Object data) {

return new AjaxResult(statusCode.getCode(), statusCode.getMsg(), data);

}

/**

* 返回错误消息

*

* @return 警告消息

*/

public static AjaxResult error() {

return AjaxResult.error(AjaxStatus.LOSE_OPERATION.getMsg());

}

/**

* 返回错误消息

*

* @param msg 状态描述

* @return 警告消息

*/

public static AjaxResult error(String msg) {

return AjaxResult.error(msg, new HashMap<>(0));

}

/**

* 返回错误消息

*

* @param msg 状态描述

* @param data 数据对象

* @return 警告消息

*/

public static AjaxResult error(String msg, Object data) {

AjaxStatus loseEfficacy = AjaxStatus.LOSE_EFFICACY;

return new AjaxResult(loseEfficacy.getCode(), msg, data);

}

/**

* 返回错误消息

*

* @param code 状态码

* @param msg 状态描述

* @return 警告消息

*/

public static AjaxResult error(int code, String msg) {

return new AjaxResult(code, msg, new HashMap<>(0));

}

/**

* 返回特定状态描述

*

* @param statusCode 特定的枚举结果

* @param data 数据对象

* @return 请求结果

*/

public static AjaxResult error(StatusCode statusCode, Object data) {

return new AjaxResult(statusCode.getCode(), statusCode.getMsg(), data);

}

/**

* 返回特定状态描述

*

* @param statusCode 特定的枚举结果

* @return 请求结果

*/

public static AjaxResult error(StatusCode statusCode) {

return new AjaxResult(statusCode.getCode(), statusCode.getMsg(), new HashMap<>(0));

}

}

返回值状态描述对象AjaxStatus

import lombok.Getter;

/**

* 返回值状态与描述

*

* @author fir

*/

@Getter

public enum AjaxStatus implements StatusCode {

/**

* 请求成功

*/

SUCCESS(200, "请求成功"),

/**

* 登录成功

*/

SUCCESS_LOGIN(200, "登录成功"),

/**

* 登出成功

*/

SUCCESS_LOGOUT(200, "登出成功"),

/**

* 启动成功

*/

SUCCESS_FLOW_START(200, "启动成功"),

/**

* 暂无数据

*/

NO_DATA(200, "暂无数据"),

/**

* 错误请求

*/

BAD_REQUEST(400, "错误请求"),

/**

* 登录过期

*/

EXPIRATION_TOKEN(401, "登录过期"),

/**

* 服务不存在

*/

FAILED_SERVICE_DOES(404, "服务不存在"),

/**

* 账号或密码为空

*/

NULL_LOGIN_DATA(480, "账号或密码为空"),

/**

* 建立通信-通信建立失败

*/

FAILED_COMMUNICATION(481, "通信建立失败"),

/**

* 接口不存在

*/

NULL_API(404, "接口不存在"),

/**

* 建立通信-非法请求

*/

ILLEGAL_REQUEST(482, "非法请求"),

/**

* 请求失败

*/

LOSE_EFFICACY(490, "请求失败"),

/**

* 操作失败

*/

LOSE_OPERATION(491, "操作失败"),

/**

* 请求失败

*/

FAILED(500, "请求失败"),

/**

* 服务不可用(gateway网关总定义-所有未定义处理的异常都返回该异常)

*/

SERVICE_UNAVAILABLE(500, "服务不可用"),

/**

* 请求整体加密-无效会话

*/

SESSION_INVALID(601, "无效会话"),

/**

* 请求整体加密-会话过期

*/

SESSION_EXPIRE(602, "会话过期"),

/**

* 防重放校验失败

*/

ANTI_REPLAY_VERIFY_FAILED(701, "防重放校验失败"),

/**

* 防重放校验失败

*/

INTEGRITY_VERIFY_FAILED(801, "完整性校验失败"),

/**

* 预留

*/

PASS(1000, "请求失败");

private final int code;

private final String msg;

AjaxStatus(int code, String msg) {

this.code = code;

this.msg = msg;

}

}

返回值枚举接口层StatusCode

package com.fir.gateway.config.result;

/**

* 返回值枚举接口层

* @author 18714

*/

public interface StatusCode {

/**

* 获取code信息

*

* @return code码

*/

int getCode();

/**

* 获取msg信息

*

* @return msg描述

*/

String getMsg();

}

全局异常处理器

做两步

覆盖默认的异常处理。自定义异常处理。

自定义通用异常

通常的处理过程为抛出异常->全局异常捕捉->返回前端 通常在代码中,对于某个特定的条件,我们抛出一个自定义异常,并携带特定的状态码与状态描述

if (session == null) {

throw new CustomException(AjaxStatus.SESSION_INVALID);

}

而此时,我们在开发环境中通常需要显示堆栈异常,但是生成环境中,大多数是不需要的,此时我们就是用了全局参数配置在自定义异常工具这个类中,我们配置了定义异常默认不打印堆栈异常。

定一个自定义异常

import com.fir.gateway.config.result.AjaxStatus;

import lombok.Getter;

/**

* 自定义通用异常

* 抛出异常->全局异常捕捉->返回前端

*

* @author fir

*/

@Getter

public class CustomException extends RuntimeException {

/**

* code状态码

*/

private final int code;

/**

* 错误状态码

*/

private final AjaxStatus ajaxStatus;

public CustomException(AjaxStatus ajaxStatus) {

super(ajaxStatus.getMsg());

this.code = ajaxStatus.getCode();

this.ajaxStatus = ajaxStatus;

}

}

覆盖默认的异常处理

此时我们覆盖默认的异常处理,并使用自定义的异常处理工具JsonExceptionHandler。

import org.springframework.beans.factory.ObjectProvider;

import org.springframework.boot.autoconfigure.web.ServerProperties;

import org.springframework.boot.autoconfigure.web.WebProperties;

import org.springframework.boot.context.properties.EnableConfigurationProperties;

import org.springframework.boot.web.reactive.error.ErrorAttributes;

import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;

import org.springframework.context.ApplicationContext;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import org.springframework.http.codec.ServerCodecConfigurer;

import org.springframework.web.reactive.result.view.ViewResolver;

import java.util.Collections;

import java.util.List;

/**

* 覆盖默认的异常处理

* @author fir

*/

@Configuration

@EnableConfigurationProperties({ServerProperties.class, WebProperties.class})

public class ErrorHandlerConfiguration {

private final ServerProperties serverProperties;

private final ApplicationContext applicationContext;

private final WebProperties webProperties;

private final List viewResolvers;

private final ServerCodecConfigurer serverCodecConfigurer;

public ErrorHandlerConfiguration(ServerProperties serverProperties,

WebProperties webProperties,

ObjectProvider> viewResolversProvider,

ServerCodecConfigurer serverCodecConfigurer,

ApplicationContext applicationContext) {

this.serverProperties = serverProperties;

this.applicationContext = applicationContext;

this.webProperties = webProperties;

this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);

this.serverCodecConfigurer = serverCodecConfigurer;

}

@Bean

@Order(Ordered.HIGHEST_PRECEDENCE)

public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {

JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(

errorAttributes,

this.webProperties,

this.serverProperties.getError(),

this.applicationContext);

exceptionHandler.setViewResolvers(this.viewResolvers);

exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());

exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());

return exceptionHandler;

}

}

自定义异常处理工具

解决三个问题

处理自定义异常处理不存在的接口对于其他的异常,统一返回一个指定的错误描述AjaxStatus.SERVICE_UNAVAILABLE。

package com.fir.gateway.config.exception;

import com.fir.gateway.config.GlobalConfig;

import com.fir.gateway.config.result.AjaxResult;

import com.fir.gateway.config.result.AjaxStatus;

import lombok.extern.slf4j.Slf4j;

import org.springframework.boot.autoconfigure.web.ErrorProperties;

import org.springframework.boot.autoconfigure.web.WebProperties;

import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;

import org.springframework.boot.web.reactive.error.ErrorAttributes;

import org.springframework.context.ApplicationContext;

import org.springframework.http.MediaType;

import org.springframework.web.reactive.function.BodyInserters;

import org.springframework.web.reactive.function.server.ServerRequest;

import org.springframework.web.reactive.function.server.ServerResponse;

import reactor.core.publisher.Mono;

import javax.annotation.Resource;

/**

* 自定义异常处理工具

* 异常时用JSON代替HTML异常信息

*

* @author fir

*/

@Slf4j

public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {

/**

* 网关参数配置

*/

@Resource

private GlobalConfig globalConfig;

public JsonExceptionHandler(ErrorAttributes errorAttributes, WebProperties webProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {

super(errorAttributes, webProperties.getResources(), errorProperties, applicationContext);

log.info(String.valueOf(errorProperties));

log.info(String.valueOf(errorAttributes));

}

/**

* 重构方法,设置返回属性格式

*/

@Override

protected Mono renderErrorResponse(ServerRequest request) {

Throwable errorThrowable = getError(request);

// 自定义异常默认不打印堆栈异常

// 决定是否打印堆栈异常

boolean printStackTrace = globalConfig.isPrintStackTrace();

if (printStackTrace) {

errorThrowable.printStackTrace();

}

// 打印全局异常

log.error(errorThrowable.getMessage());

Class errorClass = errorThrowable.getClass();

String simpleName = errorClass.getSimpleName();

AjaxStatus ajaxStatus;

switch (simpleName) {

case "CustomException":

// 处理自定义异常

CustomException customException = (CustomException) errorThrowable;

ajaxStatus = customException.getAjaxStatus();

break;

case "NotFoundException":

case "ResponseStatusException":

// 处理404

ajaxStatus = AjaxStatus.NULL_API;

break;

default:

// 统一返回一个服务错误描述

ajaxStatus = AjaxStatus.SERVICE_UNAVAILABLE;

break;

}

AjaxResult result = AjaxResult.error(ajaxStatus);

return ServerResponse.status(200).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(result));

}

}

文章来源

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: