配置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 }
至此,所有错误异常都能捕捉到,统一处理了~~