Spring MVC自定义格式化程序可在测试中使用,但在浏览器中将失败

时间:2018-07-11 17:19:50

标签: java spring-mvc spring-mvc-test

我有一个控制器 :(根据Spring WebMVC @ModelAttribute parameter-style

@GetMapping("/time/{date}")
@ResponseStatus(OK)
public LocalDate getDate(
        @ModelAttribute("date") LocalDate date
) {
    return date;
}

LocalDateFormatter 从字符串“ now” “ today” 和典型的“ yyyy-MM”编码LocalDate -dd” 格式的字符串,并将日期解码回字符串

public class LocalDateFormatter implements Formatter<LocalDate> {}

我已经通过Spring Test测试了该控制器。测试通过

我设置了转换服务,并以此模拟了MVC:

var conversion = new DefaultFormattingConversionService();
conversion.addFormatterForFieldType(LocalDate.class, new LocalDateFormatter());

mockMvc = MockMvcBuilders
        .standaloneSetup(TimeController.class)
        .setConversionService(conversionRegistry)
        .build();

测试已参数化,如下所示:

@ParameterizedTest
@MethodSource("args")
void getDate(String rawDate, boolean shouldConvert) throws Exception {
    var getTime = mockMvc.perform(get("/time/" + rawDate));

    if (shouldConvert) {
        // Date is successfully parsed and some JSON is returned
        getTime.andExpect(content().contentType(APPLICATION_JSON_UTF8));
    } else {
        // Unsupported rawDate
        getTime.andExpect(status().is(400));
    }
}

以下是参数:

private static Stream<Arguments> args() {
    // true if string should be parsed
    return Stream.of(
            Arguments.of("now", true),
            Arguments.of("today", true),
            Arguments.of("thisOneShouldNotWork", false),
            Arguments.of("2014-11-27", true)
    );
}

正如我所说,测试通过了。

但是从浏览器启动时,在任何请求下都会收到 400 错误。

我如何尝试将转换集成到Spring MVC中(没有一个有效):

  • 覆盖WebMvcConfigurer的方法:

    public class ServletConfig implements WebMvcConfigurer {
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addFormatter(new LocalDateFormatter());
            // ALSO TRIED
            registry.addFormatterForFieldType(LocalDate.class, new LocalDateFormatter());
        }
    }
    
  • 注册FormattingConversionService

    @Bean
    public FormattingConversionService conversionService() {
        var service = new FormattingConversionService();
        service.addFormatter(new LocalDateFormatter());
        return service;
    }
    

有人可以告诉我怎么了吗?

P.S。我知道这不是处理日期的最佳方法,但是由于它在Spring参考中说这应该可行,所以我想尝试一下。

1 个答案:

答案 0 :(得分:2)

定义此bean进行春季引导:

@Bean
    public Formatter<LocalDate> localDateFormatter() {
        return new Formatter<LocalDate>() {
            @Override
            public LocalDate parse(String text, Locale locale) throws ParseException {
                if ("now".equals(text))
                    return LocalDate.now();
                return LocalDate.parse(text, DateTimeFormatter.ISO_DATE);
            }

            @Override
            public String print(LocalDate object, Locale locale) {
                return DateTimeFormatter.ISO_DATE.format(object);
            }
        };
    }

如果您使用Spring MVC定义如下:

@Configuration
@ComponentScan
@EnableWebMvc
public class ServletConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new Formatter<LocalDate>() {
            @Override
            public LocalDate parse(String text, Locale locale) throws ParseException {
                if ("now".equals(text))
                    return LocalDate.now();
                return LocalDate.parse(text, DateTimeFormatter.ISO_DATE);
            }

            @Override
            public String print(LocalDate object, Locale locale) {
                return DateTimeFormatter.ISO_DATE.format(object);
            }
        });
    }
}

不要忘记将实现today的功能作为参数。