springboot 配置全局異常攔截

如今開發工做中,大部分都是用Restful風格,Java作後臺邏輯接口,iOS、Android、H5調用,在配置全局異常以前,有不少自定義業務異常和RuntimeException都是須要本身在Controller層try catch捕獲的,也就是說,每個方法中都有很冗餘複雜而且沉重的代碼去處理這些異常,爲了解決這個問題,省去不少無聊代碼,節約時間,須要作一個全局的異常攔截處理,就是這篇文章的主題了。java


  • 加全局異常處理以前的代碼
try{
	try{
		return new Result();
	}catch(CoreServiceException e){
		logger.error(e.getMessage, e);
		return new Result();
	}
}cath(Exeption e){
	logger.info(e.getMessage(), e);
	return new Result();
}

這裏爲了避免把不友好的信息返回給前臺,在這裏進行了兩次異常捕獲,內部try catch捕獲自定義業務異常,外部try catch捕獲常常發生的RuntimeException,如NullPointerException等。web


這裏使用的解決方式是用@ControllerAdvice(或者@RestControllerAdvice)註解加@ExceptionHandler註解spring

@ControllerAdvice註解

/*
 * Copyright 2002-2017 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
 *
 *      http://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.web.bind.annotation;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

/**
 * Specialization of {@link Component @Component} for classes that declare
 * {@link ExceptionHandler @ExceptionHandler}, {@link InitBinder @InitBinder}, or
 * {@link ModelAttribute @ModelAttribute} methods to be shared across
 * multiple {@code @Controller} classes.
 *
 * <p>Classes with {@code @ControllerAdvice} can be declared explicitly as Spring
 * beans or auto-detected via classpath scanning. All such beans are sorted via
 * {@link org.springframework.core.annotation.AnnotationAwareOrderComparator
 * AnnotationAwareOrderComparator}, i.e. based on
 * {@link org.springframework.core.annotation.Order @Order} and
 * {@link org.springframework.core.Ordered Ordered}, and applied in that order
 * at runtime. For handling exceptions, an {@code @ExceptionHandler} will be
 * picked on the first advice with a matching exception handler method. For
 * model attributes and {@code InitBinder} initialization, {@code @ModelAttribute}
 * and {@code @InitBinder} methods will also follow {@code @ControllerAdvice} order.
 *
 * <p>Note: For {@code @ExceptionHandler} methods, a root exception match will be
 * preferred to just matching a cause of the current exception, among the handler
 * methods of a particular advice bean. However, a cause match on a higher-priority
 * advice will still be preferred to a any match (whether root or cause level)
 * on a lower-priority advice bean. As a consequence, please declare your primary
 * root exception mappings on a prioritized advice bean with a corresponding order!
 *
 * <p>By default the methods in an {@code @ControllerAdvice} apply globally to
 * all Controllers. Use selectors {@link #annotations()},
 * {@link #basePackageClasses()}, and {@link #basePackages()} (or its alias
 * {@link #value()}) to define a more narrow subset of targeted Controllers.
 * If multiple selectors are declared, OR logic is applied, meaning selected
 * Controllers should match at least one selector. Note that selector checks
 * are performed at runtime and so adding many selectors may negatively impact
 * performance and add complexity.
 *
 * @author Rossen Stoyanchev
 * @author Brian Clozel
 * @author Sam Brannen
 * @since 3.2
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {

	/**
	 * Alias for the {@link #basePackages} attribute.
	 * <p>Allows for more concise annotation declarations e.g.:
	 * {@code @ControllerAdvice("org.my.pkg")} is equivalent to
	 * {@code @ControllerAdvice(basePackages="org.my.pkg")}.
	 * @since 4.0
	 * @see #basePackages()
	 */
	@AliasFor("basePackages")
	String[] value() default {};

	/**
	 * Array of base packages.
	 * <p>Controllers that belong to those base packages or sub-packages thereof
	 * will be included, e.g.: {@code @ControllerAdvice(basePackages="org.my.pkg")}
	 * or {@code @ControllerAdvice(basePackages={"org.my.pkg", "org.my.other.pkg"})}.
	 * <p>{@link #value} is an alias for this attribute, simply allowing for
	 * more concise use of the annotation.
	 * <p>Also consider using {@link #basePackageClasses()} as a type-safe
	 * alternative to String-based package names.
	 * @since 4.0
	 */
	@AliasFor("value")
	String[] basePackages() default {};

	/**
	 * Type-safe alternative to {@link #value()} for specifying the packages
	 * to select Controllers to be assisted by the {@code @ControllerAdvice}
	 * annotated class.
	 * <p>Consider creating a special no-op marker class or interface in each package
	 * that serves no purpose other than being referenced by this attribute.
	 * @since 4.0
	 */
	Class<?>[] basePackageClasses() default {};

	/**
	 * Array of classes.
	 * <p>Controllers that are assignable to at least one of the given types
	 * will be assisted by the {@code @ControllerAdvice} annotated class.
	 * @since 4.0
	 */
	Class<?>[] assignableTypes() default {};

	/**
	 * Array of annotations.
	 * <p>Controllers that are annotated with this/one of those annotation(s)
	 * will be assisted by the {@code @ControllerAdvice} annotated class.
	 * <p>Consider creating a special annotation or use a predefined one,
	 * like {@link RestController @RestController}.
	 * @since 4.0
	 */
	Class<? extends Annotation>[] annotations() default {};

}

這是這個註解的源碼。express

@ControllerAdvice聲明一個控制器建言,@ControllerAdvice組合了@Component註解,因此自動註冊爲Spring的Bean。apache

配置之後,默認會掃描指定包中全部@RequestMapping註解,包含@GetMapping,@PostMapping等。app

配合使用註解

@ExceptionHandler, @ModelAttribute, @InitBinderless

@ExceptionHandleride

@ExceptionHandler在此處定義全局處理,經過@ExceptionHandler的value屬性可過濾攔截的條件,「value = Exception」會默認攔截全部異常,「value = CoreServiceException」會攔截自定義業務異常,也能夠在這個類中配置多個@ExceptionHandler,會默認先攔截業務異常,最後再攔截Exception。ui

package com.shanyuan.exception;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.shanyuan.base.RespResult;

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
	
	public static final String CODE_ERROR = "500";
	
	protected Logger logger = LoggerFactory.getLogger(getClass());
	
	@ExceptionHandler(value = Exception.class)
	public RespResult allExceptionHandel(HttpServletRequest request, Exception e) {
		RespResult result = new RespResult();
		logger.error(e.getMessage(), e);
		result.setMessage("系統錯誤,請聯繫技術小哥哥!");
		return result;
	}
	
	@ExceptionHandler(value = CoreServiceException.class)
	public RespResult coreServiceExceptionHandle(HttpServletRequest request, CoreServiceException e) {
		RespResult result = new RespResult();
		result.setMessage("業務錯誤,請聯繫技術小哥哥!");
		return result;
	}

}

@ModelAttributethis

@ModelAttribute註解將鍵值對添加到全局,全部註解了@RequestMapping的方法可得到此鍵值對。

@InitBinder

經過@InitBinder註解定製WebDataBinder。

  • 在Restful純接口項目中,有@ControllerAdvice和@ExceptionHandler註解就夠了。固然,由於是純接口項目,因此@ResponseBody註解也是必不可少的,並且直接放到類上。若是使用@RestControllerAdvice註解能夠省略這一步,@Controller中,若是使用@RestController也是能夠忽略@ResponseBody註解的。具體緣由不在此多作贅述。

  • 這樣,咱們的接口方法中就不須要作try catch處理了。這個攔截器會在接口被請求的時候自動幫你處理掉你Service層跑出來但未處理的異常,具體異常處理能夠根據你自定義異常返回報文。

相關文章
相關標籤/搜索