当前位置: 移动技术网 > IT编程>开发语言>Java > SpringBoot Web篇笔记(一)

SpringBoot Web篇笔记(一)

2019年11月13日  | 移动技术网IT编程  | 我要评论

摘要

文章是根据江南一点雨(松哥)的视频进行总结


全局异常处理

通常情况下,我们都需要对自己定义的异常进行相应的处理。捕获指定的异常方式如下:

@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 {
   // 扩展
}


cors跨域

在前后端分离进行开发的情况下,一般都需要设置跨域访问,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();
    }
}


整合servlet

首先自定义的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♪(・ω・)ノ。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网