使用spring boot的開發流程:css
自動配置原理?html
請記住,飲水則思源,在每運用一個場景的時候,都要記住這是自動配置原理生效的。同時也要思考一下,spring-boot爲咱們配置了什麼?能不能修改?有哪些配置能夠修改?是否能夠擴展等。java
必定要記住:xxxAutoConfiguration幫咱們在容器中自動的配置相關組件,而其xxxProperties封裝了配置文件的內容。react
查詢類(ctrl+shift+n)WebMvcAutoConfiguration
查看其源碼,與web相關的配置在此處均可以看到:jquery
@ConfigurationProperties( prefix = "spring.resources", ignoreUnknownFields = false ) public class ResourceProperties {
也就是說有關配置能夠經過spring.resourcec進行設置。web
再來看spring
public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); } else { Duration cachePeriod = this.resourceProperties.getCache().getPeriod(); CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl(); if (!registry.hasMappingForPattern("/webjars/**")) { this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)); } String staticPathPattern = this.mvcProperties.getStaticPathPattern(); if (!registry.hasMappingForPattern(staticPathPattern)) { this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl)); } } }
從該代碼中咱們能夠看到,全部/webjars/**
都去classpath:/META-INF/resources/webjars
中找資源;bootstrap
引入jquery:後端
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.3.0</version> </dependency>
咱們將下載到的jquery包展開能夠看清楚目錄結構,結合上面有關webjars的解釋,咱們能夠嘗試經過訪問127.0.0.1:8081/webjars/jquery/3.3.0/jquery.js,發現能夠成功的訪問到該靜態資源。也就是說,打包後的項目的確是能夠訪問到的。數組
還有一種配置資源的方式,"/**"訪問當前項目的任何資源:
也就說,咱們在上述文件夾上面放置靜態資源,若是沒有特別處理,系統默認都是能夠訪問到的。
繼續查看該類的源碼:
@Bean public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext) { return new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern()); }
此處配置的是歡迎頁的映射。他都是靜態資源文件夾下的全部index.html文件。被/**
映射。 如localhost:8008則就是訪問歡迎頁面。
@Bean public SimpleUrlHandlerMapping faviconHandlerMapping() { SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); mapping.setOrder(-2147483647); mapping.setUrlMap(Collections.singletonMap("**/favicon.ico", this.faviconRequestHandler())); return mapping; }
該處配置咱們喜歡的圖標,即瀏覽器表標籤頁左方的小圖標。仍是映射到了**.favicon.ico
,也就是咱們的全部靜態文件夾下面。
從上面能夠看出,系統默認用一個staticLocations
做爲映射路徑,該路徑默認爲剛纔所列出的默認路徑,若是要配置自定義的資源路徑,則能夠:
spring.resources.static-locations=classpath:/hello,classpath:/hello2
就能夠了,但要注意以前的默認值就不生效了。
市面上比較經常使用的有JSP、Velocity、FreeMarker、以及Spring boot推薦的Thymeleaf。
雖然模板引擎不少,可是其核心思想都是同樣的,即按照必定的語法標準,將你的數據轉化爲實際的html頁面,他們的區別只在於語法。
spring boot推薦的themeleaf語法比較簡單,並且功能更強大。
注意,若是是1.x版本的spring boot此處若想使用3.x版本的thymeleaf的話,請在properties配置節配置其版本號以及佈局版本號,以覆蓋SB中默認的低版本thymeleaf。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
查看spring-boot-autoconfigure
包能夠查看到有關thymeleaf相關的配置信息ThymeleafAutoConfiguration
。其無非就是爲thymeleaf添加相關的組件。咱們主要關注的是其相關的配置規則:ThymeleafProperties。
@ConfigurationProperties( prefix = "spring.thymeleaf" ) public class ThymeleafProperties { private static final Charset DEFAULT_ENCODING; public static final String DEFAULT_PREFIX = "classpath:/templates/"; public static final String DEFAULT_SUFFIX = ".html"; private boolean checkTemplate = true; private boolean checkTemplateLocation = true; private String prefix = "classpath:/templates/"; private String suffix = ".html"; private String mode = "HTML"; private Charset encoding; private boolean cache; private Integer templateResolverOrder; private String[] viewNames; private String[] excludedViewNames; private boolean enableSpringElCompiler; private boolean renderHiddenMarkersBeforeCheckboxes; private boolean enabled; private final ThymeleafProperties.Servlet servlet; private final ThymeleafProperties.Reactive reactive;
從默認規則裏面咱們不難看出不少東西其實已經無需修改,就按該默認配置進行業務代碼編寫就好了。也就是從配置中能夠看出,咱們的全部頁面只須要放在classpath:/templates/
資源文件夾下面,並以.html
即爲便可,根本無需其餘多餘的配置:
@RequestMapping("success") public String success(){ return "success"; }
該代碼交給thymeleaf渲染template/success.html
的文件。
詳細的官方文件請點擊:參考文檔
<html xmlns:th="http://www.thymeleaf.org">
@RequestMapping("success") public String success(Map<String, Object> map){ map.put("hello", "你好"); return "success"; }
<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> this is success page. <p th:text="${hello}">這裏顯示默認信息。</p> </body> </html>
從輸出結果能夠看出,該頁面徹底能夠獨立於出來直接運行,其輸出的結果不通過渲染只不過只會輸出
這裏是默認信息
這樣的字段而已,作到了很好的先後端分離。
改變當前元素的文本內容等,例如:th:html屬性
其值均可以替換原生的元素對應的值。 相關的介紹參考官方文檔;
參考文檔Iteration
部分。
該標籤用於遍歷數組數據。須要注意的是,該標籤寫在那個標籤上,那個標籤都會在每次遍歷中生成一次。由此咱們能夠了解到,該標籤常常會和表格行標籤<tr>
搭配使用。
<h1>Product list</h1> <table> <tr> <th>NAME</th> <th>PRICE</th> <th>IN STOCK</th> </tr> <tr th:each="prod : ${prods}"> <td th:text="${prod.name}">Onions</td> <td th:text="${prod.price}">2.41</td> <td th:text="${prod.inStock}? #{true} : #{false}">yes</td> </tr> </table>
以上全部的片斷均可以組合使用,例如:
'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))
該表達式用於獲取變量的值,使用的是OGNL語法:
${session.user.id}
和${...}的功能是同樣的,不過有一個補充使用,即配合<th:object>
使用,以下面的示例:
<div th:object="${session.user}"> <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="*{lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div>
其等價於:
<div> <p>Name: <span th:text="${session.user.firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="${session.user.nationality}">Saturn</span>.</p> </div>
也就是說,用*{}
能夠省略公共的對象信息。固然,咱們也能夠在循環體內部混合使用這兩種語法:
<div th:object="${session.user}"> <p>Name: <span th:text="*{firstName}">Sebastian</span>.</p> <p>Surname: <span th:text="${session.user.lastName}">Pepper</span>.</p> <p>Nationality: <span th:text="*{nationality}">Saturn</span>.</p> </div>
該表達式用於獲取國際化內容。
定義url。
<!-- Will produce 'http://localhost:8080/gtvg/order/details?orderId=3' (plus rewriting) --> <a href="details.html" th:href="@{http://localhost:8080/gtvg/order/details(orderId=${o.id})}">view</a> <!-- Will produce '/gtvg/order/details?orderId=3' (plus rewriting) --> <a href="details.html" th:href="@{/order/details(orderId=${o.id})}">view</a> <!-- Will produce '/gtvg/order/3/details' (plus rewriting) --> <a href="details.html" th:href="@{/order/{orderId}/details(orderId=${o.id})}">view</a>
若是須要添加多個參數的話,用逗號分隔便可。
@{/order/process(execId=${execId},execType='FAST')}
片斷引用表達式。
<div th:insert="~{commons :: main}">...</div>
參考文檔Inlining
部分。
不少時候,咱們想顯示的文本實際上是單純的文本節點,徹底不想使用html標籤包裹,這時候須要怎麼寫呢。咱們顯然不能這樣寫:
my name is ${$name}.
正確的寫法應該使用行內表達式
my name is [[${name}]]!
關於行內式有兩種標籤寫法:
[[...]]
等價於th:text
,會轉義特殊字符,即按原樣輸出,<h1>
標籤會格式化內部文字;[(...)]
等價於th:utext
,不會轉義特殊字符,即按相應的標籤格式輸出,例如<h1>
標籤直接輸出爲<h1>
。轉義這個有點繞,不當心把本身也繞進去了。簡單一點的記法:想要有html標籤格式化文本,用
text
([[...]]
),想原樣輸出標籤用utext
,。
Spring boot 自動配置好了Spring mvc,如下是SB對spring mvc的默認配置,這些配置組件均可以在WebMvcConfigurationSupport
類中查看相應源碼:
自動配置了ViewResoulver(視圖解析器:根據方法的返回值獲得視圖對象(View),視圖對象決定如何渲染...轉發、重定向)
ContentNegotiatingViewResolver
: 組合全部的視圖解析器。Support for serving static resources, including support for WebJars (covered later in this document)): 靜態資源文件夾路徑,webjars.
Automatic registration of Converter, GenericConverter, and Formatter beans.
Support for HttpMessageConverters
(covered later in this document)
Automatic registration of MessageCodesResolver
(covered later in this document).
Static index.html
support.
Custom Favicon support (covered later in this document).
Automatic use of a ConfigurableWebBindingInitializer
bean (covered later in this document).
SB對web的自動配置其實不止這個類中作了,其實還有其餘的以***AutoConfiguration的類,都對web場景進行了一些配置。
模式:給容器中添加對應的自定義組件就能夠了。
咱們之前配置試圖映射、攔截器均可以在springmvc.xml中進行配置,以下圖所示:
```xml <mvc:view-controller path="/hello" view-name="success"/> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/hello"/> <bean></bean> </mvc:interceptor> </mvc:interceptors>
那在spring boot中該怎麼作呢?
編寫一個配置類(@Configuration
),是WebMvcConfigurerAdapter
類型;不能標註@EnableWebMvc
;
注意此處是1.x版本,2.x版本提示這個類準備移除了,咱們再也不須要繼承
WebMvcConfigurerAdapter
,而是直接實現接口WebMvcConfigurer
來寫配置類便可。
@Configuration public class MyConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { // 瀏覽器發送/restweb也會來到hello頁面. registry.addViewController("/restweb").setViewName("hello"); } }
該方式即保留了spring boot的全部自動配置,也能用咱們的擴展配置。能夠查看以下了解原理:
@import(EnableWebMvcConfiguration.class)
@Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); } }
spring boot 會將全部的WebMvcConfiguration相關配置一塊兒調用
這種狀況下,咱們通常是不想要SpringBoot的全部配置,全部的都是由咱們本身來指定。只須要在自定義配置類中添加一個配置@EnableWebMvc
便可,這樣以後全部的SpringMVC的自動配置都失效了。
@EnableWebMvc
原理:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc { }
注意其中的DelegatingWebMvcConfiguration
,其源碼以下:
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
咱們再來看自動配置類的源碼:
@Configuration @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class}) @ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) @AutoConfigureOrder(-2147483638) @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class}) public class WebMvcAutoConfiguration {
咱們能夠看到這一句
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
其生效方式恰好就是若容器中沒有WebMvcConfigurationSupport
,因爲前面的註解致使該組件導入了進來,所以自動配置類就不生效了。導入的WebMvcConfigurationSupport
只是SpringMVC最基本的功能。
使用SpringBoot通常不推薦SpringMVC全面接管(那就不必用SpringBoot了)
添加entities包以及dao包,引入測試用例類以及靜態資源,這裏參考原視頻教程配套代碼。 添加thymeleaf場景包,springboot會自動啓用該場景:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
咱們已經將index.html放在了template文件夾下面,此時,咱們爲了將index.html映射到網站的首頁,通常會寫以下的控制方法:
@RequestMapping({"/","index.html"}) public String index(){ return "index"; }
該控制器方法能夠將請求路徑"/","index.html"
都映射爲index.html的資源信息(thymeleaf渲染),還能夠經過在配置類中配置映射的方式完成上述效果:
@Override public void addViewControllers(ViewControllerRegistry registry) { // 瀏覽器發送/restweb也會來到hello頁面. registry.addViewController("/").setViewName("index"); // registry.addViewController("/index.html").setViewName("index"); }
再有,咱們前面有講到,springboot會將咱們生成的全部組件添加到相應的組件族中,所以,咱們這裏也能夠手動的建立一個WebMvcConfigurer,也一樣生效(別忘了添加組件註解:@Bean
,將組件註冊到容器中),上下兩端代碼完成的效果是一致的,固然也能夠是互補的(映射不一樣的話):
@Bean public WebMvcConfigurer myWebMvcConfigurer(){ return new WebMvcConfigurer() { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/index").setViewName("index"); } }; }
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.3.1-1</version> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>4.1.3</version> </dependency>
引入以後,則能夠將以前的相對路徑引入的靜態資源替換掉了,找到index.html頁面(改成login.html),使用th:xxx
修改路徑引入:
<link th:href="@{/webjars/bootstrap/4.1.3/css/bootstrap.css}" href="asserts/css/bootstrap.min.css" rel="stylesheet">
<html xmlns:th="http://www.thymeleaf.org">
別忘了經過這個能夠添加thymeleaf語法提示哦。
在springMVC中,咱們須要:
步驟:
/resource
目錄下新建i18n文件夾ResourcebundleMessageSource
管理國際化資源文件,在spring boot中,則不須要了(他已經幫我配置好了)。查看類MessageSourceAutoConfiguration
中已經有該組件的配置了。@Configuration @ConditionalOnMissingBean( value = {MessageSource.class}, search = SearchStrategy.CURRENT ) @AutoConfigureOrder(-2147483648) @Conditional({MessageSourceAutoConfiguration.ResourceBundleCondition.class}) @EnableConfigurationProperties public class MessageSourceAutoConfiguration { @Bean @ConfigurationProperties( prefix = "spring.messages" ) public MessageSourceProperties messageSourceProperties() { return new MessageSourceProperties(); }
配置了組件
@Bean public MessageSource messageSource(MessageSourceProperties properties) { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); if (StringUtils.hasText(properties.getBasename())) { messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename()))); }
咱們注意到這裏
String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");
也就是說,咱們的配置文件能夠直接放在類路徑下叫messages.properties便可,可是這樣作顯然不是很好,所以咱們只須要修改spring.messages.basename
配置便可自定義國際化內容的存放位置。
spring.messages.basename=i18n/login
再次提醒,這裏2.x版本. 1.x版本這裏彷佛是不同的寫法都行
i18n.login
#{...}
部分源碼以下:
<input type="text" class="form-control" th:placeholder="#{login.username}" placeholder="Username" required="" autofocus="">
如今咱們想經過點擊下方的中文``English
兩個按鈕切換國際化頁面該怎麼作呢?
國家化Locale(區域信息對象);LocaleResolver獲取區域信息對象,在WebMvcAutoConfiguration
:
@Bean @ConditionalOnMissingBean @ConditionalOnProperty( prefix = "spring.mvc", name = {"locale"} ) public LocaleResolver localeResolver() { if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) { return new FixedLocaleResolver(this.mvcProperties.getLocale()); } else { AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver(); localeResolver.setDefaultLocale(this.mvcProperties.getLocale()); return localeResolver; } }
默認的區域信息解析器就是根據請求頭帶來的區域信息進行的國際化。
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
所以,咱們徹底能夠本身寫一個區域化信息解析器來本身處理請求信息。
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a> <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
別忘了添加該組件:
@Bean public LocaleResolver localeResolver(){ return new MyLocaleResolver(); }
注意此處方法名必須寫爲
localResolver
,由於Spring會默認將其做爲Bean的名字,而SB的默認區域解析器會以此做爲是否生成的條件。
模板殷勤修改之後,若想實時生效,須要作以下操做:
(1) 禁用模板引擎緩存(開發過程當中建議關閉,生產環境可開啓)
spring.thymeleaf.cache=false
(2)idea編譯器的話,按ctrl + F9,從新編譯一下便可。
#工具.工具方法 if標籤的優先級比text高
<p style="color:red" th:text="{msg}" th:if="${not #strings.isEmpty(msg)}"></p>
return "redirect:/main.html"
經過進行登陸檢查,即實現SpringMVC中的HandlerIntercepter
攔截方法.
@Controller public class LoginController { @PostMapping(value = {"/user/login"}) public String login(@RequestParam("username")String username, @RequestParam("password") String password, HttpSession session, Map<String, Object> map){ if(!StringUtils.isEmpty(username) && "123456".equals(password)){ session.setAttribute("loginUser","admin"); return "redirect:/index"; }else{ map.put("msg", "用戶名或密碼錯誤"); return "login"; } } }
其中:
@PostMapping(value = {"/user/login","login"})
等價於 @RequestMapping(value={"/user/login","login"}, method = RequestMethod.POST)
;@RequestParam("username")
強調該請求必須接受一個名爲username的參數,不然會報400錯誤,並提示要求的參數不存在。index
給模板引擎解析,顯然當前是轉發user/login請求,若是咱們刷新頁面,會出現表單的重複提交,而且,若是index.html中若是寫的是相對路徑,則其路徑會誤認爲user是一個項目名稱,致使資源所有引入失敗。所以,咱們須要將其重定向。return "redirect:/index";
@Override public void addViewControllers(ViewControllerRegistry registry) { // 瀏覽器發送/restweb也會來到hello頁面. registry.addViewController("/login").setViewName("login"); registry.addViewController("/").setViewName("index"); registry.addViewController("/index").setViewName("index"); }
其中:
registry.addViewController("/login").setViewName("login");
就等價於咱們寫一個Controller進行映射:
@RequestMapping(value="/login") public String login(){ return "login"; }
所以,若是隻是單純的映射跳轉而沒有其餘的業務邏輯的話,推薦在這裏直接配置便可。
首先,咱們要編寫一個攔截器組件:
public class LoginHandlerInterupter implements HandlerInterceptor { /** * 其餘的方法因爲java8的default,咱們能夠不實現了,專心寫這部分代碼進行登陸檢查便可 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object loginUser = request.getSession().getAttribute("loginUser"); // 若登陸,放行請求 if(loginUser != null){ return true; } request.setAttribute("msg","未登陸,請先登陸"); System.out.println("this is is a preHandler method."); request.getRequestDispatcher("/login").forward(request, response); return false; } }
注意:
HandlerInterceptor
接口,經過查看該接口的源碼能夠發現:default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; }
其全部的方法都用了java8新關鍵字default
修飾了全部的接口方法,所以,在咱們的實現類中,無需實現全部的方法(若是不瞭解的話,請參考java8相關書籍——推薦 java8實戰 ,大概就是default修飾的方法不須要實現類實現了,挑本身想覆蓋的方法覆蓋便可。)
添加攔截器組件到容器中,並配置相關的參數:
/** * 添加自定義攔截器到容器中,並配置相關參數 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { // 視頻中老師有講到spring boot已經對靜態資源作了映射,不過他是針對1.x版本這樣解釋,可是我2.0版本這裏是不行的,仍是得放行靜態資源,因此加了/assert和webjars這兩個靜態資源路徑的放行,否則靜態資源仍是會被攔截下來。請注意一下。 registry.addInterceptor(new LoginHandlerInterupter()).addPathPatterns("/**") . excludePathPatterns("/login","/user/login","/asserts/**","/webjars/**"); }
WebMvcConfigurer
的配置類中,目前其徹底代碼以下所示:@Configuration public class MyConfig implements WebMvcConfigurer { @Override public void addViewControllers(ViewControllerRegistry registry) { // 瀏覽器發送/restweb也會來到hello頁面. registry.addViewController("/login").setViewName("login"); registry.addViewController("/").setViewName("index"); registry.addViewController("/index").setViewName("index"); } /** * 添加自定義攔截器到容器中,並配置相關參數 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { // SB已經對靜態資源 *.css , *.jss進行了映射,咱們能夠不加管理 registry.addInterceptor(new LoginHandlerInterupter()).addPathPatterns("/**") . excludePathPatterns("/login","/user/login","/asserts/**","/webjars/**"); } /** * 自定義本地解析器 * @return */ @Bean public LocaleResolver localeResolver(){ return new MyLocaleResolver(); }
能夠看到,該配置類實現WebMvcConfigurer
接口,用於修改spring mvc相關的默認配置,好比這裏添加了視圖控制器、攔截器,另外則是一個以前爲了作本地化配置的自定義本地化解析器。
addPathPatterns("/**")
代表該攔截器會攔截全部的請求.excludePathPatterns("/login","/user/login")
代表"/login","/user/login","/asserts/**","/webjars/**"
這四個請求,是特殊的、不攔截的,注意後兩個是資源文件入口。測試運行正常的登陸,一切運行正常。