Начиная с Spring 4.1 Java 8 java.util.Optional
, объект-контейнер, который может содержать или не содержать ненулевое значение, поддерживается с помощью @RequestParam
, @RequestHeader
и @MatrixVariable
. При использовании Java 8 java.util.Optional
вы убедитесь, что ваши параметры никогда не равны null
.
Параметры запроса
В этом примере мы java.time.LocalDate
как java.util.Optional
используя @RequestParam
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@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(); } } |
До весны 4.1 мы получали исключение, что не было найдено ни одного подходящего редактора или стратегии конвертации. С весны 4.1 это больше не проблема. Чтобы убедиться, что привязка работает правильно, мы можем создать простой интеграционный тест:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@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(); } // ... } |
В первом тесте мы проверим, правильно ли работает привязка и возвращается ли правильный результат:
1
2
3
4
5
|
@Test public void bindsNonNullLocalDateAsRequestParam() throws Exception { mockMvc.perform(get( "/o/r" ).param( "ld" , "2020-01-01" )) .andExpect(content().string( "ld: 2020-01-01" )); } |
В следующем тесте мы не будем передавать параметр ld
:
1
2
3
4
5
|
@Test public void bindsNoLocalDateAsRequestParam() throws Exception { mockMvc.perform(get( "/o/r" )) .andExpect(content().string( "ld: " )); } |
Оба теста должны быть зелеными!
Заголовки запроса
Точно так же мы можем связать @RequestHeader
с java.util.Optional
:
1
2
3
4
5
6
7
8
9
|
@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(); } |
И тесты:
01
02
03
04
05
06
07
08
09
10
11
|
@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: " )); } |
Матричные переменные
Представленная в Spring 3.2 аннотация @MatrixVariable
указывает, что параметр метода должен быть связан с парой имя-значение в сегменте пути:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@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(); } |
Вышеуказанный метод может быть вызван через /o/m/42;p=4;q=2
url. Давайте создадим тест для этого:
1
2
3
4
5
|
@Test public void bindsNonNullMatrixVariables() throws Exception { mockMvc.perform(get( "/o/m/42;p=4;q=2" )) .andExpect(content().string( "p: 4, q: 2" )); } |
К сожалению, тест не @MatrixVariable
, потому что поддержка аннотации @MatrixVariable
по умолчанию отключена в Spring MVC . Чтобы включить его, нам нужно настроить конфигурацию и установить для свойства removeSemicolonContent
RequestMappingHandlerMapping
значение false
. По умолчанию установлено значение true
. Я сделал с WebMvcConfigurerAdapter
как WebMvcConfigurerAdapter
ниже:
1
2
3
4
5
6
7
8
9
|
@Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void configurePathMatch(PathMatchConfigurer configurer) { UrlPathHelper urlPathHelper = new UrlPathHelper(); urlPathHelper.setRemoveSemicolonContent( false ); configurer.setUrlPathHelper(urlPathHelper); } } |
И теперь все испытания проходят! Пожалуйста, найдите исходный код этой статьи здесь: https://github.com/kolorobot/spring41-samples
Ссылка: | Spring 4.1 и Java 8: java.util.Опционально от нашего партнера JCG Рафаля Боровца в блоге Codeleak.pl . |