通常情况下,我们都需要对自己定义的异常进行相应的处理。捕获指定的异常方式如下:
@ControllerAdvice public class ExceptionHandlers { // 捕获自定义异常类进行处理 @ExceptionHandler(CustomException.class) public ModelAndView handler(CustomException e) { ModelAndView modelAndView = new ModelAndView("customException"); //自定义异常错误页面 modelAndView.addObject("msg", e.getMessage()); // ... return modelAndView; } } 复制代码
若服务器抛出404错误码(页面找不到)时,通常会返回如下页面:
而我们需要指定在服务器抛出相应的错误码时,跳转到指定的动态或静态页面。
参考默认的视图解析器 org.springframework.boot.autoconfigure.web.servlet.error.DefaultErrorViewResolver
源码,取出部分代码片段如下:
public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered { private static final Map<Series, String> SERIES_VIEWS; // 存放不同错误码对应的视图 // 添加默认的视图 static { Map<Series, String> views = new EnumMap<>(Series.class); views.put(Series.CLIENT_ERROR, "4xx"); views.put(Series.SERVER_ERROR, "5xx"); SERIES_VIEWS = Collections.unmodifiableMap(views); } ... // 开始解析错误视图 @Override public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) { // status.value() 得到的是错误码 // 寻找错误码指定的页面,如404就找名为404的页面 ModelAndView modelAndView = resolve(String.valueOf(status.value()), model); // 若找不到错误码指定的页面,则400,401,403,404...都会去找4xx的页面 if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) { modelAndView = resolve(SERIES_VIEWS.get(status.series()), model); } // 若modelAndView还是null,那么就返回上面的那个图片了 return modelAndView; } private ModelAndView resolve(String viewName, Map<String, Object> model) { String errorViewName = "error/" + viewName; //首先去动态资源中查看是否存在对应的页面 TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext); if (provider != null) { return new ModelAndView(errorViewName, model); } //若动态资源中找不到则到静态资源中寻找对应的页面 return resolveResource(errorViewName, model); } //获取静态页面资源 private ModelAndView resolveResource(String viewName, Map<String, Object> model) { // 遍历静态资源,查找是否有对应的页面 for (String location : this.resourceProperties.getStaticLocations()) { try { Resource resource = this.applicationContext.getResource(location); resource = resource.createRelative(viewName + ".html"); if (resource.exists()) { return new ModelAndView(new HtmlResourceView(resource), model); } } catch (Exception ex) { } } return null; } ... } 复制代码
1.首先会去找指定错误码的页面,若指定页面找不到则找4xx、5xx页面,(400、401...都会找4xx) 2.先到动态资源下的error目录寻找,再到静态资源中的error目录寻找
如果为动态资源的页面,返回的ModelAttribute可以查看 org.springframework.boot.web.servlet.error.DefaultErrorAttributes
, 返回的数据如下:
timestamp status error message ...
thymeleaf
下页面使用如下:
<table> <tr> <td th:text="${status}"></td> </tr> <tr> <td th:text="${message}"></td> </tr> </table> 复制代码
若需要扩展,则继承 DefaultErrorAttributes
,对扩展类加 @Component
注释:
@Component public class CustomErrorAttribute extends DefaultErrorAttributes { // 扩展 } 复制代码
在前后端分离进行开发的情况下,一般都需要设置跨域访问,springBoot提供 CORS
跨域设置如下:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") //所有前缀 .allowedOrigins("http://localhost:8081") //跨域地址(前端地址) .allowedHeaders("*") //允许所有请求头 .allowedMethods("*") //允许通过所有方法 .maxAge(30 * 1000); //探测请求的有效期 } } 复制代码
拦截器可以拦截 request
请求,若自定义权限认证的功能,就可以使用拦截器去进行实现。
public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return false; } public void postHandle ... public void afterCompletion ... } 复制代码
preHandler
执行方法前调用, postHandler
在返回视图前调用, afterCompletion
在方法执行完后调用。 添加拦截器到配置中,重写 addInterceptors
方法
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myInterceptor()) .addPathPatterns("/**"); //拦截所有路径 } @Bean MyInterceptor myInterceptor() { return new MyInterceptor(); } } 复制代码
首先自定义的Servelt继承 javax.servlet.http.HttpServlet
;使用 @WebServlet
进行url映射
@WebServlet(urlPatterns = "/myservlet") public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doget"); } } 复制代码
在启动类 xxxApplication
对自定义的Servlet的目录进行扫描
@ServletComponentScan(basePackages = "org.java.servlet") 复制代码
这就可以成功访问到啦! localhost:8080/myservlet
扩展(怕忘记了,记一下):
request
监听实现接口 javax.servlet.ServletRequestListener
, 然后对 request
监听类使用 javax.servlet.annotation.WebListener
注解; request
拦截器实现接口 javax.servlet.Filter
,然后对拦截器使用 javax.servlet.annotation.WebFilter
注解,如:
@WebListener public class MyRequestListener implements ServletRequestListener { @Override public void requestDestroyed(ServletRequestEvent sre) {System.out.println("requestDestroyed");} @Override public void requestInitialized(ServletRequestEvent sre) {System.out.println("requestInitialized");} } @WebFilter(urlPatterns = "/*") //对所有目录进行拦截 public class MyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("doFilter"); chain.doFilter(request,response); } } 复制代码
上述的监听器和拦截器一定要在 @ServletComponentScan
的扫描目录下或子目录。
若文章有错误或疑问,可在下方评论,Thanks♪(・ω・)ノ。
个人博客网址: colablog.cn/
如果我的文章帮助到您,可以关注我的微信公众号,第一时间分享文章给您