spring MVC 统一异常处理支持页面 JSON

资料来源于:http://blog.csdn.net/m13321169565/article/details/7641978

在使用web开发和API 开发都使用到异常的处理,web 异常后跳到指定的错误页面,那么API或AJAX调用需要返回JSON的错误信息,所以我们需要一个统一的异常处理机制来管理这些异常!

1.定义自己的异常处理类

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;

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

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;

/**
 * 不必在Controller中对异常进行处理,抛出即可,由此异常解析器统一控制。<br>
 * ajax请求(有@ResponseBody的Controller)发生错误,输出JSON。<br>
 * 页面请求(无@ResponseBody的Controller)发生错误,输出错误页面。<br>
 * 需要与AnnotationMethodHandlerAdapter使用同一个messageConverters<br>
 * Controller中需要有专门处理异常的方法。
 * 
 * @author dongjian
 * 
 * */
public class AnnotationHandlerMethodExceptionResolver extends ExceptionHandlerExceptionResolver {
	
	private String defaultErrorView;
	
	public String getDefaultErrorView() {
		return defaultErrorView;
	}

	public void setDefaultErrorView(String defaultErrorView) {
		this.defaultErrorView = defaultErrorView;
	}

	/***
	 * 异常后跳转到页面
	 */
	protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
		
		if (handlerMethod == null) {
			return null;
		}
		
		Method method = handlerMethod.getMethod();

		if (method == null) {
			return null;
		}
		
		ModelAndView returnValue = super.doResolveHandlerMethodException(request, response, handlerMethod, exception);
		
		ResponseBody responseBodyAnn = AnnotationUtils.findAnnotation(method, ResponseBody.class);
		if (responseBodyAnn != null) {
			try {
				ResponseStatus responseStatusAnn = AnnotationUtils.findAnnotation(method, ResponseStatus.class);
				if (responseStatusAnn != null) {
					HttpStatus responseStatus = responseStatusAnn.value();
					String reason = responseStatusAnn.reason();
					if (!StringUtils.hasText(reason)) {
						response.setStatus(responseStatus.value());
					} else {
						try {
							response.sendError(responseStatus.value(), reason);
						} catch (IOException e) { }
					}
				}
			
				return handleResponseBody(returnValue, request, response);
			} catch (Exception e) {
				return null;
			}
		}
		
		if(returnValue.getViewName() == null){
			returnValue.setViewName(defaultErrorView);
		}
		
		return returnValue;
		
	}
	
	
	/**
	 * 异常后 返回json
	 * @param returnValue
	 * @param request
	 * @param response
	 * @return
	 * @throws ServletException
	 * @throws IOException
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private ModelAndView handleResponseBody(ModelAndView returnValue, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Map value = returnValue.getModelMap();
		HttpInputMessage inputMessage = new ServletServerHttpRequest(request);
		List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept();
		if (acceptedMediaTypes.isEmpty()) {
			acceptedMediaTypes = Collections.singletonList(MediaType.ALL);
		}
		MediaType.sortByQualityValue(acceptedMediaTypes);
		HttpOutputMessage outputMessage = new ServletServerHttpResponse(response);
		Class<?> returnValueType = value.getClass();
		List<HttpMessageConverter<?>> messageConverters = super.getMessageConverters();
		if (messageConverters != null) {
			for (MediaType acceptedMediaType : acceptedMediaTypes) {
				for (HttpMessageConverter messageConverter : messageConverters) {
					if (messageConverter.canWrite(returnValueType, acceptedMediaType)) {
						messageConverter.write(value, acceptedMediaType, outputMessage);
						return new ModelAndView();
					}
				}
			}
		}
		if (logger.isWarnEnabled()) {
			logger.warn("Could not find HttpMessageConverter that supports return type [" + returnValueType + "] and " + acceptedMediaTypes);
		}
		return null;
	}

}

 2.在spring MVC 配置中添加如下配置

 	<!--  ResponseBody 的类型 -->
	<bean
		id="messageConverters" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
			 <property name="supportedMediaTypes">
				 <list>
					 <value>application/json;charset=UTF-8</value>
				 </list>
			 </property>
	 </bean>
 
	
	<bean id="handlerAdapter"
		class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
		<property name="cacheSeconds" value="0" />
		<property name="messageConverters" ref="messageConverters" />
	</bean>
	
	<!-- 设置自定义异常处理 -->
    <bean id="handlerExceptionResolver" class="com.chengkun.base.exception.AnnotationHandlerMethodExceptionResolver">
		<property name="defaultErrorView" value="error.jsp"/><!-- 错误页面 -->
		<property name="messageConverters" ref="messageConverters"/> <!--JSON 处理的messageConverters->
	</bean>

 3.修改web.xml 禁止自动注册,让其使用我们自定义的类

<servlet>
		<servlet-name>spring-mvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring/spring-mvc.xml</param-value>
		</init-param>
		
		<!-- 取消其自动注册的异常解析器 -->
		<init-param>
			<param-name>detectAllHandlerExceptionResolvers</param-name>
			<param-value>false</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

 4.在BaseController 中加入异常控制,所有controller必须继承BaseController

/**
	* 异常控制,可以根据不同的异常类型 在此定义不同的错误消息和操作
	* */
	@ExceptionHandler(Exception.class)
	@ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
	public ModelAndView handleException(Exception ex, HttpServletRequest request) {
		return new ModelAndView().addObject(new ResultPojo(500));
	}

 

 

 

扫描二维码关注公众号,回复: 498536 查看本文章

猜你喜欢

转载自jay-c-k.iteye.com/blog/2216957