1. 程式人生 > >微服務 SpringBoot 2.0(八):靜態資源和攔截器處理

微服務 SpringBoot 2.0(八):靜態資源和攔截器處理

一文搞清楚靜態資源和攔截器 —— Java面試必修

引言

接觸一個web專案,首先要確認的就是入口,所以靜態資源和攔截器在專案中是架構級的,在第五章我們整合了Thymeleaf模組,初次認識了SpringBoot對靜態資源的預設支援。今天我們來繼續學習SpringBoot中如何合理的存放靜態資源,如何根據我們自身需要來進行擴充套件資源和攔截器的擴充套件。

在接下來的文章中,我在末尾處會公佈原始碼,原始碼將託管在碼雲上

靜態資源

工具

SpringBoot版本:2.0.4
開發工具:IDEA 2018
Maven:3.3 9
JDK:1.8

在web開發中,靜態資源的訪問是必不可少的,如:圖片、js、css 等資源的訪問。

Spring Boot 對靜態資源訪問提供了很好的支援,基本使用預設配置就能滿足開發需求,Spring Boot 對靜態資源對映提供了預設配置:

  1. 自動對映 localhost:8080/** 為
    • classpath:/META-INF/resources
    • classpath:/resources
    • classpath:/static
    • classpath:/public
  2. 自動對映 localhost:8080/webjars/** 為
    • classpath:/META-INF/resources/webjars/
    • 依據1類推

你會發現這些路徑的優先順序順序為:META-INF/resources > resources > static > public,即預設先找第一個資料夾,如果找到了,那麼就直接取那張,否則接著找第二個資料夾,依此類推

實驗圖

此時,我們不需要多作些什麼,只需要將靜態資源放入 src/main/resources 目錄下的 resources、static 或 public 資料夾下,可直接通過localhost:8080/a.jpg 定位相關資源,不要問為什麼,因為這4個目錄都是SpringBoot作為(預設)的靜態資源路徑

自定義靜態資源對映

在實際開發中,可能需要自定義靜態資源訪問路徑,那麼可以繼承**[WebMvcConfigurerAdapter | WebMvcConfigurer ]** 或 更改配置檔案來實現

一、程式碼配置

在舊版中,一般繼承 WebMvcConfigurerAdapter類,但由於2.0後,前者已經過時,WebMvcConfigurer 介面中定義了很多default方法(基於jdk1.8+ ),所以2.0後實現WebMvcConfigurer介面就好了。注:使用程式碼實現不會覆蓋系統預設4種方式(同名定義除外)

SpringBoot 1.x寫法


@Configuration
public class CustomerMvcConfigurerAdapter extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //配置靜態資源處理
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/resources2/")
                .addResourceLocations("classpath:/static2/")
                .addResourceLocations("classpath:/public2/")
                .addResourceLocations("classpath:/META-INF/resources2/");
    }
}

SpringBoot 2.0之後寫法

@Configuration
public class CustomerMvcConfigurerAdapter implements WebMvcConfigurer {

    /**
     * 新增靜態資原始檔,外部可以直接訪問地址
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //如下配置則能可以訪問src/main/resources/mysource下面的檔案
        registry.addResourceHandler("/myprofix/**").addResourceLocations("classpath:/mysource/");
        //如訪問mysource資料夾下的a.jpg,則輸入:localhost:8080/myprofix/a.jpg
    }
}

不管哪個版本,addResourceHandler方法是設定訪問路徑字首,addResourceLocations方法設定資源路徑,如果你想指定外部的目錄也很簡單,直接addResourceLocations指定即可,程式碼如下:

registry.addResourceHandler("/myprofix/**").addResourceLocations("file:E:/my/");
二、yml配置

配置檔案跟程式碼一樣,分兩個:

  1. spring.mvc.static-path-pattern(訪問路徑),對應addResourceHandler方法
    此設定只是改變訪問路徑,4個資料夾的訪問優先順序不改變,下面舉個例子
有4個資料夾分別為META-INF/resources、resources、static、public,它們各自資料夾下都放有a.jpg照片,
預設訪問localhost:8080/a.jpg(優先順序檢視開頭的小實驗)。
但配置了下面第二行後訪問路徑則發生了改變,變為:localhost:8080/mysource/a.jpg,但優先順序任然不變

# 預設值為 /**  如我要訪問
spring.mvc.static-path-pattern: 

#下面配置生效後,其他4種方式無法訪問,而且之前訪問路徑由:localhost:8080/a.jpg變成了localhost:8080/mysource/.jpg
spring.mvc.static-path-pattern: /mysource/**

結論:spring.mvc.static-path-pattern只是更改檔案的訪問路徑,而原有的優先順序不會發生改變

  1. spring.resources.static-locations(對映路徑),對應addResourceLocations方法
    該配置將導致預設值失效,所以一般新增配置一定會相容預設值
#資原始檔對映路徑,預設值:classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
spring.resources.static-locations: 

#此行配置後其他資料夾將失效
spring.resources.static-locations: classpath:/public/

#如果我們需要新增一個資料夾newsource作為資原始檔夾,我們通常加在預設配置的末尾
spring.resources.static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/newsource/

結論

程式碼實現也好,配置實現也罷,我們都應該分開去弄清楚,去學習訪問路徑對映路徑,弄清楚他們各自的作用後,才能更好的搭配使用,接下來我們學習攔截器這一章

頁面跳轉小彩蛋

以前要訪問一個頁面需要先建立個Controller控制類,再寫方法跳轉到頁面, 在這裡配置後就不需要那麼麻煩了,直接訪問http://localhost:8080/toLogin就跳轉到login.html頁面了

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/toLogin").setViewName("login");
    }

注意,需要引入thymeleaf依賴,然後在templates下加入login.html頁面,否則會跳轉到Controller對映中去

攔截器

Spring Boot 1.x

在spring boot1.x中,使用攔截器,一般進行如下配置:

@Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
	@Resource
	private CsInterceptor csInterceptor;

	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		//自定義攔截器,新增攔截路徑和排除攔截路徑 
		registry.addInterceptor(csInterceptor).addPathPatterns("api/**").excludePathPatterns("api/login");
	}
}

但是在spring boot2.x中,WebMvcConfigurerAdapter被deprecated,雖然繼承WebMvcConfigurerAdapter這個類雖然有此便利,但在Spring5.0裡面已經deprecated了。

官方文件也說了,WebMvcConfigurer介面現在已經有了預設的空白方法,所以在Springboot2.0(Spring5.0)下更好的做法還是implements WebMvcConfigurer。

Spring Boot 2.x

自定義攔截器程式碼

定義一個登入攔截器,攔截需要登入的操作,若未登入則重定向至登入介面

@Component
public class CustomerInterceptor implements HandlerInterceptor {

    /**
     * 進入controller層之前攔截請求
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        boolean flag =true;
        UserSession user=(UserSession)request.getSession().getAttribute("userSession");
        if(null == user){
            //若為空則跳轉到登入頁
            response.sendRedirect("toLogin");
            flag = false;
        }else{
            flag = true;
        }
        return flag;
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, 
Object handler, ModelAndView modelAndView) throws Exception {
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
 Object handler, Exception ex) throws Exception {
    }
}
攔截器統一管理

addPathPatterns("/**")對所有請求都攔截,但是排除了/loginIn和/login請求的攔截

@Configuration
public class WebConfig implements WebMvcConfigurer {
    //自定義的攔截器
	@Resource
	private CustomerInterceptor customerInterceptor;

	@Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 自定義攔截器,新增攔截路徑和排除攔截路徑
        registry.addInterceptor(customerInterceptor).addPathPatterns("/**").excludePathPatterns("/login","/loginIn");
    }
}
新建Controller和提交表單介面
@Controller
public class UserController {


    @GetMapping("/login")
    public ModelAndView login(HttpServletRequest request, HttpServletResponse response){
        //跳轉至登入介面
        ModelAndView modelAndView = new ModelAndView("login");
        return modelAndView;
    }

    @PostMapping("/loginIn")
    @ResponseBody
    public Map<String,Object> loginIn(HttpServletRequest request, HttpServletResponse response){
        Map<String,Object> map = new HashMap<String,Object>();
        String userName = request.getParameter("userName");
        System.out.print(userName);
        if("itmsbx".equals(userName)){
            request.getSession().setAttribute("userSession", new UserSession());
            map.put("result" , "1");
        }else{
            map.put("result" , "-1");
        }
        return map;
    }

    @RequestMapping("/manager")
    public ModelAndView manager(HttpServletRequest request, HttpServletResponse response){
        //跳轉至管理後臺
        ModelAndView modelAndView = new ModelAndView("manager");
        return modelAndView;
    }

登入介面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Java面試必修</title>
</head>
<body>
除了登陸什麼都沒有
    <input type="text" name="userName" id="userName" value="itmsbx">
    <input type="button" onclick="loginIn()">
</body>
<script src="https://www.51object.com/static/heninet/js/jquery-1.11.3.min.js"></script>

<script>
    function loginIn(){
        var userName = $("#userName").val();
        $.ajax({
            type : "POST",
            url : "loginIn?userName=" + userName,
            dataType : "json",
            success : function(data) {
                if (data.result == "1") {
                    window.location.href ="/manager";
                } else {
                    alert("登入失敗!");
                }
            }
        });

    }

</script>
</html>
訪問

總結

通過這一章你是否弄懂了靜態資源和攔截器的配置和使用,靜態資源可以自定義進行配置。攔截器和普通的springmvc沒有多大區別,同樣是設定需要攔截的和不需要攔截的路徑,下一章我們講解SpringBoot2.0整合mybatis。

原始碼地址:

作者有話說:喜歡的話就請移步Java面試必修網,請自備水,更多幹、幹、乾貨等著你