配置springboot在访问404时自定义返回结果以及统一异常处理

在搭建项目框架的时候用的是springboot,想统一处理异常,但是发现404的错误总是捕捉不到,总是返回的是springBoot自带的错误结果信息。

如下是springBoot自带的错误结果信息:

1 {
2   "timestamp": 1492063521109,
3   "status": 404,
4   "error": "Not Found",
5   "message": "No message available",
6   "path": "/rest11/auth"
7 }

 

百度一波,发现需要配置文件中加上如下配置:

properties格式:

#出现错误时, 直接抛出异常
spring.mvc.throw-exception-if-no-handler-found=true
#不要为我们工程中的资源文件建立映射
spring.resources.add-mappings=false

yml格式:

spring:
#出现错误时, 直接抛出异常(便于异常统一处理,否则捕获不到404)
  mvc:
    throw-exception-if-no-handler-found: true

#不要为我们工程中的资源文件建立映射
  resources:
    add-mappings: false

   

下面是我SpringMVC-config配置代码,里面包含统一异常处理代码,都贴上:

  

  1 package com.qunyi.jifenzhi_zx.core.config;
  2 
  3 import com.alibaba.druid.pool.DruidDataSource;
  4 import com.alibaba.druid.support.http.StatViewServlet;
  5 import com.alibaba.druid.support.http.WebStatFilter;
  6 import com.alibaba.druid.support.spring.stat.BeanTypeAutoProxyCreator;
  7 import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
  8 import com.alibaba.fastjson.JSON;
  9 import com.alibaba.fastjson.serializer.SerializerFeature;
 10 import com.alibaba.fastjson.support.config.FastJsonConfig;
 11 import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
 12 import com.qunyi.jifenzhi_zx.core.Const;
 13 import com.qunyi.jifenzhi_zx.core.base.exception.ServiceException;
 14 import com.qunyi.jifenzhi_zx.core.base.result.ResponseMsg;
 15 import com.qunyi.jifenzhi_zx.core.base.result.Result;
 16 import org.slf4j.Logger;
 17 import org.slf4j.LoggerFactory;
 18 import org.springframework.beans.factory.annotation.Value;
 19 import org.springframework.boot.web.servlet.FilterRegistrationBean;
 20 import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
 21 import org.springframework.boot.web.servlet.ServletRegistrationBean;
 22 import org.springframework.context.annotation.Bean;
 23 import org.springframework.context.annotation.Configuration;
 24 import org.springframework.http.converter.HttpMessageConverter;
 25 import org.springframework.web.context.request.RequestContextListener;
 26 import org.springframework.web.method.HandlerMethod;
 27 import org.springframework.web.servlet.HandlerExceptionResolver;
 28 import org.springframework.web.servlet.ModelAndView;
 29 import org.springframework.web.servlet.NoHandlerFoundException;
 30 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 31 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 32 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 33 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 34 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 35 
 36 import javax.servlet.http.HttpServletRequest;
 37 import javax.servlet.http.HttpServletResponse;
 38 import java.io.IOException;
 39 import java.nio.charset.Charset;
 40 import java.util.List;
 41 
 42 /**
 43  * Spring MVC 配置
 44  *
 45  * @author xujingyang
 46  * @date 2018/05/25
 47  */
 48 @Configuration
 49 public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
 50 
 51     private final Logger logger = LoggerFactory.getLogger(WebMvcConfigurer.class);
 52     @Value("${spring.profiles.active}")
 53     private String env;//当前激活的配置文件
 54 
 55     //使用阿里 FastJson 作为JSON MessageConverter
 56     @Override
 57     public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
 58         FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
 59         FastJsonConfig config = new FastJsonConfig();
 60         config.setSerializerFeatures(SerializerFeature.WriteMapNullValue,//保留空的字段
 61                 SerializerFeature.WriteNullStringAsEmpty,//String null -> ""
 62                 SerializerFeature.WriteNullNumberAsZero);//Number null -> 0
 63         converter.setFastJsonConfig(config);
 64         converter.setDefaultCharset(Charset.forName("UTF-8"));
 65         converters.add(converter);
 66     }
 67 
 68 
 69     //统一异常处理
 70     @Override
 71     public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
 72         exceptionResolvers.add(new HandlerExceptionResolver() {
 73             public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
 74                 ResponseMsg result;
 75                 if (e instanceof ServiceException) {//业务失败的异常,如“账号或密码错误”
 76                     result = new ResponseMsg("501", "业务层出错:" + e.getMessage());
 77                     logger.info(e.getMessage());
 78                 } else if (e instanceof NoHandlerFoundException) {
 79                     result = new ResponseMsg("404", "接口 [" + request.getRequestURI() + "] 不存在");
 80                 } else {
 81                     result = new ResponseMsg("500", "接口 [" + request.getRequestURI() + "] 错误,请联系管理员!");
 82                     String message;
 83                     if (handler instanceof HandlerMethod) {
 84                         HandlerMethod handlerMethod = (HandlerMethod) handler;
 85                         message = String.format("接口 [%s] 出现异常,方法:%s.%s,异常摘要:%s",
 86                                 request.getRequestURI(),
 87                                 handlerMethod.getBean().getClass().getName(),
 88                                 handlerMethod.getMethod().getName(),
 89                                 e.getMessage());
 90                     } else {
 91                         message = e.getMessage();
 92                     }
 93                     logger.error(message, e);
 94                 }
 95                 responseResult(response, result);
 96                 return new ModelAndView();
 97             }
 98 
 99         });
100     }
101 
102     //解决跨域问题
103     @Override
104     public void addCorsMappings(CorsRegistry registry) {
105         registry.addMapping("/**") // **代表所有路径
106                 .allowedOrigins("*") // allowOrigin指可以通过的ip,*代表所有,可以使用指定的ip,多个的话可以用逗号分隔,默认为*
107                 .allowedMethods("GET", "POST", "HEAD", "PUT", "DELETE") // 指请求方式 默认为*
108                 .allowCredentials(false) // 支持证书,默认为true
109                 .maxAge(3600) // 最大过期时间,默认为-1
110                 .allowedHeaders("*");
111     }
112 
113     //添加拦截器
114     @Override
115     public void addInterceptors(InterceptorRegistry registry) {
116         //接口登录验证拦截器
117         if (!"dev".equals(env)) { //开发环境忽略登录验证
118             registry.addInterceptor(new HandlerInterceptorAdapter() {
119                 @Override
120                 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
121                     //验证登录
122                     Object obj = request.getSession().getAttribute(Const.LOGIN_SESSION_KEY);
123                     if (obj != null) {
124                         return true;
125                     } else {
126                         logger.warn("请先登录!==> 请求接口:{},请求IP:{},请求参数:{}",
127                                 request.getRequestURI(), getIpAddress(request), JSON.toJSONString(request.getParameterMap()));
128 
129                         responseResult(response, new ResponseMsg(Result.SIGNERROR));
130                         return false;
131                     }
132                 }
133             });
134         }
135     }
136 
137 
138     private void responseResult(HttpServletResponse response, ResponseMsg result) {
139         response.setCharacterEncoding("UTF-8");
140         response.setHeader("Content-type", "application/json;charset=UTF-8");
141         response.setStatus(200);
142         try {
143             response.getWriter().write(JSON.toJSONString(result));
144         } catch (IOException ex) {
145             logger.error(ex.getMessage());
146         }
147     }
148 
149     private String getIpAddress(HttpServletRequest request) {
150         String ip = request.getHeader("x-forwarded-for");
151         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
152             ip = request.getHeader("Proxy-Client-IP");
153         }
154         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
155             ip = request.getHeader("WL-Proxy-Client-IP");
156         }
157         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
158             ip = request.getHeader("HTTP_CLIENT_IP");
159         }
160         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
161             ip = request.getHeader("HTTP_X_FORWARDED_FOR");
162         }
163         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
164             ip = request.getRemoteAddr();
165         }
166         // 如果是多级代理,那么取第一个ip为客户端ip
167         if (ip != null && ip.indexOf(",") != -1) {
168             ip = ip.substring(0, ip.indexOf(",")).trim();
169         }
170 
171         return ip;
172     }
173 
174 
175     /**
176      * druidServlet注册
177      */
178     @Bean
179     public ServletRegistrationBean druidServletRegistration() {
180         ServletRegistrationBean registration = new ServletRegistrationBean(new StatViewServlet());
181         registration.addUrlMappings("/druid/*");
182         return registration;
183     }
184 
185     /**
186      * druid监控 配置URI拦截策略
187      *
188      * @return
189      */
190     @Bean
191     public FilterRegistrationBean druidStatFilter() {
192         FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
193         // 添加过滤规则.
194         filterRegistrationBean.addUrlPatterns("/*");
195         // 添加不需要忽略的格式信息.
196         filterRegistrationBean.addInitParameter("exclusions", "/web_frontend/*,*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid,/druid/*,/error,/login*");
197         // 用于session监控页面的用户名显示 需要登录后主动将username注入到session里
198         filterRegistrationBean.addInitParameter("principalSessionName", "username");
199         return filterRegistrationBean;
200     }
201 
202 
203     /**
204      * druid数据库连接池监控
205      */
206     @Bean
207     public DruidStatInterceptor druidStatInterceptor() {
208         return new DruidStatInterceptor();
209     }
210 
211     /**
212      * druid数据库连接池监控
213      */
214     @Bean
215     public BeanTypeAutoProxyCreator beanTypeAutoProxyCreator() {
216         BeanTypeAutoProxyCreator beanTypeAutoProxyCreator = new BeanTypeAutoProxyCreator();
217         beanTypeAutoProxyCreator.setTargetBeanType(DruidDataSource.class);
218         beanTypeAutoProxyCreator.setInterceptorNames("druidStatInterceptor");
219         return beanTypeAutoProxyCreator;
220     }
221 
222     /**
223      * RequestContextListener注册
224      */
225     @Bean
226     public ServletListenerRegistrationBean<RequestContextListener> requestContextListenerRegistration() {
227         return new ServletListenerRegistrationBean<>(new RequestContextListener());
228     }
229 
230     /**
231      * 将swagger-ui.html 添加 到 resources目录下
232      *
233      * @param registry
234      */
235     @Override
236     public void addResourceHandlers(ResourceHandlerRegistry registry) {
237         registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
238         registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
239         registry.addResourceHandler("/web_frontend/**").addResourceLocations("classpath:/web_frontend/");
240 
241     }
242 
243 }
View Code

 

  

  至此,所有错误异常都能捕捉到,统一处理了~~

 

posted @ 2018-05-29 09:54  oldmonk  阅读(17854)  评论(2编辑  收藏  举报
Fork me on GitHub