不學無數——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中。
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