1. 程式人生 > >不學無數——SpringBoot入門V

不學無數——SpringBoot入門V

SpringBoot

1.開發一個Web程式

SpringBoot是非常適合開發Web應用的,因為他內嵌有Tomcat、Jetty、Undertow或者Netty。大部分的應用可以通過載入spring-boot-starter-web模組能夠快速的建立並啟動一個Web應用。

1.1SpringMVC框架

SpringMVC是一個“model view controller”的Web級的框架。SpringMVC能夠用@Controller或者@RestController註解在Bean中攔截相應的HTTP請求。具體請求方法是在用@Controller或者@RestController進行註解的類中的方法裡面。方法用@RequestMapping進行註解。下面的例子展示了典型的@RestController的使用方法。

@RestController
@RequestMapping(value="/users")
public class MyRestController {

	@RequestMapping(value="/{user}", method=RequestMethod.GET)
	public User getUser(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
	List<Customer> getUserCustomers(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
	public User deleteUser(@PathVariable Long user) {
		// ...
	}

}

Spring MVC是Spring框架的一部分,詳細的資訊可以看SpringMVC官方文件

1.1.1 SpringMVC自動配置

SpringMVC不用再像之前一樣用許多的配置檔案來開啟各種功能,SpringBoot已經將其許多的功能進行了自動配置化。下面就是SpringBoot針對SpringMVC的自動配置的一些功能:

  • 包括ContentNegotiatingViewResolver和BeanNameViewResolver類
  • 支援靜態資源的服務,包括支援WebJars
  • 自動註冊Converter、GenericConverter和Formatter
  • 支援HttpMessageConverters
  • 自動註冊MessageCodesResolver
  • 支援靜態的index.html
  • 對於定製化Favicon的支援
  • 自動使用ConfigurableWebBindingInitializer

如果你想保持上面的功能不變,但是想要額外的新增一些功能。能夠使用@Configuration註解進行配置不能加上@EnableWebMvc,如果你不想要上面的功能,想完全自己定義SpringMVC的功能,那麼就加上@EnableWebMvc。如果想要擁有定製化的RequestMappingHandlerMapping、RequestMappingHandlerAdapter或者ExceptionHandlerExceptionResolver,宣告一個WebMvcRegistrationsAdapter例項提供相應的內容。

1.1.2 HttpMessageConverters

SpringMVC使用HttpMessageConverter去轉換從HTTP發出來的請求及響應的內容。HTTP的請求其實都會封裝在ServletInputStream流中,而響應則會封裝在ServletOutputStream流中。而從流中讀取的資料都是原始的字串的報文,此時就需要將報文進行轉換。而基本上都是字串和java物件進行互轉的過程。所以SpringMVC用到了HttpMessageConverter來進行解決的。

例如現在有一個實體類User,我直接返回頁面UserDao物件。

@RequestMapping("/user")
    UserDao getUser(){
        return new UserDao("不學無數",23,"HeNan","1111111");
    }

此時在訪問的時候就會在頁面發現物件被轉換成了Json字串

<center><img src="http://p9jfgo4wc.bkt.clouddn.com/HttpMessageConverters.png"/></center>

如果需要自己定製轉化器的話,可以在SpringBoot使用HttpMessageConverters進行配置,如下所示:

import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;

@Configuration
public class MyConfiguration {

	@Bean
	public HttpMessageConverters customConverters() {
		HttpMessageConverter<?> additional = ...
		HttpMessageConverter<?> another = ...
		return new HttpMessageConverters(additional, another);
	}
}

1.1.3 定製JSON的序列化和反序列化

如果使用Jackson去序列化和反序列化JSON資料的話,可能需要自己定製JsonSerializer和JsonDeserializer的類。SpringBoot提供了@JsonComponent註解可以直接非常容易的將你寫的定製化解析JSON的類註冊在Spring中。

也可以使用@JsonComponent直接註解在JsonSerializer和JsonDeserializer的實現上。也可以註解在類上,類中包含了JsonSerializer和JsonDeserializer的實現.如下所示:

import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;

@JsonComponent
public class Example {

	public static class Serializer extends JsonSerializer<SomeObject> {
		// ...
	}

	public static class Deserializer extends JsonDeserializer<SomeObject> {
		// ...
	}

}

1.1.4 靜態資源

預設情況下,SpringBoot會將放在/static、/public、/resources或者/META-INF/resources目錄下的檔案稱為靜態資源。因為SpringBoot預設配置的對映地址為/**。例如我們在專案中resources中建立一下兩個資料夾,並且將靜態的圖片資源放入,分別起名為a和b。

<center><img src="http://p9jfgo4wc.bkt.clouddn.com/static.png"/></center>

此時我們如果將專案啟動起來,然後在瀏覽器中分別訪問一下地址

http://localhost:8080/a.png
http://localhost:8080/b.png

都能夠正常訪問到相應的圖片資源。因此可以知道SpringBoot在訪問靜態資源的時候會從/static、/public、/resources或者/META-INF/resources目錄下進行尋找檔案,如果找到的話便直接返回。

如果預設的靜態資源訪問路徑不符合需求的話,也可以進行自定義靜態資源的訪問路徑配置。第一種的配置方式就是通過spring.mvc.static-path-pattern元素的配置。此時如果如下配置

##這裡表示在頁面的訪問路徑中為/resources/**的時候才會處理請求
spring.mvc.static-path-pattern=/resources/**

那麼還是之前的靜態資源存放路徑的情況下,瀏覽器得如下訪問才能訪問到檔案。

http://localhost:8080/resources/a.png
http://localhost:8080/resources/b.png

如果此時是想更改靜態資原始檔的存放路徑,那麼可以通過spring.resources.static-locations元素進行配置

##預設情況下SpringBoot會在以下的資料夾中尋找靜態檔案
spring.resources.static-locations=classpath:/static,classpath:/public,classpath:/resources,classpath:/META-INF/resources

所以“spring.mvc.static-path-pattern”用於闡述HTTP請求地址,而“spring.resources.static-locations”則用於描述靜態資源的存放位置。

第二種方式是通過@Configure註解然後繼承WebMvcConfigurerAdapter重寫addResourceHandlers方法。

/**
 * @program: FirstSpringBoot
 * @description: 配置靜態資源的對映
 * @author: [email protected]
 * @create: 2018-07-27 14:37
 **/
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/");
    }
}

1.1.5 模板檔案

在網路傳輸中,想要提升效率,第一個是提升網路頻寬,第二個就是在有限的頻寬下傳輸更少的東西,而模板檔案就是這樣。通常在使用者第一次訪問網站的時候,如果一些不變的內容可以在使用者本機生成一個模板檔案,然後第二次訪問或者重新整理的時候只傳輸動態的內容即可。

SpringBoot支援下列的模板技術的自動配置:

  • FreeMarker
  • Groovy
  • Thymeleaf
  • Mustache

如果使用SpringBoot的預設配置的話,那麼模板檔案將會自動掃描放在src/main/resources/templates的檔案作為模板檔案。

如果使用IDEA進行專案的開發的話,由於IDEA掃描路徑的方式不同。所以如果使用IDE進行main方法的啟動和使用gradle或者maven進行jar包的啟動的話,掃描路徑也是不同的。這有可能造成SpringBoot在classpath中去找不到templates檔案。如果有這種問題的話,可以使用IDEA中的配置資原始檔配置一下,或者在配置檔案中配置classpath*:/templates/即可。

1.1.6 錯誤處理

通常在開發過程中,在Controller中每個方法或許都得寫一個異常處理的程式碼。例如下面這個例子:

    @RequestMapping(value = "/query", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> queryCondition() {
       
        try {
            //業務程式碼省略
            return setResult(list, count);
        } catch (Exception e) {
            return setFailure("查詢失敗");
        }
    }

    @RequestMapping(value = "/getDetail", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> getByKey() {
      
        try {
            //業務程式碼省略
            return map;
        } catch (Exception e) {
            return setFailure("查詢失敗");
        }
    }

程式碼中存在著許多的try-catch 而且處理的還都是一個異常,返回的資訊也是一樣的,所以這時程式碼就會顯得難看而且臃腫。SpringBoot提供了全域性的異常處理方法。例如下面例子

/**
 * @program: FirstSpringBoot
 * @description: 全域性Controller層異常處理
 * @author: [email protected]
 * @create: 2018-07-27 16:54
 **/
@ControllerAdvice
public class GlobExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleException(Exception e){
        return "Exception BuXueWuShu "+e.toString();
    }
}

其中@ControllerAdvice註解是將所寫的類註冊到Spring容器中,@ControllerAdvice有個引數basePackageClasses,如果寫了的話那麼他就會處理所寫的那個類所傳出來的異常。如果不寫的話,那麼預設處理所有傳出來的異常。另外@ExceptionHandler註解裡面加上了異常的種類的話,那麼此方法就單獨的處理所寫的異常,如果沒寫的話,就預設處理所有的異常。這時候在Controller層中所有的try-catch就可以去掉了。

1.1.7 自定義錯誤頁面

在網站中,如果沒有找到某個資源的話就會返回404的錯誤,預設的404介面有點醜,不夠美觀。如果想要自定義錯誤頁面的話,那麼就在靜態資原始檔夾下建立一個error資料夾,error資料夾下放想要處理狀態碼的檔案,其中檔名為狀態碼。下面為狀態碼為404的例子:


src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/
             +- error/
             |   +- 404.html
             +- <other public assets>

當然你也可以和上一節相結合,將錯誤資訊返回到錯誤頁面中,然後運用模板技術將錯誤資訊拼接返回給使用者。

1.1.8 自定義內嵌的Servlet容器

通用的Servlet的配置可以通過Spring的環境變數來設定,一般都是講配置寫在application.properties中的。

常見的配置如下:

  • 預設的埠是8080,如果想改變埠號可以通過server.port改變。介面地址繫結server.address
  • session設定:session是否一直儲存,server.servlet.session.persistence。session過期時間server.servlet.session.timeout。本地的session資料存放地址:server.servlet.session.store-dir。session-cookie的配置:server.servlet.session.cookie.*
  • error頁面的存放地址:server.error.path

ServerProperties 更加詳細的配置屬性

1.1.8.1 程式化配置

如果想要程式化配置內嵌的Servlet容器的話,需要在Spring中註冊實現了WebServerFactoryCustomizer介面的Bean。WebServerFactoryCustomizer提供了ConfigurableServletWebServerFactory。而ConfigurableServletWebServerFactory提供了許多的set方法進行設定屬性。例子如下:

@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

	@Override
	public void customize(ConfigurableServletWebServerFactory server) {
		server.setPort(9000);
	}

}

1.1.8.2 直接配置ConfigurableServletWebServerFactory

如果上面的例子還不滿足的話,那麼可以直接在Spring容器中註冊TomcatServletWebServerFactory、JettyServletWebServerFactory或者UndertowServletWebServerFactory

@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
	TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
	factory.setPort(9000);
	factory.setSessionTimeout(10, TimeUnit.MINUTES);
	factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
	return factory;
}

1.1.9 JSP的侷限性

SpringBoot是不推薦在專案中使用JSP的,因為JSP在SpringBoot有以下的缺點:

  • Tomcat和Jetty如果使用war進行打包,然後用java -jar進行執行的時候都可以執行的,但是JSPs不支援。
  • Undertow不支援JSPs
  • 建立error.jsp不會覆蓋掉預設的錯誤頁面

這有一個JSP Sample教你如何在SpringBoot配置JSP