SpringBoot Web篇筆記(一)

摘要

文章是根據江南一點雨(鬆哥)的視頻進行總結javascript

江南一點雨博客html


全局異常處理

一般狀況下,咱們都須要對本身定義的異常進行相應的處理。捕獲指定的異常方式以下:前端

@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錯誤碼(頁面找不到)時,一般會返回以下頁面:
java

而咱們須要指定在服務器拋出相應的錯誤碼時,跳轉到指定的動態或靜態頁面。web

源碼閱讀

參考默認的視圖解析器org.springframework.boot.autoconfigure.web.servlet.error.DefaultErrorViewResolver源碼,取出部分代碼片斷以下:spring

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下頁面使用以下:app

<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♪(・ω・)ノ。

相關文章
相關標籤/搜索