leftso 1786 0 2019-08-22 09:23:16

文章位置:左搜> 编程技术> 正文
           Spring boot/mvc项目中通过@RestControllerAdvice或者@ControllerAdvice配合@ExceptionHandler实现全局异常统一处理。

       在spring web项目开发中,我们经常会遇到各种exception,这些exception根据业务或者场景不同抛出不同的信息和返回类型,有的exception需要返回json数据格式的错误,有的exception又需要跳转到某个错误页面。这里将会讲解常见的几个exception统一处理。


通过注解@RestControllerAdvice统一处理rest接口的异常信息。

注意@RestControllerAdvice注解一般在spring boot接口项目中使用。spring普通项目也支持不过需要高版本的spring才有@RestControllerAdvice注解标签。

Java代码:
import com.leftso.business.response.Result;
import com.leftso.system.exception.BusinessException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class RestExceptionHandler {

    @ExceptionHandler(value = { BusinessException.class })
    public Result business(BusinessException ex) {
        return Result.fail("业务异常:"+ex.getMessage());
    }

    @ExceptionHandler(value = { MethodArgumentNotValidException.class })
    public Result methodArgumentNotValidException(MethodArgumentNotValidException ex) {
        String field=ex.getBindingResult().getFieldError().getField().replace("parameter.","");
        String message=ex.getBindingResult().getFieldError().getDefaultMessage();
        return Result.fail("验证失败:字段["+field+"]"+message);
    }

    @ExceptionHandler(value = { Exception.class })
    public Result exception(Exception ex) {
        return Result.fail("系统异常:"+ex.getMessage());
    }
}

通过注解@ControllerAdvice统一处理异常

import com.leftso.common.http.result.ResultJson;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = {BusinessException.class})
    @ResponseBody
    public ResultJson business(BusinessException ex) {
        return ResultJson.fail("业务异常:" + ex.getMessage());
    }


    @ExceptionHandler(value = {Exception.class})
    public ModelAndView exception(Exception ex, HttpServletRequest request, HttpServletResponse response) {
        String uri = request.getRequestURI();
        ModelAndView modelAndView = new ModelAndView();
        if (uri.contains("enterprise")) {
            MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
            modelAndView.setView(jsonView);
            modelAndView.addObject(ResultJson.fail("系统异常:" + ex.getMessage()));
            return modelAndView;
        } else {
            RedirectView redirectView = new RedirectView("/static/error/500.jsp");
            redirectView.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            modelAndView.setView(redirectView);
            return modelAndView;
        }
    }
}

某些情况我们需要根据请求类型返回不同得view,比如ajax请求返回JSON数据,普通请求返回页面数据,
 
import com.alibaba.fastjson.JSON;
import net.ifok.common.utils.MapUtil;
import net.ifok.ocms.system.exception.BusinessException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.AccessDeniedException;
import java.util.List;

@ControllerAdvice
public class ControllerExceptionHandler {

	/**
	 * 业务异常
	 * 
	 * @param
	 * @param e
	 * @return
	 * @throws IntrospectionException
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 */
	@ResponseBody
	@ExceptionHandler(value = { BusinessException.class ,RuntimeException.class})
	public ModelAndView businessExceptionHandler(HttpServletRequest request, BusinessException e)
			throws IllegalAccessException, InvocationTargetException, IntrospectionException {
		Log.error("业务异常:" + e.getMessage(),e, getClass());
		String uri = request.getRequestURI();
		boolean isJsonRequest =isAjaxRequest(request);
		if (isJsonRequest) {
			ModelAndView view = new ModelAndView();
			MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
			jsonView.setAttributesMap(MapUtil.toMap(Result.fail(e.getMessage())));
			view.setView(jsonView);
			return view;
		} else {
			ModelAndView view = new ModelAndView();
			view.setViewName("redirect:/503.html");
			return view;
		}
	}

	@ExceptionHandler(value = { MethodArgumentNotValidException.class})
	public ModelAndView methodArgumentNotValidExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e){
		String message=e.getBindingResult().getFieldError().getDefaultMessage();
		Log.error("验证失败:" +message,e, getClass());
		boolean isJsonRequest =isAjaxRequest(request);
		if (isJsonRequest) {
			ModelAndView view = new ModelAndView();
			MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
			jsonView.setAttributesMap(JSON.parseObject(JSON.toJSONString(Result.fail(message))));
			view.setView(jsonView);
			return view;
		} else {
			ModelAndView view = new ModelAndView();
			view.setViewName("redirect:/503.html");
			return view;
		}
	}


	@ExceptionHandler(value = { HttpRequestMethodNotSupportedException.class })
	public ModelAndView methodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException e){
		Log.error("HttpRequestMethodNotSupportedException:请求方法不支持:"+e.getMethod()+"\n请求地址:"
				+request.getRequestURI()+"\n UA:\n" + request.getHeader("User-Agent"),getClass());
		boolean isJsonRequest =isAjaxRequest(request);
		if (isJsonRequest) {
			ModelAndView view = new ModelAndView();
			MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
			jsonView.setAttributesMap(JSON.parseObject(JSON.toJSONString(Result.fail("请求方式["+e.getMethod()+"]不支持"))));
			view.setView(jsonView);
			return view;
		} else {
			ModelAndView view = new ModelAndView();
			view.setViewName("redirect:/404.html");
			return view;
		}
	}




	@ExceptionHandler(value = { AccessDeniedException.class })
	public ModelAndView accessDeniedException(HttpServletRequest request, AccessDeniedException e) {
		Log.error("权限不足->\n资源地址:" + request.getRequestURI() + "\n UA:\n" + request.getHeader("User-Agent"),
				this.getClass());
		boolean isJsonRequest=isAjaxRequest(request);
		if (isJsonRequest) {
			ModelAndView view = new ModelAndView();
			MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
			jsonView.setAttributesMap(JSON.parseObject(JSON.toJSONString(Result.fail(e.getMessage()))));
			view.setView(jsonView);
			return view;
		} else {
			ModelAndView view = new ModelAndView();
			view.setViewName("redirect:/403.html");
			return view;
		}
	}

	@ExceptionHandler(value = { Exception.class })
	public ModelAndView exceptionHandler(HttpServletRequest reqeust, Exception e) {
		Log.error(e.getMessage(), e, getClass());
		boolean isJsonRequest =isAjaxRequest(reqeust);
		if (isJsonRequest) {
			ModelAndView view = new ModelAndView();
			MappingJackson2JsonView jsonView = new MappingJackson2JsonView();
			jsonView.setAttributesMap(JSON.parseObject(JSON.toJSONString(Result.fail(e.getMessage()))));
			view.setView(jsonView);
			return view;
		} else {
			ModelAndView view = new ModelAndView();
			view.setViewName("redirect:/503.html");
			return view;
		}
	}
	public static boolean isAjaxRequest(HttpServletRequest request) {
		String requestedWith = request.getHeader("x-requested-with");
		if (requestedWith != null && requestedWith.equalsIgnoreCase("XMLHttpRequest")) {
			return true;
		} else {
			return false;
		}
	}
}