文档章节

关于SpringMVC的异常中心DefaultExceptionHandler

nonnetta
 nonnetta
发布于 2017/01/23 14:56
字数 1056
阅读 44
收藏 2

在服务端经常会遇到需要手动的抛出异常,比如业务系统,校验异常,比较通用的处理方案是在最顶层进行拦截异常,例如Struts的全局异常处理,而Spring的异常处理机制就相对于Struts来说好用多了。

 

第一种:配置式

<!-- 基于配置文件式的异常处理 -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
    <property name="exceptionMappings">  
        <props>  
            <prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop>
            <prop key="com.sirdc.modules.exceptions.ServiceException">error/503</prop>
        </props>  
    </property>  
</bean>

 

第二种:注解式

<!-- 基于注解式子的异常处理 -->
<bean id="exceptionHandlerExceptionResolver" 
class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver"></bean>

然后在后端采用@ControllerAdvice注解进行全局处理。

import com.sirdc.modules.exceptions.ServiceException;
import com.sirdc.modules.validator.BeanValidators;
import com.sirdc.modules.web.model.Message;
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.context.request.NativeWebRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.validation.ConstraintViolationException;
import java.util.List;

/**
 * 自定义统一异常处理中心
 *
 * @version Revision: 0.0.1
 * @author: weihuang.peng
 * @Date: 2015年1月17日
 */
@ControllerAdvice
public class DefaultExceptionHandler {

    /**
     * 处理业务异常
     *
     * @param request
     * @param model
     * @param exception
     * @return Model
     */
    @ExceptionHandler({ServiceException.class})
    public ModelAndView processServiceException(NativeWebRequest request, ServiceException exception) {
        ModelAndView model = new ModelAndView("/error/503");
        model.addObject("exception", exception);
        model.addObject("message", "服务器未能处理您的请求");
        return model;
    }

    /**
     * 处理校验异常
     *
     * @param request
     * @param exception
     * @return
     */
    @ExceptionHandler({ConstraintViolationException.class})
    @ResponseBody
    public Message processConstraintViolationException(NativeWebRequest request, ConstraintViolationException exception) {
        exception.printStackTrace();
        List<String> list = BeanValidators.extractPropertyAndMessageAsList(exception, ": ");
        list.add(0, "数据验证失败:");
        return handleMessage(list.toArray(new String[]{}));
    }

    @ExceptionHandler({Exception.class})
    public ModelAndView processException(NativeWebRequest request, Exception exception) {
        exception.printStackTrace();
        ModelAndView model = new ModelAndView("/error/500");
        model.addObject("exception", exception);
        model.addObject("message", "服务器出错了");
        return model;
    }

    /**
     * 添加Flash消息
     *
     * @param messages 消息
     * @return
     */
    protected Message handleMessage(String... messages) {
        Message model = new Message();
        StringBuilder sb = new StringBuilder();
        for (String message : messages) {
            sb.append(message).append(messages.length > 1 ? "<br/>" : "");
        }
        model.setCode("500");
        model.setMessage(sb.toString());
        return model;
    }
}

 

在DefaultExceptionHandler中使用了BeanValidators,代码如下。

import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * <pre>
 * JSR303 Validator(Hibernate Validator)工具类.
 * JSR 303 – Bean Validation 是一个数据验证的规范.
 * 
 * validate(Object)的返回值是Set,每一个ConstraintViolation包含了出错的
 * message和propertyPath、InvalidValue, 不同场景有不同的显示需求,国际化在propertyPath的i18N翻译上.	
 * ConstraintViolation中包含propertyPath, message 和invalidValue等信息.
 * 提供了各种convert方法,适合不同的i18n需求:
 * 1. List<String>, String内容为message
 * 2. List<String>, String内容为propertyPath + separator + message
 * 3. Map<propertyPath, message>
 * 
 * 详情见wiki: http://hibernate.org/subprojects/validator/docs/
 * </pre>
 * 
 * @author HaiYan
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class BeanValidators {

	/**
	 * 调用JSR303的validate方法, 验证失败时抛出ConstraintViolationException,
	 * 而不是返回constraintViolations.
	 */
	public static void validateWithException(Validator validator,
			Object object, Class<?>... groups)
			throws ConstraintViolationException {
		Set constraintViolations = validator.validate(object, groups);
		if (!constraintViolations.isEmpty()) {
			throw new ConstraintViolationException(constraintViolations);
		}
	}

	/**
	 * 转换ConstraintViolationException中的Set<ConstraintViolations>中为List<message>.
	 * 
	 * @param e
	 *            ConstraintViolationException
	 * @return List<String>, String内容为message
	 */
	public static List<String> extractMessage(ConstraintViolationException e) {
		return extractMessage(e.getConstraintViolations());
	}

	/**
	 * 转换Set<ConstraintViolation>为List<message>.
	 * 
	 * @param constraintViolations
	 * @return List<String>, String内容为message
	 */
	public static List<String> extractMessage(
			Set<? extends ConstraintViolation> constraintViolations) {
		List<String> errorMessages = Lists.newArrayList();
		for (ConstraintViolation violation : constraintViolations) {
			errorMessages.add(violation.getMessage());
		}
		return errorMessages;
	}

	/**
	 * 转换ConstraintViolationException中的Set<ConstraintViolations>为Map<property,
	 * message>.
	 * 
	 * @param e
	 *            ConstraintViolationException
	 * @return Map<String, String> key=propertyPath,value=message
	 */
	public static Map<String, String> extractPropertyAndMessage(
			ConstraintViolationException e) {
		return extractPropertyAndMessage(e.getConstraintViolations());
	}

	/**
	 * 转换Set<ConstraintViolation>为Map<property, message>.
	 * 
	 * @param e
	 *            ConstraintViolationException
	 * @return Map<String, String> key=propertyPath,value=message
	 */
	public static Map<String, String> extractPropertyAndMessage(
			Set<? extends ConstraintViolation> constraintViolations) {
		Map<String, String> errorMessages = Maps.newHashMap();
		for (ConstraintViolation violation : constraintViolations) {
			errorMessages.put(violation.getPropertyPath().toString(),
					violation.getMessage());
		}
		return errorMessages;
	}

	/**
	 * 转换ConstraintViolationException中的Set<ConstraintViolations>为List<
	 * propertyPath message>.
	 * 
	 * @param e
	 *            ConstraintViolationException
	 * @return List<String>, String内容为propertyPath + separator + message
	 */
	public static List<String> extractPropertyAndMessageAsList(
			ConstraintViolationException e) {
		return extractPropertyAndMessageAsList(e.getConstraintViolations(), " ");
	}

	/**
	 * 转换ConstraintViolationException的Set<ConstraintViolations>为List<
	 * propertyPath + separator + message>.
	 * 
	 * @param e
	 *            ConstraintViolationException
	 * @param separator
	 *            分隔符
	 * @return List<String>, String内容为propertyPath + separator + message
	 */
	public static List<String> extractPropertyAndMessageAsList(
			ConstraintViolationException e, String separator) {
		return extractPropertyAndMessageAsList(e.getConstraintViolations(),
				separator);
	}

	/**
	 * 转换Set<ConstraintViolations>为List<propertyPath message>.
	 * 
	 * @param constraintViolations
	 * @return List<String>, String内容为propertyPath + separator + message
	 */
	public static List<String> extractPropertyAndMessageAsList(
			Set<? extends ConstraintViolation> constraintViolations) {
		return extractPropertyAndMessageAsList(constraintViolations, " ");
	}

	/**
	 * 转换Set<ConstraintViolation>为List<propertyPath + separator + message>.
	 * 
	 * @param e
	 *            ConstraintViolationException
	 * @return List<String>, String内容为propertyPath + separator + message
	 */
	public static List<String> extractPropertyAndMessageAsList(
			Set<? extends ConstraintViolation> constraintViolations,
			String separator) {
		List<String> errorMessages = Lists.newArrayList();
		for (ConstraintViolation violation : constraintViolations) {
			errorMessages.add(violation.getPropertyPath() + separator
					+ violation.getMessage());
		}
		return errorMessages;
	}
}

 

Message对象:

import java.io.Serializable;

/**
 * 
 * @author: weihuang.peng
 * @version Revision: 0.0.1
 * @Date: 2015年1月21日
 */
public class Message implements Serializable {

	private static final long serialVersionUID = 1769341992221383236L;

	private String code;
	
	private String message;
	
	private Object data;
	
	/**
	 * @author: weihuang.peng
	 * @return the data
	 */
	public Object getData() {
		return data;
	}

	/**
	 * @author: weihuang.peng
	 * @param data the data to set
	 */
	public void setData(Object data) {
		this.data = data;
	}

	/**
	 * @return the code
	 */
	public String getCode() {
		return code;
	}

	/**
	 * @param code the code to set
	 */
	public void setCode(String code) {
		this.code = code;
	}

	/**
	 * @return the message
	 */
	public String getMessage() {
		return message;
	}

	/**
	 * @param message the message to set
	 */
	public void setMessage(String message) {
		this.message = message;
	}
}

 

© 著作权归作者所有

nonnetta
粉丝 7
博文 9
码字总数 8465
作品 0
厦门
高级程序员
私信 提问
加载中

评论(2)

nonnetta
nonnetta 博主

引用来自“12叔”的评论

有个问题验证失败 返回的都是相同的异常。。只能通过message区分 错误么。。
正常情况下,我们返回的某一错误类型都会拥有同一个错误码,而差异就在这个message中。
12叔
12叔
有个问题验证失败 返回的都是相同的异常。。只能通过message区分 错误么。。
Spring Framework 5.1.5 发布,Bug 修复和改进

Spring Framework 最新版本 5.1.5 已发布,该维护版包含了总计超过 40 项的 bug 修复和改进。 下面简单介绍一下值得关注的新变化: 对于无效的赋值,SpringEL 不应抛出 IllegalAccessError 异...

局长
02/14
1K
0
Archx/spring-agg

#SPRING-AGG 这个一个框架整合案列,包含 SpringMVC/MyBatis/Apache Shiro 。 演示数据 演示数据请导入 db.sql 演示账号密码均为 SpringMVC 配置 演示项目使用的是 RESTful 风格,不是传统的...

Archx
2015/01/12
0
0
Spring Boot学习笔记-错误处理及自定义

正常的Web应用开发时,需要考虑到应用运行发生异常时或出现错误时如何来被处理,例如捕获必要的异常信息,记录日志方便日后排错,友好的用户响应输出等等。 当然应用发生错误,有可能是应用自...

chace0120
2015/12/31
6.3K
0
[springboot](十三)spring boot admin 监控集群

版权声明:本文为博主原创文章,未经博主允许不得转载。有任何问题请邮件联系ashuo.com@qq.com https://blog.csdn.net/drdongshiye/article/details/82808083 参考https://www.cnblogs.com/i...

菜鸟腾飞
2018/09/21
0
0
Java程序员从笨鸟到菜鸟之(七十四)细谈Spring(六)spring之AOP基本概念和配置详解

首先我们来看一下官方文档所给我们的关于AOP的一些概念性词语的解释: 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的...

长平狐
2012/11/12
162
0

没有更多内容

加载失败,请刷新页面

加载更多

SSH安全加强两步走

从 OpenSSH 6.2 开始已经支持 SSH 多因素认证,本文就来讲讲如何在 OpenSSH 下启用该特性。 OpenSSH 6.2 以后的版本多了一个配置项 AuthenticationMethods。该配置项可以让 OpenSSH 同时指定...

xiangyunyan
30分钟前
4
0
C或C++不是C/C++

http://www.voidcn.com/article/p-mucdruqa-ws.html

shzwork
今天
6
0
OSChina 周六乱弹 —— 如何将梳子卖给和尚

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @for_ :划水五分钟,专注两小时。分享Various Artists的单曲《贝多芬第8号钢琴奏鸣曲悲伤的第三乐章》: 《贝多芬第8号钢琴奏鸣曲悲伤的第三乐...

小小编辑
今天
191
8
ES5

什么是ES5:比普通js运行要求更加严格的模式 为什么:js语言本身有很多广受诟病的缺陷 如何:在当前作用域的顶部添加:"use strict" 要求: 1、禁止给未声明的变量赋值 2、静默失败升级为错误...

wytao1995
今天
7
0
c++ 内联函数调用快的原因

见图片分析

天王盖地虎626
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部