【Spring Boot】5.web開發

使用spring boot的開發流程:css

  1. 建立Spring Boot應用,選中咱們須要的模塊;
  2. Spring Boot已經爲咱們將全部的場景配置好了(spring-boot-autoconfigure包自動配置),咱們只須要在配置文件中指定對應Properties相關的少許配置就能夠運行起來;
  3. 編寫業務代碼。

自動配置原理?html

請記住,飲水則思源,在每運用一個場景的時候,都要記住這是自動配置原理生效的。同時也要思考一下,spring-boot爲咱們配置了什麼?能不能修改?有哪些配置能夠修改?是否能夠擴展等。java

必定要記住:xxxAutoConfiguration幫咱們在容器中自動的配置相關組件,而其xxxProperties封裝了配置文件的內容。react

5.1 spring boot對靜態資源的映射規則

查詢類(ctrl+shift+n)WebMvcAutoConfiguration查看其源碼,與web相關的配置在此處均可以看到:jquery

@ConfigurationProperties(
    prefix = "spring.resources",
    ignoreUnknownFields = false
)
public class ResourceProperties {

也就是說有關配置能夠經過spring.resourcec進行設置。web

webjars

再來看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

  • webjars: 以jar包的方式引入靜態資源,如jquery等,咱們只須要配置pom文件便可引入這些靜態資源,參考:官網地址

引入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,發現能夠成功的訪問到該靜態資源。也就是說,打包後的項目的確是能夠訪問到的。數組

靜態資源文件夾

還有一種配置資源的方式,"/**"訪問當前項目的任何資源:

  • classpath:/META-INF/resources/
  • classpath:/resources/
  • classpath:/static/
  • classpath:/public/
  • /:當前項目的根路徑

也就說,咱們在上述文件夾上面放置靜態資源,若是沒有特別處理,系統默認都是能夠訪問到的。

歡迎頁

繼續查看該類的源碼:

@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

就能夠了,但要注意以前的默認值就不生效了。

5.2 模板引擎

市面上比較經常使用的有JSP、Velocity、FreeMarker、以及Spring boot推薦的Thymeleaf。

雖然模板引擎不少,可是其核心思想都是同樣的,即按照必定的語法標準,將你的數據轉化爲實際的html頁面,他們的區別只在於語法。

spring boot推薦的themeleaf語法比較簡單,並且功能更強大。

引入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的文件。

5.3 thymeleaf語法

詳細的官方文件請點擊:參考文檔

使用步驟:

  1. 導入thymeleaf的名稱空間在html標籤中,這樣就有語法提示了;
<html xmlns:th="http://www.thymeleaf.org">
  1. controller傳值
@RequestMapping("success")
    public String success(Map<String, Object> map){
        map.put("hello", "你好");
        return "success";
    }
  1. 渲染頁使用thymeleaf語法
<!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屬性 其值均可以替換原生的元素對應的值。 相關的介紹參考官方文檔;

標籤語法詳解

th:each

參考文檔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>

表達式語法

  1. 簡單表達式:
  • Variable Expressions: ${...}
  • Selection Variable Expressions: *{...}
  • Message Expressions: #{...}
  • Link URL Expressions: @{...}
  • Fragment Expressions: ~{...}
  1. Literals(字面量)
  • Text literals: 'one text' , 'Another one!' ,…
  • Number literals: 0 , 34 , 3.0 , 12.3 ,…
  • Boolean literals: true , false
  • Null literal: null
  • Literal tokens: one , sometext , main ,…
  1. Text operations(文本操做)
  • String concatenation: +
  • Literal substitutions: |The name is ${name}|
  1. Arithmetic operations(數學運算)
  • Binary operators: + , - , * , / , %
  • Minus sign (unary operator): -
  1. Boolean operations(布爾運算)
  • Binary operators: and , or
  • Boolean negation (unary operator): ! , not
  1. Comparisons and equality(比較運算)
  • Comparators: > , < , >= , <= ( gt , lt , ge , le )
  • Equality operators: == , != ( eq , ne )
  1. Conditional operators(條件操做)
  • If-then: (if) ? (then)
  • If-then-else: (if) ? (then) : (else)
  • Default: (value) ?: (defaultvalue)
  1. Special tokens(特殊標記-token:特徵;記號)
  • No-Operation: _

以上全部的片斷均可以組合使用,例如:

'User is of type ' + (${user.isAdmin()} ? 'Administrator' : (${user.type} ?: 'Unknown'))

表達式語法詳解

${...}

該表達式用於獲取變量的值,使用的是OGNL語法:

  1. 獲取對象的屬性、調用方法
  2. 使用內置的基本對象
${session.user.id}
  1. 內置的工具對象

*{...}

和${...}的功能是同樣的,不過有一個補充使用,即配合<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,。

5.4 spring mvc自動配置

經過官方文檔查閱

源碼查閱

查看文檔

Spring boot 自動配置好了Spring mvc,如下是SB對spring mvc的默認配置,這些配置組件均可以在WebMvcConfigurationSupport類中查看相應源碼:

  1. 自動配置了ViewResoulver(視圖解析器:根據方法的返回值獲得視圖對象(View),視圖對象決定如何渲染...轉發、重定向)

    • ContentNegotiatingViewResolver : 組合全部的視圖解析器。
    • 如何定製:咱們能夠本身給容器中添加一個視圖解析器,他會自動的將其組合起來。
  2. Support for serving static resources, including support for WebJars (covered later in this document)): 靜態資源文件夾路徑,webjars.

  3. Automatic registration of Converter, GenericConverter, and Formatter beans.

    • Converter:轉換器,類型轉化
    • Formatter 格式化器:2017.1.1===Date;
  4. Support for HttpMessageConverters (covered later in this document)

    • springMVC中用來轉換http請求和響應的User===Json
    • HttpMessageConverters是從容器中肯定獲取全部的HttpMessageConver;本身給容器中添加賭贏的組件,只須要將本身的組件註冊到容器中便可(@Bean,@Component)
  5. Automatic registration of MessageCodesResolver (covered later in this document).

    • 定義錯誤代碼的生成規則的;
  6. Static index.html support.

    • 靜態頁面支持
  7. Custom Favicon support (covered later in this document).

    • 圖標支持
  8. Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

    • 做用爲初始化WebDataBinder的,例如請求數據JavaBean,就須要用到數據綁定器,裏面牽涉到類型轉化、格式化等等;
    • 咱們能夠配置一個ConfigurableWebBindingInitializer來替換默認的。

SB對web的自動配置其實不止這個類中作了,其實還有其餘的以***AutoConfiguration的類,都對web場景進行了一些配置。

5.5 修改SpringBoot的默認配置

模式:給容器中添加對應的自定義組件就能夠了。

  1. Spring Boot在自動配置不少組件的時候,都會先看容器中有沒有用戶本身配置(@Bean、@Component),若是有就用用戶配置的,若是沒有就用Spring Boot本身默認配置的;可是若是組件能夠有多個的話,則是將其全部配置的組合起來;
  2. 僅靠Spring boot的默認配置仍是不夠的,咱們還須要一些本身新的配置,那麼咱們則須要擴展以及全面接管springMVC的相關功能。如何作呢?見下一節。

5.6 擴展與全面接管SpringMVC

咱們之前配置試圖映射、攔截器均可以在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的全部自動配置,也能用咱們的擴展配置。能夠查看以下了解原理:

  • WebMvcAutoConfiguration是springmvc的自動配置類;
  • 再作其餘自動配置時會導入,@import(EnableWebMvcConfiguration.class)
@Autowired(required = false)
	public void setConfigurers(List<WebMvcConfigurer> configurers) {
		if (!CollectionUtils.isEmpty(configurers)) {
			this.configurers.addWebMvcConfigurers(configurers);
		}
	}

spring boot 會將全部的WebMvcConfiguration相關配置一塊兒調用

  • 容器中全部的WebMvcConfigurer都會起做用,包括咱們本身配置的;

全面接管SpringMVC

這種狀況下,咱們通常是不想要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了)

5.7 restweb製做

引入資源

添加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");
            }
        };
    }

經過webjars引入其餘靜態資源

<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語法提示哦。

5.8 國際化

在springMVC中,咱們須要:

  1. 編寫國際化配置文件;
  2. 使用ResourcebundleMessageSource管理國際化資源文件;
  3. 在頁面使用fmt:message提取國際化內容。

步驟:

  1. 編寫國際化配置文件,抽去頁面須要顯示的國際化信息;
    • /resource目錄下新建i18n文件夾
    • 在i18n下簡歷login文件夾
    • 建立login.properties表明默認顯示、login_en_US.properties(英國)、login_zh_CN.properties(中國);
    • 在編譯器提供的國際化操做界面一次性寫入相關的文本信息,如:login.username login.password等(在同一界面進行配置,手寫比較繁瑣。)。
  2. 若是是SpringMVC的話,如上面步驟所示,咱們還要配置使用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

  1. 去頁面獲取國際化的值 還記得學習thymeleaf的時候講過一個獲取國際化值的標籤嗎?沒錯,就是他:
#{...}

部分源碼以下:

<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

所以,咱們徹底能夠本身寫一個區域化信息解析器來本身處理請求信息。

  1. 修改切換按鈕的連接信息:
<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>
  1. 自定義一個區域信息解析器:

別忘了添加該組件:

@Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }

注意此處方法名必須寫爲localResolver,由於Spring會默認將其做爲Bean的名字,而SB的默認區域解析器會以此做爲是否生成的條件。

  1. 點擊連接,便可實現切換國際化。

5.9 攔截器

模板修改實時生效

模板殷勤修改之後,若想實時生效,須要作以下操做:

(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攔截方法.

LoginController 登陸邏輯檢測

@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";
        }

    }
}

其中:

  1. @PostMapping(value = {"/user/login","login"}) 等價於 @RequestMapping(value={"/user/login","login"}, method = RequestMethod.POST);
  2. @RequestParam("username") 強調該請求必須接受一個名爲username的參數,不然會報400錯誤,並提示要求的參數不存在。
  3. 若是咱們直接返回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修飾的方法不須要實現類實現了,挑本身想覆蓋的方法覆蓋便可。)

  • 咱們這裏實現preHandler方法,該方法會在全部的Http請求以前執行,也就是說,咱們能夠經過此方法對Session進行檢索,從而判斷用戶此刻是否登陸。若登陸,咱們放行請求;若未登陸,則對請求驚醒攔截,而且將當前請求跳轉到登陸界面;

添加攔截器組件到容器

添加攔截器組件到容器中,並配置相關的參數:

/**
     * 添加自定義攔截器到容器中,並配置相關參數
     * @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/**"這四個請求,是特殊的、不攔截的,注意後兩個是資源文件入口。

測試運行

測試運行正常的登陸,一切運行正常。

相關文章
相關標籤/搜索