Spring Boot全局异常处理------基于控制器异常转发实现

基于Spring Boot控制器异常转发实现的全局异常处理

1、原理

在Spring Boot项目中所有控制器出现的异常都会默认交由/error来处理,所以我们可以将/error映射到指定的控制器来处理Spring Boot项目的所有控制器异常。继承org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController类并编写相关逻辑代码即可。

2、系统状态枚举类

package com.drsanjun.enums;

/**
 * 服务器状态枚举
 * 
 * @author dyw
 * @date 2019年9月25日
 */
public enum SystemStatusEnum {
	SUCCEED(0, "成功"), UN_SUCCEED(1, "失败");
	/** 枚举键 */
	private final Integer key;
	/** 枚举值 */
	private final String value;

	private SystemStatusEnum(Integer key, String value) {
		this.key = key;
		this.value = value;
	}

	public Integer getStatue() {
		return key;
	}

	public String getValue() {
		return value;
	}
}

2、统一接口返回对象

package com.drsanjun.pojo.bean;

import java.io.Serializable;
import com.drsanjun.enums.SystemStatusEnum;


/**
 * RESTful接口消息传送实体
 * 
 * @author dyw
 * @date 2019年6月15日
 */
public class Message implements Serializable {
	private static final long serialVersionUID = 2524200426257142759L;
	/** 状态码 */
	private Integer statue;
	/** 消息 */
	private String message;
	/** 数据 */
	private Object data;

	private Message() {
	}

	private Message(Integer statue, String message) {
		this.statue = statue;
		this.message = message;
	}

	private Message(Integer statue, String message, Object data) {
		this.statue = statue;
		this.message = message;
		this.data = data;
	}

	private Message(SystemStatusEnum statusEnum) {
		this.statue = statusEnum.getStatue();
		this.message = statusEnum.getValue();
	}

	private Message(SystemStatusEnum statusEnum, Object data) {
		this.statue = statusEnum.getStatue();
		this.message = statusEnum.getValue();
		this.data = data;
	}

	/**
	 * 返回成功状态
	 * 
	 * @return
	 */
	public static Message success() {
		return new Message(SystemStatusEnum.SUCCEED);
	}

	/**
	 * 返回成功状态,自定义提示消息
	 * 
	 * @return
	 */
	public static Message success(String message) {
		return new Message(SystemStatusEnum.SUCCEED.getStatue(), message);
	}

	/**
	 * 返回成功状态,包含数据
	 * 
	 * @return
	 */
	public static Message success(Object data) {
		return new Message(SystemStatusEnum.SUCCEED, data);
	}

	/**
	 * 返回失败状态
	 * 
	 * @return
	 */
	public static Message failure() {
		return new Message(SystemStatusEnum.UN_SUCCEED);
	}

	/**
	 * 返回失败状态,自定义提示消息
	 * 
	 * @return
	 */
	public static Message failure(String message) {
		return new Message(SystemStatusEnum.UN_SUCCEED.getStatue(), message);
	}

	/**
	 * 返回失败状态,包含数据
	 * 
	 * @return
	 */
	public static Message failure(Object data) {
		return new Message(SystemStatusEnum.UN_SUCCEED, data);
	}

	/**
	 * 完全自定义
	 * 
	 * @return
	 */
	public static Message message(Integer statue, String message, Object data) {
		return new Message(statue, message, data);
	}

	public Integer getStatue() {
		return statue;
	}

	public void setStatue(Integer statue) {
		this.statue = statue;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	}

	@Override
	public String toString() {
		return "Message {statue=" + statue + ", message=" + message + ", data=" + data + "}";
	}
}

3、全局异常处理控制器

package com.drsanjun.controller;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.drsanjun.enums.SystemStatusEnum;
import com.drsanjun.pojo.bean.Message;

/**
 * 全局通用异常处理控制器
 * 
 * @author dyw
 * @date 2019年9月28日
 */
@RestController
public class ErrorController extends AbstractErrorController {
	protected Logger logger = LoggerFactory.getLogger(getClass());

	public ErrorController() {
		super(new DefaultErrorAttributes());
	}

	/**
	 * 所有控制器异常后到会转发到此接口
	 */
	@Override
	public String getErrorPath() {
		return null;
	}

	/**
	 * 异常处理接口
	 * 
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping("/error")
	public Message error(HttpServletRequest request, HttpServletResponse response) {
		Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, false));
		/**
		 * 获取异常、HTTP状态码、异常类名
		 */
		Throwable cause = getCause(request);
		int httpStatus = (Integer) model.get("status");
		String errorClassName = cause.getClass().getName();
		/**
		 * 获取错误信息
		 */
		String errorMessage = (String) model.get("message");
		/**
		 * 获取友好提示信息
		 */
		String friendlyMessage = getFriendlyMessage(cause);
		/**
		 * 设置HTTP状态码
		 */
		response.setStatus(httpStatus);
		/**
		 * 封装返回数据
		 */
		Map<String, Object> resultMap = new HashMap<String, Object>();
		resultMap.put("errorMessage", errorMessage);
		resultMap.put("errorClassName", errorClassName);
		logger.info(httpStatus + "," + errorMessage, cause);
		return Message.message(SystemStatusEnum.UN_SUCCEED.getStatue(), friendlyMessage, resultMap);
	}

	/**
	 * 将包装后的异常还原成实际异常类型
	 * 
	 * @param request
	 * @return
	 */
	protected Throwable getCause(HttpServletRequest request) {
		Throwable error = (Throwable) request.getAttribute("javax.servlet.error.exception");
		if (error != null) {
			while (error instanceof ServletException && error.getCause() != null) {
				error = ((ServletException) error).getCause();
			}
		}
		return error;
	}

	/**
	 * 这里指定友好提示信息
	 * 
	 * @param cause
	 * @return
	 */
	protected String getFriendlyMessage(Throwable cause) {
		// 你还可以通过异常类型判断需要提示的信息,具体的细化控制可指定实现
		return "系统异常,请联系管理员";
	}
}

附一个Spring Boot框架默认的异常处理类

/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure.web.servlet.error;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ErrorProperties.IncludeStacktrace;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * Basic global error {@link Controller}, rendering {@link ErrorAttributes}. More specific
 * errors can be handled either using Spring MVC abstractions (e.g.
 * {@code @ExceptionHandler}) or by adding servlet
 * {@link AbstractServletWebServerFactory#setErrorPages server error pages}.
 *
 * @author Dave Syer
 * @author Phillip Webb
 * @author Michael Stummvoll
 * @author Stephane Nicoll
 * @since 1.0.0
 * @see ErrorAttributes
 * @see ErrorProperties
 */
@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController {

	private final ErrorProperties errorProperties;

	/**
	 * Create a new {@link BasicErrorController} instance.
	 * @param errorAttributes the error attributes
	 * @param errorProperties configuration properties
	 */
	public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) {
		this(errorAttributes, errorProperties, Collections.emptyList());
	}

	/**
	 * Create a new {@link BasicErrorController} instance.
	 * @param errorAttributes the error attributes
	 * @param errorProperties configuration properties
	 * @param errorViewResolvers error view resolvers
	 */
	public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties,
			List<ErrorViewResolver> errorViewResolvers) {
		super(errorAttributes, errorViewResolvers);
		Assert.notNull(errorProperties, "ErrorProperties must not be null");
		this.errorProperties = errorProperties;
	}

	@Override
	public String getErrorPath() {
		return this.errorProperties.getPath();
	}

	@RequestMapping(produces = MediaType.TEXT_HTML_VALUE)
	public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
		HttpStatus status = getStatus(request);
		Map<String, Object> model = Collections
				.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));
		response.setStatus(status.value());
		ModelAndView modelAndView = resolveErrorView(request, response, status, model);
		return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
	}

	@RequestMapping
	public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
		Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
		HttpStatus status = getStatus(request);
		return new ResponseEntity<>(body, status);
	}

	/**
	 * Determine if the stacktrace attribute should be included.
	 * @param request the source request
	 * @param produces the media type produced (or {@code MediaType.ALL})
	 * @return if the stacktrace attribute should be included
	 */
	protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {
		IncludeStacktrace include = getErrorProperties().getIncludeStacktrace();
		if (include == IncludeStacktrace.ALWAYS) {
			return true;
		}
		if (include == IncludeStacktrace.ON_TRACE_PARAM) {
			return getTraceParameter(request);
		}
		return false;
	}

	/**
	 * Provide access to the error properties.
	 * @return the error properties
	 */
	protected ErrorProperties getErrorProperties() {
		return this.errorProperties;
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豢龙先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值