Spring Web MVC框架(通常簡稱為"Spring MVC")是一個富"模型,視圖,控制器"的web框架。 Spring MVC允許你創建特定的@Controller或@RestController beans來處理傳入的HTTP請求。 使用@RequestMapping注解可以將控制器中的方法映射到相應的HTTP請求。
示例:
@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) { // ... } }
SpringBoot 中常用注解@PathVaribale/@RequestParam/@GetMapping介紹
Spring MVC自動配置
Spring Boot為Spring MVC提供適用於多數應用的自動配置功能。在Spring默認基礎上,自動配置添加了以下特性:
1. 引入ContentNegotiatingViewResolver和BeanNameViewResolver beans。 2. 對靜態資源的支持,包括對WebJars的支持。 3. 自動注冊Converter,GenericConverter,Formatter beans。 4. 對HttpMessageConverters的支持。 5. 自動注冊MessageCodeResolver。 6. 對靜態index.html的支持。 7. 對自定義Favicon的支持。
如果想全面控制Spring MVC,你可以添加自己的@Configuration,並使用@EnableWebMvc對其注解。如果想保留SpringBoot MVC的特性,並只是添加其他的MVC配置(攔截器,formatters,視圖控制器等),你可以添加自己的WebMvcConfigurerAdapter類型的@Bean(不使用@EnableWebMvc注解)。
HttpMessageConverters
Spring MVC使用HttpMessageConverter接口轉換HTTP請求和響應。對象可以自動轉換為JSON(使用Jackson庫)或XML(如果Jackson XML擴展可用則使用它,否則使用JAXB)。字符串默認使用UTF-8編碼。
如果需要添加或自定義轉換器,你可以使用Spring Boot的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); } }
任何在上下文中出現的HttpMessageConverter bean將會添加到converters列表,你可以通過這種方式覆蓋默認的轉換器(converters)。
MessageCodesResolver
Spring MVC有一個策略,用於從綁定的errors產生用來渲染錯誤信息的錯誤碼:MessageCodesResolver。如果設置 spring.mvc.message-codes-resolver.format 屬性為 PREFIX_ERROR_CODE 或 POSTFIX_ERROR_CODE (具體查看 DefaultMessageCodesResolver.Format 枚舉值),
Spring Boot會為你創建一個MessageCodesResolver。
靜態內容
默認情況下,Spring Boot從classpath下一個叫/static(/public,/resources或/META-INF/resources)的文件夾或從ServletContext根目錄提供靜態內容。這使用了Spring MVC的ResourceHttpRequestHandler,所以你可以通過添加自己的WebMvcConfigurerAdapter並覆寫addResourceHandlers方法來改變這個行為(加載靜態文件)。
在一個單獨的web應用中,容器默認的servlet是開啟的,如果Spring決定不處理某些請求,默認的servlet作為一個回退(降級)將從ServletContext根目錄加載內容。大多數時候,這不會發生(除非你修改默認的MVC配置),因為Spring總能夠通過DispatcherServlet處理請求。
此外,上述標准的靜態資源位置有個例外情況是Webjars內容。任何在/webjars/**路徑下的資源都將從jar文件中提供,只要它們以Webjars的格式打包。
注:如果你的應用將被打包成jar,那就不要使用src/main/webapp文件夾。盡管該文件夾是一個共同的標准,但它僅在打包成war的情況下起作用,並且如果產生一個jar,多數構建工具都會靜悄悄的忽略它。
模板引擎
正如REST web服務,你也可以使用Spring MVC提供動態HTML內容。Spring MVC支持各種各樣的模板技術,包括Velocity,
FreeMarker和JSPs。很多其他的模板引擎也提供它們自己的Spring MVC集成。
Spring Boot為以下的模板引擎提供自動配置支持:
1. FreeMarker
2. Groovy
3. Thymeleaf
4. Velocity
注:如果可能的話,應該忽略JSPs,因為在內嵌的servlet容器使用它們時存在一些已知的限制。
當你使用這些引擎的任何一種,並采用默認的配置,你的模板將會從src/main/resources/templates目錄下自動加載。
注:IntelliJ IDEA根據你運行應用的方式會對classpath進行不同的整理。在IDE里通過main方法運行你的應用跟從Maven或Gradle或打包好的jar中運行相比會導致不同的順序。這可能導致Spring Boot不能從classpath下成功地找到模板。如果遇到這個問題,你可以在IDE里重新對classpath進行排序,將模塊的類和資源放到第一位。或者,你可以配置模塊的前綴為classpath*:/templates/,這樣會查找classpath下的所有模板目錄。
Freemarker整合
步驟:
1.pom.xml中添加spring-boot-starter-freemarker
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency>
里面包含了spring-boot-starter-web
2.在配置文件中配置freemarker相關配置
①想從ftl中獲取request對象,可以配置spring.freemarker.request-context-attribute=request
②設置模板默認路徑;
③設置靜態文件訪問路徑
詳細如下:
######################################################## ###FREEMARKER (FreeMarkerAutoConfiguration) ######################################################## spring.freemarker.allow-request-override=false #本機調試時,配置項template_update_delay=0,這樣就關閉了模板緩存。注意線上環境要開啟緩存 spring.freemarker.cache=false spring.freemarker.settings.template_update_delay=0 spring.freemarker.check-template-location=true spring.freemarker.charset=UTF-8 spring.freemarker.content-type=text/html spring.freemarker.expose-request-attributes=false spring.freemarker.expose-session-attributes=false spring.freemarker.expose-spring-macro-helpers=false spring.freemarker.prefix= #若在freemarker獲取request對象,在spring boot 在application.properties可以這么配置 spring.freemarker.request-context-attribute=request #spring.freemarker.settings.*= spring.freemarker.suffix=.ftl #template-loader-path表示所有的模板文件都放在該目錄下 spring.freemarker.template-loader-path=classpath:/templates/ #spring.freemarker.view-names= #whitelistofviewnamesthatcanberesolved #static-locations可以自定義靜態資源路徑,不過會覆蓋springboot默認路徑 #在這個最末尾的file:${web.upload-path}之所有要加file:是因為指定的是一個具體的硬盤路徑,其他的使用classpath指的是系統環境變量 #spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,file:${web.upload-path} spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/ spring.freemarker.settings.auto_import=common/common.ftl as com spring.freemarker.settings.datetime_format=yyyy-MM-dd #兼容傳統模式 spring.freemarker.settings.classic_compatible=true #表示訪問該路徑時代表請求靜態資源,用戶可以直接訪問該請求路徑中的靜態資源 spring.mvc.static-path-pattern=/static/** server.port=8080 server.context-path=/test server.session.timeout=10000
3.編寫攔截器,用來向request中添加host和port;用來作為ftl中的basePath;使用${basePath!}得到
package com.zjt.chapter05.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CommonInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { String path = httpServletRequest.getContextPath(); String scheme = httpServletRequest.getScheme(); String serverName = httpServletRequest.getServerName(); int port = httpServletRequest.getServerPort(); String basePath = scheme + "://" + serverName + ":" + port + path; httpServletRequest.setAttribute("basePath", basePath); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
package com.zjt.chapter05.interceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class CommonInterceptorConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new CommonInterceptor()).addPathPatterns("/**"); } }
4.編寫測試用的controller:
package com.zjt.chapter05.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; @Controller public class TestController { @RequestMapping("/hello") public ModelAndView Hello(){ ModelAndView modelAndView=new ModelAndView(); modelAndView.setViewName("test"); modelAndView.addObject("name","趙佳濤"); modelAndView.addObject("message","祝你新春快樂"); return modelAndView; } }
5.在freemarker的ftl模板中顯示,大家可以自由使用宏;
<#macro head title=""> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title>${title}</title> <#nested /> </head> </#macro> <#macro body> <body> <#--事實上IE8和IE9並不支持媒體查詢(Media Queries),但你可以使用下面的補丁完美兼容!該補丁來自於開源社區:--> <!-- 讓IE8/9支持媒體查詢,從而兼容柵格 --> <!--[if lt IE 9]> <script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script> <script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script> <![endif]--> <#--將上述代碼放入你頁面 <body> 標簽內的任意位置--> <#nested /> </body> </html> </#macro>
<@com.head title=""> <base id="base" href="${basePath!}"> <link href="${basePath!}/static/plugins/layui/css/layui.css" type="text/css" media="screen" rel="stylesheet"/> <script src="${basePath!}/static/plugins/layui/layui.js" type="text/javascript"></script> </@com.head> <@com.body> <img src="${basePath!}/static/images/logo.png"> <br/> ${name!}${message!} </@com.body>
6.運行項目,訪問controller,返回模板頁面:
查看網頁源代碼,
可以發現靜態資源全部使用ip+端口+項目名的方式來顯示靜態資源,這樣會減少很多麻煩,填平很多坑,這也是前文攔截器中封裝的
String basePath = scheme + "://" + serverName + ":" + port + path;
為我們帶來的便利;
freemarker整合源代碼:https://github.com/zhaojiatao/springboot-zjt-chapter05.git