目录

Spring4.1新特性——综述

Spring4.1新特性——Spring核心部分及其他

Spring4.1新特性——Spring缓存框架增强

Spring4.1新特性——异步调用和事件机制的异常处理

Spring4.1新特性——数据库集成测试脚本初始化

Spring4.1新特性——Spring MVC增强

Spring4.1新特性——页面自动化测试框架Spring MVC Test HtmlUnit简介

Spring4.1新特性——静态资源处理增强

Spring 4.1对Spring MVC部分做的增强是最多的,提供了一些视图解析器的mvc标签实现简化配置、提供了GroovyWebApplicationContext用于 Groovy web集成、提供了Gson、protobuf的HttpMessageConverter、提供了对groovy-templates模板的支持、 JSONP的支持、对Jackson的@JsonView的支持等。

1、GroovyWebApplicationContext 

在Spring 4.1之前没有提供Web集成的ApplicationContext,在《Spring4新特性——Groovy Bean定义DSL》中我们自己去实现的com.sishuok.spring4.context.support.WebGenricGroovyApplicationContext,而4.1其已经提供了相应实现,直接把《Spring4新特性——Groovy Bean定义DSL》配置中的相应类改掉即可。

2、视图解析器标签

之前我们都是这样定义视图解析器:

    <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标签定义:

<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>

再来看一个更复杂的例子:

<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、重定向视图控制器标签

    <mvc:redirect-view-controller
path="/redirect"
redirect-url="/status"
context-relative="true"
status-code="301"
keep-query-params="true"/>

3.2、状态控制器标签

<mvc:status-controller path="/status" status-code="200"/> 

3.3、带状态的视图控制器标签

    <mvc:view-controller path="/error/**" status-code="200"/>  

4、Groovy Template引擎集成

Spring 4.1提供了对Groovy Template模板引擎的集成,其是一种DSL风格的模板引擎,其也是最早在Spring Boot中引入的。

4.1、Spring配置文件

    <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

    yieldUnescaped '<!DOCTYPE html>'
html {
head {
title('hello groovy templates')
}
body {
div("hello $user.name")
}
}

具体语法请参考官方文档。

5、 Jackson @JsonView支持

可以使用@JsonView来分组渲染JSON数据,按需展示JSON数据。

5.1、模型

    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、控制器

    @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提供的支持

<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的支持

    @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,其作用是在响应体写出之前做一些处理:

    @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配置

    <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配置

<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)

    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代码

    <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、测试控制器

    @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)

    @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测试框架详解——客户端测试》。

测试过程中会抛出:

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是不允许修改的。暂时解决办法是注释掉:

//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。

@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:

${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用于进行一些通用配置,使用方式如下:

mockMvc = MockMvcBuilders.webAppContextSetup(context).apply(defaultSetup()).build();&nbsp;

MockMvcConfigurer实现:

    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。

相关文章

http://beta.groovy-lang.org/docs/groovy-2.3.0-SNAPSHOT/html/documentation/markup-template-engine.html

https://spring.io/blog/2014/05/28/using-the-innovative-groovy-template-engine-in-spring-boot

Spring4新特性——Groovy Bean定义DSL

Spring3.2新注解@ControllerAdvice

Spring MVC测试框架详解——服务端测试

Spring MVC测试框架详解——客户端测试

Spring4新特性——注解、脚本、任务、MVC等其他特性改进

Spring4新特性

Spring4新特性——泛型限定式依赖注入

Spring4新特性——核心容器的其他改进

Spring4新特性——Web开发的增强

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

Spring4新特性——Groovy Bean定义DSL

Spring4新特性——更好的Java泛型操作API

Spring4新特性——JSR310日期API的支持

Spring4新特性——注解、脚本、任务、MVC等其他特性改进

源码下载

https://github.com/zhangkaitao/spring4-1-showcase/tree/master/spring4.1-groovy

https://github.com/zhangkaitao/spring4-1-showcase/tree/master/spring4.1-mvc

Spring4.1新特性——Spring MVC增强的更多相关文章

  1. Spring4.1新特性——Spring缓存框架增强(转)

    目录 Spring4.1新特性——综述 Spring4.1新特性——Spring核心部分及其他 Spring4.1新特性——Spring缓存框架增强 Spring4.1新特性——异步调用和事件机制的异 ...

  2. Spring框架入门之Spring4.0新特性——泛型注入

    Spring框架入门之Spring4.0新特性——泛型注入 一.为了更加快捷的开发,为了更少的配置,特别是针对 Web 环境的开发,从 Spring 4.0 之后,Spring 引入了 泛型依赖注入. ...

  3. 理解Spring4.0新特性@RestController注解

    参考原文 @RestController注解是它继承自@Controller注解.4.0之前的版本,spring MVC的组件都使用@Controller来标识当前类是一个控制器servlet. 使用 ...

  4. JAVA8新特性——接口定义增强

    JAVA9都要出来了,JAVA8新特性都没搞清楚,是不是有点掉队哦~ 接口定义增强 在JDK1.8以前,接口是定义的: 接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法 ...

  5. 。。。在学习新框架Spring MVC的感受。。。

    已经学习一遍Spring MVC了,感觉还是懵懵懂懂的,特别是重定向,路径,参数的这些问题,心好乱,不过,这,都不是问题!!! 继续努力,努力到会为止!!!加油!!!

  6. JDK1.6新特性,网络增强(Networking features and enhancements)

    参考: http://docs.oracle.com/javase/6/docs/technotes/guides/net/enhancements-6.0.html http://blog.csdn ...

  7. Oracle12c中数据泵新特性之功能增强(expdp, impdp)

    Oracle的数据泵功能在10g中被引进.本文对数据泵在12c中的增强做一个概览. 1.   禁用日志选项(DISABLE_ARCHIVE_LOGGING) Impdp的TRANSFORM参数已经扩展 ...

  8. Spring Boot 2(一):Spring Boot 2.0新特性

    Spring Boot 2(一):Spring Boot 2.0新特性 Spring Boot依赖于Spring,而Spring Cloud又依赖于Spring Boot,因此Spring Boot2 ...

  9. Oracle 11g新特性延迟段创建和truncate的增强

    下面测试Oracle 11g开始的新特性truncate的增强和延迟段空间创建. Oracle从11g开始,当用户创建一张空表的时候不会先分配段和空间,只有当对这张表插入第一行数据的时候才分配段和空间 ...

随机推荐

  1. 虚拟机VMware怎么完全卸载干净

    虚拟机VMware怎么完全卸载干净 听语音 | 浏览:19929 | 更新:2014-12-21 10:28 | 标签:虚拟机 1 2 3 4 5 6 7 分步阅读 一键约师傅 百度师傅高质屏和好师傅 ...

  2. es安装

    1,安装java(至少1.8) yum install -y java java -version 在/etc/profile追加: JAVA_HOME=/usr/java/jdk1..0_45 PA ...

  3. OAuth

    http://oauth.net http://oauth.net/2/ http://tools.ietf.org/html/rfc6749 人人网:http://wiki.dev.renren.c ...

  4. JAVA常用设计模式整理

    设计模式:一个程序员对设计模式的理解:“不懂”为什么要把很简单的东西搞得那么复杂.后来随着软件开发经验的增加才开始明白我所看到的“复杂”恰恰就是设计模式的精髓所在,我所理解的“简单”就是一把钥匙开一把 ...

  5. UIKit各类概述

    1.UIAcceleration: 被叫做加速事件的一个UIAcceleration类的实例是用来代表即时的三维加速数据.为了接收重力加速度,要注册一个应用应用程序作为一个共享UIAccelerate ...

  6. 使用jquer获取当前时间,并赋值到input上。

    今天,做一个项目,需要将自动获取的时间能够赋值到input上.我一开始试用javascript写的,写之后使用很多办法都赋值失败,最后使用了jquery写了出来,下面附上代码. <script ...

  7. 敏捷开发之Scrum

    现在敏捷开发是越来越火了,人人都在谈敏捷,人人都在学习Scrum和XP... 为了不落后他人,于是我也开始学习Scrum,今天主要是对我最近阅读的相关资料,根据自己的理解,用自己的话来讲述Scrum中 ...

  8. 【亲测】appium_v1.4.16版本自动化适配android7.0系统

    要解决的问题:appium在androidV7.0系统上运行时报错 Failure [INSTALL_FAILED_ALREADY_EXISTS: Attempt to re-install io.a ...

  9. vue学习记录④(路由传参)

    通过上篇文章对路由的工作原理有了基本的了解,现在我们一起来学习路由是如何传递参数的,也就是带参数的跳转. 带参数的跳转,一般是两种方式: ①.a标签直接跳转. ②点击按钮,触发函数跳转. 在上篇文章中 ...

  10. CH 5102Mobile Service题解

    题目: 用动态规划很容易将完成任务量作为dp的阶段,通过指派服务员,从当前i-1个任务转移到i个任务: 我们可以用一个四维数组f[i][x][y][z]来表示在完成当前任务i时,三个机器人分别在x,y ...