Spring 4.1与Java 8 java.util.Optional

标签: 基础技术 教程 java8 Spring | 发表时间:2014-09-24 08:00 | 作者:xiafei
出处:http://www.importnew.com

在Spring 4.1中,利用Java 8的 java.util.Optional,通过 @RequestParam@RequestHeader@MatrixVariable三个注解,支持了仅包含非空(non-null)的容器对象。有了Java 8的 java.util.Optional,你可以保证你的参数永远不会为 null

Request Params (请求参数)

在这个例子中,我们将使用 @RequestParam注解把 java.time.LocalData绑定为 java.util.Optional

@RestController
@RequestMapping("o")
public class SampleController {

    @RequestMapping(value = "r", produces = "text/plain")
    public String requestParamAsOptional(
            @DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
            @RequestParam(value = "ld") Optional<LocalDate> localDate) {

        StringBuilder result = new StringBuilder("ld: ");
        localDate.ifPresent(value -> result.append(value.toString()));
        return result.toString();
    }
}

在Spring 4.1之前,可能会发生 no matching editors or coversion strategy was found(找不到匹配的编辑或转换策略)异常,这在Spring 4.1中不再是一个问题。为了验证这个绑定能够有效的运行,我们编写了一个简单的集成测试:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
public class SampleSomeControllerTest {

    @Autowired
    private WebApplicationContext wac;
    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }
    // ...
}

在这第一个测试中,我们将检测是否这个绑定有效的运行并且返回有效的结果:

@Test
public void bindsNonNullLocalDateAsRequestParam() throws Exception {
    mockMvc.perform(get("/o/r").param("ld", "2020-01-01"))
            .andExpect(content().string("ld: 2020-01-01"));
}

在接下来的测试中,我们将不会传入 ld参数:

@Test
public void bindsNoLocalDateAsRequestParam() throws Exception {
    mockMvc.perform(get("/o/r"))
            .andExpect(content().string("ld: "));
}

两个测试都顺利通过了!

Request Header (请求头部)

类似的,我们可以把 @RequestHeader绑定到 java.util.Optional

@RequestMapping(value = "h", produces = "text/plain")
public String requestHeaderAsOptional(
        @RequestHeader(value = "Custom-Header") Optional<String> header) {

    StringBuilder result = new StringBuilder("Custom-Header: ");
    header.ifPresent(value -> result.append(value));

    return result.toString();
}

然后测试:

@Test
public void bindsNonNullCustomHeader() throws Exception {
    mockMvc.perform(get("/o/h").header("Custom-Header", "Value"))
            .andExpect(content().string("Custom-Header: Value"));
}

@Test
public void noCustomHeaderGiven() throws Exception {
    mockMvc.perform(get("/o/h").header("Custom-Header", ""))
            .andExpect(content().string("Custom-Header: "));
}

Matrix Variables (数组变量)

在Spring 3.2中引入的 @MatrixVariable注解表明了在一个路径段中的方法参数应该被绑定到一个名值对中:

@RequestMapping(value = "m/{id}", produces = "text/plain")
public String execute(@PathVariable Integer id,
                      @MatrixVariable Optional<Integer> p,
                      @MatrixVariable Optional<Integer> q) {

    StringBuilder result = new StringBuilder();
    result.append("p: ");
    p.ifPresent(value -> result.append(value));
    result.append(", q: ");
    q.ifPresent(value -> result.append(value));

    return result.toString();
}

以上的方法可以通过获取url /o/m/42;p=4;q=2来调用。我们写个例子测试一下:

@Test
public void bindsNonNullMatrixVariables() throws Exception {
    mockMvc.perform(get("/o/m/42;p=4;q=2"))
            .andExpect(content().string("p: 4, q: 2"));
}

不幸的是,这个测试失败了。因为 在Spring MVC中, @MatrixVariable注解默认是禁止的。为了使它能用,我们需要调整 RequestMappingHandlerMapping的属性 removeSemicolonContent,默认为true,设置为false。通过 WebMvcConfigurerAdapter设置了这个属性,就像下面这样:

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        UrlPathHelper urlPathHelper = new UrlPathHelper();
        urlPathHelper.setRemoveSemicolonContent(false);
        configurer.setUrlPathHelper(urlPathHelper);
    }
}

现在,所有的测试都可以通过了。在 这里你可以找到这篇文章的示例源码(github)。

相关文章

相关 [spring java java] 推荐:

Spring 4.1与Java 8 java.util.Optional

- - ImportNew
在Spring 4.1中,利用Java 8的 java.util.Optional,通过 @RequestParam、 @RequestHeader和 @MatrixVariable三个注解,支持了仅包含非空(non-null)的容器对象. 有了Java 8的 java.util.Optional,你可以保证你的参数永远不会为 null.

Spring Boot 中使用 Java API 调用 lucene

- - SegmentFault 最新的文章
Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言). Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎.

Java中如何获取Spring中配置的bean

- - CSDN博客推荐文章
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. 二、如何在程序中获取Spring配置的bean呢. 方法一:在初始化时保存ApplicationContext对象. 说明:这种方式适用于采用Spring框架的独立应用程序,需要程序通过配置文件手工初始化Spring的情况.

[Java][web]利用Spring随时随地获得Request和Session

- - CSDN博客推荐文章
利用Spring随时随地获得Request和Session. 在web.xml中添加  . 1、方法一:通过代码实现. 2、方法二:通过注解实现:. 三、关于RequestContextListener的背景知识:. 基于LocalThread将HTTP request对象绑定到为该请求提供服务的线程上.

使用Java注解进行Spring bean管理

- - 编程语言 - ITeye博客
原文链接: http://www.ibm.com/developerworks/cn/webservices/ws-springjava/. 使用 Java 配置进行 Spring bean 管理. 学习使用 Java 配置管理 Spring bean. Spring bean 是使用传统的 XML 方法配置的.

使用SPRING中的线程池ThreadPoolTaskExecutor实现JAVA并发

- - Java - 编程语言 - ITeye博客
//线程池所使用的缓冲队列 . //线程池维护线程的最少数量 . //线程池维护线程的最大数量 . //线程池维护线程所允许的空闲时间 .  .      .      .      .

为什么说 Java 程序员必须掌握 Spring Boot ?

- - 博客园_知识库
  Spring Boot 2.0 的推出又激起了一阵学习 Spring Boot 热,那么, Spring Boot 诞生的背景是什么. Spring 企业又是基于什么样的考虑创建 Spring Boot. 传统企业使用 Spring Boot 会给我们带来什么样变革?.   带着这些问题,我们一起来了解下 Spring Boot 到底是什么?.

Best Performance Practices for Hibernate 5 and Spring Boot 2 (Part 1) - DZone Java

- -
Description:If not, then is important to know that attributes can be loaded lazily, as well via Hibernate bytecode instrumentation (another approach is via subentities).

使用Java 8 Streams和Spring Data JPA流式传输MySQL结果

- -
2015年10月19日|  KrešimirNesek. 从1.8版开始,Spring数据项目包含一个有趣的功能 - 通过一个简单的API调用,开发人员可以请求将数据库查询结果作为Java 8流返回. 在技​​术上可行并且由底层数据库技术支持的情况下,结果将逐个流式传输,并且可以使用流操作进行处理.

项目中单元测试容易出现的普遍问题归纳(Junit/Spring/Spring-test/Dubbo/RocketMQ/JAVA)

- - 编程语言 - ITeye博客
   最近公司要求项目在使用maven构建的时候不能跳过test的生命周期,也就是通过mvn test命令需要将整个项目运行起来. 因为之前项目组的成员都是在eclipse中去执行的unit test,在maven对所有模块构建的都是直接-Dmaven.test.skip=true的方式直接跳过UT的.