javascript
Spring4.1新特性——Spring MVC增强
2019獨角獸企業重金招聘Python工程師標準>>>
1、GroovyWebApplicationContext?
在Spring 4.1之前沒有提供Web集成的ApplicationContext,在《Spring4新特性——Groovy Bean定義DSL》中我們自己去實現的com.sishuok.spring4.context.support.WebGenricGroovyApplicationContext,而4.1其已經提供了相應實現,直接把《Spring4新特性——Groovy Bean定義DSL》配置中的相應類改掉即可。
?2、視圖解析器標簽
之前我們都是這樣定義視圖解析器:
Java代碼 ?
<bean?id="mvcVelocityEngine"?class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> ??
????<property?name="resourceLoaderPath"?value="/WEB-INF/vm/,classpath:com/github/zhangkaitao"?/> ??
</bean> ??
<bean?id="viewResolver"?class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> ??
????<property?name="prefix"?value=""/> ??
????<property?name="suffix"?value=".vm"/> ??
????<property?name="cache"?value="false"/> ??
</bean>??
而現在我們可以使用MVC標簽定義:?
Java代碼 ?
<mvc:velocity-configurer?resource-loader-path="/WEB-INF/vm/,classpath:com/github/zhangkaitao"/> ??
<mvc:view-resolvers> ??
????<mvc:velocity?cache-views="false"?prefix=""?suffix=".vm"/> ??
</mvc:view-resolvers>??
?再來看一個更復雜的例子:?
Java代碼 ?
<mvc:velocity-configurer?resource-loader-path="/WEB-INF/vm/,classpath:com/github/zhangkaitao"/> ??
<mvc:groovy-configurer?resource-loader-path="classpath:templates/"?cache-templates="false"/> ??
<mvc:view-resolvers> ??
????<mvc:content-negotiation> ??
????????<mvc:default-views> ??
????????????<bean?class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"> ??
????????????????<property?name="jsonpParameterNames"> ??
????????????????????<set> ??
????????????????????????<value>jsonp</value> ??
????????????????????????<value>callback</value> ??
????????????????????</set> ??
????????????????</property> ??
????????????</bean> ??
????????</mvc:default-views> ??
????</mvc:content-negotiation> ??
????<mvc:velocity?cache-views="false"?prefix=""?suffix=".vm"/> ??
????<mvc:groovy?cache-views="false"?suffix=".tpl"/> ??
</mvc:view-resolvers>??
mvc:content-negotiation用于定義內容協商的視圖解析器,且內部可以定義默認視圖;然后我們又定義了mvc:velocity和mvc:groovy兩個視圖解析器;它們會按照順序進行解析。另外幾個視圖解析器是:
?mvc:freemarker
mvc:bean-name
mvc:jsp
?這種方式有一個很大的問題就是只能做默認配置,如果想自定義其屬性值就搞不定了,估計當時開發的人考慮不全或沒有經驗。
3、控制器標簽
Spring 4.1提供了更豐富的控制器標簽:
3.1、重定向視圖控制器標簽
Java代碼 ?
<mvc:redirect-view-controller ??
????????path="/redirect"??
????????redirect-url="/status"??
????????context-relative="true"??
????????status-code="301"??
????????keep-query-params="true"/>??
3.2、狀態控制器標簽
Java代碼 ?
<mvc:status-controller?path="/status"?status-code="200"/>??
3.3、帶狀態的視圖控制器標簽
Java代碼 ?
<mvc:view-controller?path="/error/**"?status-code="200"/>??
?4、Groovy Template引擎集成
Spring 4.1提供了對Groovy Template模板引擎的集成,其是一種DSL風格的模板引擎,其也是最早在Spring Boot中引入的。
4.1、Spring配置文件 ? ?
Java代碼 ?
<mvc:groovy-configurer?resource-loader-path="classpath:templates/"?cache-templates="false"/> ??
<mvc:view-resolvers> ??
????<mvc:groovy?cache-views="false"?suffix=".tpl"/> ??
</mvc:view-resolvers>??
4.2、模板heelo.tpl
Java代碼 ?
yieldUnescaped?'<!DOCTYPE?html>'??
html?{ ??
??head?{ ??
????title('hello?groovy?templates') ??
??} ??
??body?{ ??
??????div("hello?$user.name") ??
??} ??
}??
具體語法請參考官方文檔。
?5、 Jackson @JsonView支持?
可以使用@JsonView來分組渲染JSON數據,按需展示JSON數據。
5.1、模型
Java代碼 ?
public?class?User?implements?Serializable?{ ??
????public?static?interface?OnlyIdView?{} ??
????public?static?interface?OnlyNameView?{} ??
????public?static?interface?AllView?extends?OnlyIdView,?OnlyNameView?{} ??
??
????@JsonView(OnlyIdView.class) ??
????private?Long?id; ??
??
????@JsonView(OnlyNameView.class) ??
????private?String?name;?? ??
????…… ??
}??
定義了三個視圖:OnlyIdView、OnlyNameView和AllView。
?5.2、控制器
Java代碼 ?
@RestController??
public?class?JacksonJsonViewController?{ ??
??
????@RequestMapping("/jackson1") ??
????@JsonView(User.OnlyIdView.class) ??
????public?User?test1()?{ ??
????????return?new?User(1L,?"zhangsan"); ??
????} ??
??
????@RequestMapping("/jackson2") ??
????@JsonView(User.OnlyNameView.class) ??
????public?User?test2()?{ ??
????????return?new?User(1L,?"zhangsan"); ??
????} ??
??
????@RequestMapping("/jackson3") ??
????@JsonView(User.AllView.class)?//可以省略 ??
????public?User?test3()?{ ??
????????return?new?User(1L,?"zhangsan"); ??
????} ??
}??
使用@JsonView控制渲染哪些數據。
?6、Jsonp支持??
6.1、MappingJackson2JsonView提供的支持?
Java代碼 ?
<bean?class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"> ??
????<property?name="jsonpParameterNames"> ??
????????<set> ??
????????????<value>jsonp</value> ??
????????????<value>callback</value> ??
????????</set> ??
???</property> ??
</bean>??
然后訪問如http://localhost:8080/json?callback=callback即可得到JSONP響應:callback({"user":{"id":1,"name":"zhangsan"}});。
?6.2、對使用HttpMessageConverter的@ResponseBody的支持?
Java代碼 ?
@Order(2) ??
@ControllerAdvice(basePackages?=?"com.github") ??
public?class?JsonpAdvice?extends?AbstractJsonpResponseBodyAdvice?{ ??
????public?JsonpAdvice()?{ ??
????????super("callback",?"jsonp");?//指定jsonpParameterNames ??
????} ??
}??
訪問http://localhost:8080/jackson1?callback=callback即可看到JSONP響應。?
?
@ContollerAdvice的作用請參考《Spring3.2新注解@ControllerAdvice》,basePackages用于指定對哪些包里的Controller起作用。
?6.3、ResponseBodyAdvice
我們之前實現的JsonpAdvice其繼承自AbstractJsonpResponseBodyAdvice,而AbstractJsonpResponseBodyAdvice繼承自ResponseBodyAdvice,其作用是在響應體寫出之前做一些處理:?
Java代碼 ?
@Order(1) ??
@ControllerAdvice(basePackages?=?"com.github") ??
public?class?MyResponseBodyAdvice?implements?ResponseBodyAdvice<Object>?{ ??
??
????@Override??
????public?boolean?supports(MethodParameter?methodParameter,?Class<??extends?HttpMessageConverter<?>>?converterType)?{ ??
????????return?methodParameter.getMethod().getReturnType().isAssignableFrom(User.class); ??
????} ??
??
????@Override??
????public?Object?beforeBodyWrite( ??
????????????Object?obj,?MethodParameter?methodParameter,?MediaType?mediaType, ??
????????????Class<??extends?HttpMessageConverter<?>>?converterType, ??
????????????ServerHttpRequest?serverHttpRequest,?ServerHttpResponse?serverHttpResponse)?{ ??
??
????????User?user?=?((User)obj); ??
????????user.setName("---"?+?user.getName()?+?"---"); ??
????????return?user; ??
????} ??
}??
1、supports指定支持哪些類型的方法進行處理,此處是返回值為User的;2、我們得到User對象然后在名字前后拼上”---“ ;3、可以指定多個ResponseBodyAdvice,使用@Order指定順序。訪問http://localhost:8080/jackson2?callback=callback可以看到效果。
?7、Gson HttpMessageConverter
7.1、Spring配置?
Java代碼 ?
<mvc:annotation-driven> ??
????<mvc:message-converters> ??
????????<bean?class="org.springframework.http.converter.json.GsonHttpMessageConverter"/> ??
????</mvc:message-converters> ??
</mvc:annotation-driven>??
使用方式和Jackson Json類似。本文使用的是<gson.version>2.2.4</gson.version>版本。
8、Protobuf HttpMessageConverter
8.1、Spring配置?
Java代碼 ?
<mvc:annotation-driven> ??
????<mvc:message-converters> ??
????????<bean?class="org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter"> ??
????????????<constructor-arg> ??
????????????????<bean?class="com.github.zhangkaitao.web.controller.MyExtensionRegistryInitializer"/> ??
????????????</constructor-arg> ??
????????</bean> ??
????</mvc:message-converters> ??
</mvc:annotation-driven>??
?8.2、定義protobuf message(proto/user.proto)
Java代碼 ?
package?com.github.zhangkaitao.pb; ??
? ??
?option?java_package?=?"com.github.zhangkaitao.pb"; ??
?option?java_outer_classname?=?"UserProtos"; ??
? ??
?message?User?{ ??
???optional?int64?id?=?1; ??
???optional?string?name?=?2; ??
?}??
?8.3、添加maven插件自動把protobuf message轉化成Java代碼
Java代碼 ?
<plugin> ??
????<groupId>com.google.protobuf.tools</groupId> ??
????<artifactId>maven-protoc-plugin</artifactId> ??
????<version>0.1.10</version> ??
????<executions> ??
????????<execution> ??
????????????<id>generate-sources</id> ??
????????????<goals> ??
????????????????<goal>compile</goal> ??
????????????</goals> ??
????????????<phase>generate-sources</phase> ??
????????????<configuration> ??
????????????????<protoSourceRoot>${basedir}/src/main/proto/</protoSourceRoot> ??
????????????????<includes> ??
????????????????????<param>**/*.proto</param> ??
????????????????</includes> ??
????????????</configuration> ??
????????</execution> ??
????</executions> ??
????<configuration> ??
????????<protocExecutable>D:/software/protoc.exe</protocExecutable> ??
????</configuration> ??
</plugin>??
?8.4、測試控制器?
Java代碼 ?
@RestController??
public?class?ProtobufController?{ ??
????@RequestMapping("/proto/read") ??
????public?ResponseEntity<UserProtos.User>?protoRead()?{ ??
????????return?ResponseEntity.ok(UserProtos.User.newBuilder().setId(1).setName("zhangsan").build()); ??
????} ??
????@RequestMapping("/proto/write") ??
????public?ResponseEntity<UserProtos.User>?protoRead(RequestEntity<UserProtos.User>?requestEntity)?{ ??
????????System.out.println("server===\n"?+?requestEntity.getBody()); ??
????????return?ResponseEntity.ok(requestEntity.getBody()); ??
????} ??
}??
?8.5、測試用例(com.github.zhangkaitao.proto.ProtoTest) ??
Java代碼 ?
@Test??
public?void?testRead()?{ ??
????HttpHeaders?headers?=?new?HttpHeaders(); ??
????RequestEntity<UserProtos.User>?requestEntity?= ??
????????????new?RequestEntity<UserProtos.User>(headers,?HttpMethod.POST,?URI.create(baseUri?+?"/proto/read")); ??
??
????ResponseEntity<UserProtos.User>?responseEntity?= ??
????????????restTemplate.exchange(requestEntity,?UserProtos.User.class); ??
??
????System.out.println(responseEntity.getBody()); ??
} ??
??
@Test??
public?void?testWrite()?{ ??
????UserProtos.User?user?=?UserProtos.User.newBuilder().setId(1).setName("zhangsan").build(); ??
????HttpHeaders?headers?=?new?HttpHeaders(); ??
????RequestEntity<UserProtos.User>?requestEntity?= ??
????????????new?RequestEntity<UserProtos.User>(user,?headers,?HttpMethod.POST,?URI.create(baseUri?+?"/proto/write")); ??
??
????ResponseEntity<UserProtos.User>?responseEntity?= ??
????????????restTemplate.exchange(requestEntity,?UserProtos.User.class); ??
????System.out.println(responseEntity.getBody()); ??
}??
測試用例知識請參考《Spring MVC測試框架詳解——服務端測試》和《Spring MVC測試框架詳解——客戶端測試》。
測試過程中會拋出:
Java代碼 ?
Caused?by:?java.lang.UnsupportedOperationException ??
????at?java.util.Collections$UnmodifiableMap.put(Collections.java:1342) ??
????at?org.springframework.http.HttpHeaders.set(HttpHeaders.java:869) ??
????at?org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter.setProtoHeader(ProtobufHttpMessageConverter.java:196)??
這是因為ProtobufHttpMessageConverter會修改響應頭,但是ResponseEntity構造時HttpHeaders是不允許修改的。暫時解決辦法是注釋掉:
Java代碼 ?
//setProtoHeader(outputMessage,?message);??
9、RequestEntity/ResponseEntity
Spring 4.1提供了ResponseEntity配對的RequestEntity,使用方式和HttpEntity一樣。具體可以參考com.github.zhangkaitao.web.controller.RequestResponseEntityController。
?10、MvcUriComponentsBuilder
其作用可以參考《Spring4新特性——注解、腳本、任務、MVC等其他特性改進》,Spring 4.1又提供了一個新的方法MvcUriComponentsBuilder.fromMappingName用于根據控制器方法來生成請求URI。
?Java代碼 ?
@RestController??
public?class?MvcUriComponentsBuilderController?{ ??
??
????@RequestMapping("/uri") ??
????public?String?mvcUriComponentsBuilder1()?{ ??
????????return?MvcUriComponentsBuilder.fromMappingName("MUCBC#mvcUriComponentsBuilder1").build(); ??
????} ??
????@RequestMapping("/uri/{id}") ??
????public?String?mvcUriComponentsBuilder2(@PathVariable?Long?id)?{ ??
????????return?MvcUriComponentsBuilder.fromMappingName("MUCBC#mvcUriComponentsBuilder2").arg(0,?"123").build(); ??
????} ??
}??
規則是“控制器所有大寫字母#方法名”找到相應的方法。 另外可以直接在頁面中使用如下方式獲取相應的URI:
Java代碼 ?
${s:mvcUrl('MUCBC#mvcUriComponentsBuilder2').arg(0,"123").build()}??
如上方式只能在正常EL 3.0的容器中運行,可參考《Expression Language 3.0新特性》。?
11、MockRestServiceServer
MockRestServiceServer目前提供了對AsyncRestTemplate的支持,使用方式和RestTemplate一樣。可參考《Spring MVC測試框架詳解——客戶端測試》。
?12、MockMvcConfigurer
Spring 4.1提供了MockMvcConfigurer用于進行一些通用配置,使用方式如下:
Java代碼 ?
mockMvc?=?MockMvcBuilders.webAppContextSetup(context).apply(defaultSetup()).build();???
MockMvcConfigurer實現:?
Java代碼 ?
private?MockMvcConfigurer?defaultSetup()?{ ??
????return?new?MockMvcConfigurer()?{ ??
????????@Override??
????????public?void?afterConfigurerAdded(ConfigurableMockMvcBuilder<?>?configurableMockMvcBuilder)?{ ??
????????????configurableMockMvcBuilder.alwaysExpect(status().isOk()); ??
????????} ??
????????@Override??
????????public?RequestPostProcessor?beforeMockMvcCreated(ConfigurableMockMvcBuilder<?>?configurableMockMvcBuilder,?WebApplicationContext?webApplicationContext)?{ ??
????????????return?new?RequestPostProcessor()?{ ??
????????????????@Override??
????????????????public?MockHttpServletRequest?postProcessRequest(MockHttpServletRequest?mockHttpServletRequest)?{ ??
????????????????????mockHttpServletRequest.setAttribute("aa",?"aa"); ??
????????????????????return?mockHttpServletRequest; ??
????????????????} ??
????????????}; ??
????????} ??
????}; ??
}??
可以在如上實現中進行一些通用配置,如安全(往Request中扔安全對象之類的)。測試用例可參考com.github.zhangkaitao.proto.ProtoTest2。
轉載于:https://my.oschina.net/u/2409257/blog/483065
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的Spring4.1新特性——Spring MVC增强的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux内核中大小端判定宏
- 下一篇: Linux中设置定期备份oracle数据