springmvc 的异常是挺好用的,可以 作统一的异常拦截,而且可以记录错误异常到日志里面。。
可是 如果 我有时候想 返回错误的json 格式,,,有时候想返回错误的视图,比如 500错误页面,, 怎么控制呢? 肯定不能写两个异常拦截的,,, 今天在 公司的项目里面,发现大神写好了,,,根据请求头判断的,,,也是厉害了。。。 我之前还想着 是否可以 判断返回 对象来判断呢。。。这样的方式挺好的。。。 下面是 实现代码:参考
package com.gwqm.exception;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.druid.support.json.JSONUtils;
import com.gwqm.app.ctrl.base.AppBaseAction;
import com.gwqm.app.enums.common.SuccessEnum;
import com.gwqm.app.exp.AppAuthorityException;
import com.gwqm.app.exp.AppCommonException;
import com.gwqm.base.mv.JModelAndView;
import com.gwqm.base.tools.exception.BaseException;
import com.gwqm.platform.app.enums.AppCommonErrorEnum;
import com.gwqm.platform.service.ISysConfigService;
import com.gwqm.platform.service.IUserConfigService;
/**
* 捕获异常统一处理
*
* @description TODO
* @author liwanhua
* @create date 2017年4月12日
* @modified by
* @modify date
* @version v1.0
*/
@Component
public class GlobalExceptionHandler implements HandlerExceptionResolver {
@Autowired
protected ISysConfigService configService;
@Autowired
protected IUserConfigService userConfigService;
protected static Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
private final static String EXPTION_MSG_KEY = "message";
private final static String EXPTION_SUCC_KEY = "success";
private final static String SELLER = "seller";
private final static String ADMIN = "admin";
private final static String BUYER = "buyer";
@Override
public ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response,Object obj,Exception ex){
ex.printStackTrace();//打印异常,方便问题追踪
logger.info("BaseException handler " + ex.getMessage());
ModelAndView mv = new ModelAndView();
if(!(request.getHeader("accept").indexOf("application/json") > -1 || (request
.getHeader("X-Requested-With") != null && request.getHeader(
"X-Requested-With").indexOf("XMLHttpRequest") > -1))){
//如果不是ajax,jsp格式返回
String url = "";
String requestUrl = request.getRequestURI();
requestUrl = requestUrl.substring(1, requestUrl.indexOf("/",2));
if(ex instanceof BaseException) {
if(requestUrl.toLowerCase().equals(ADMIN)){//管理员统一异常返回
url = "exception/error-admin.html";
}else if(requestUrl.toLowerCase().equals(SELLER)){//卖家统一异常返回
url = "exception/error-seller.html";
}else if(requestUrl.toLowerCase().equals(BUYER)){//买家统一异常返回
url = "exception/error-seller.html";
}else{
url="exception/error-seller.html";
}
}
mv = new JModelAndView(url,
this.configService.getSysConfig(),
this.userConfigService.getUserConfig(), 0, request,
response);
mv.addObject(EXPTION_MSG_KEY, ex.getMessage());
} else {
response.setStatus(HttpStatus.OK.value());
// 设置ContentType
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
// 避免乱码
response.setCharacterEncoding("UTF-8");
response.setHeader("Cache-Control", "no-cache, must-revalidate");
try {
PrintWriter writer = response.getWriter();
Map<String, Object> map = new HashMap<String, Object>();
String header = request.getHeader(AppBaseAction.USER_AGENTS_KEY);
// String headerParam = request.getParameter(AppBaseAction.USER_AGENTS_KEY);
// header = (null != header && !"".equals(header)) ? header : headerParam;
logger.info("获取头部信息:【{}】", header);
if (AppBaseAction.USER_AGENTS_VALUE.equals(header)) {
map.put(AppBaseAction.SUCCESS, SuccessEnum.FAIL.getType());
if (ex instanceof AppAuthorityException) {
map.put(AppBaseAction.ERROR_CODE, ((AppAuthorityException) ex).getType());
map.put(AppBaseAction.ERROR_MSG, ((AppAuthorityException) ex).getMessage());
} else if (ex instanceof AppCommonException) {
map.put(AppBaseAction.ERROR_CODE, ((AppCommonException) ex).getType());
map.put(AppBaseAction.ERROR_MSG, ((AppCommonException) ex).getMessage());
} else {
map.put(AppBaseAction.ERROR_CODE, AppCommonErrorEnum.SYSTEM_ERROR.getType());
map.put(AppBaseAction.ERROR_MSG, AppCommonErrorEnum.SYSTEM_ERROR.getDescpt());
}
} else {
map.put("success", false);
map.put("message", ex.getMessage());
}
writer.write(JSONUtils.toJSONString(map));
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return mv;
}
}
为了处理 json串中文乱码这样在xml里面配置:
<!-- 解决@ExceptionHandler的@ResponseBody中文乱码 -->
<!-- <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
</list>
</property>
</bean> -->
可以有其他的方式来控制中文乱码的通过 response来设置,,,比如 response 输入的时候,设置 utf-8 编码。。。这里就不具体说了。
//这句话的意思,是让浏览器用utf8来解析返回的数据
response.setHeader("Content-type", "text/html;charset=UTF-8");
//这句话的意思,是告诉servlet用UTF-8转码,而不是用默认的ISO8859
response.setCharacterEncoding("UTF-8");
String data = "中国";
PrintWriter pw = response.getWriter();
pw.write(data);
//这句话的意思,是让浏览器用utf8来解析返回的数据
response.setHeader("Content-type", "text/html;charset=UTF-8");
String data = "中国";
OutputStream ps = response.getOutputStream();
//这句话的意思,使得放入流的数据是utf8格式
ps.write(data.getBytes("UTF-8"));
这里有几个小细节需要注意:
- response.setCharacterEncoding("UTF-8");需要写在PrintWriter out = response.getWriter();的前面。拿到字符流后再设置编码是没有用的。
- response.setHeader("content-type", "text/html;charset=UTF-8");有一种更为简单的写法response.setContentType("text/html;charset=UTF-8");。 3.response.setContentType("text/html;charset=UTF-8");这句代码其实有两个作用:通知response以UTF-8输出和浏览器以UTF-8打开。即等价于response.setHeader("content-type", "text/html;charset=UTF-8");和response.setCharacterEncoding("UTF-8");两句代码。 4.通过以上阅读,读者应该能明白为什么response.getOutputStream.write(1);这句代码在浏览器的输出不是1。因为浏览器是一个文本编辑器,收到数据后会拿着1去查码表,然后显示对应字符。想在浏览器输出数字,应该把数字变成字符串,response.getOutputStream.write((1+"").getBytes());. 用OutputStream(字节流)发送数据: 1、response.getOutputStream().write(“中国”.getBytes());//以默认编码发送数据 2、response.getOutputStream().write("中国".getBytes("UTF-8"));//以UTF-8编码发送数据,浏览器(默认用GB2312)会出现乱码 解决办法: 2.1通过更改浏览器的编码方式:IE/”查看”/”编码”/”UTF-8”(不可取) 2.2通过设置响应头告知客户端编码方式:response.setHeader(“Content-type”, “text/html;charset=UTF-8”);//告知浏览器数据类型及编码 2.3通过meta标签模拟请求头:out.write("<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />".getBytes()); 2.4通过以下方法:response.setContentType("text/html;charset=UTF-8");
中文乱码 参考> http://blog.csdn.net/simon_1/article/details/9092747 和 http://www.jb51.net/article/56704.htm
当然了 异常拦截也可以通过 AOP 来作,只是性能肯定没有 springmvc 自带的方便和 优化