微服務 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 對靜態資源對映提供了預設配置:
- 自動對映 localhost:8080/** 為
- classpath:/META-INF/resources
- classpath:/resources
- classpath:/static
- classpath:/public
- 自動對映 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配置
配置檔案跟程式碼一樣,分兩個:
- 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只是更改檔案的訪問路徑,而原有的優先順序不會發生改變
- 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面試必修網,請自備水,更多幹、幹、乾貨等著你