一次获取多个参数的映射

Get mapping with multiple params as once

我有这样的映射:

@GetMapping(value = "/topics", params = "dateRange")
public Set<Integer> getTopicsInRange(@RequestParam DateRange dateRange) {
    return topicService.getTopicsInRange(dateRange);
}

现在我想测试它:

private final static DateRange VALID_DATE_RANGE = new DateRange(LocalDate.of(2018, 1, 1), LocalDate.of(2018, 2, 2));

@Test
public void gettingTopicsInRangeShouldReturn200(){
    given().
    .when()
    .get(String.format("/topics?dateRange=%s", VALID_DATE_RANGE)
    .then()
    .statusCode(200);
}

Expected status code <200> doesn't match actual status code <400>.

我知道如果我将我的 DateRange 参数更改为 2 个单独的参数,我的解决方案就会起作用:

@GetMapping(value = "/topics", params = {"begin", "end"})
public Set<Integer> getTopicsInRange(@RequestParam Date begin, @RequestParam Date end) {
    return topicService.getTopicsInRange(begin, end);
}

然后将其测试为 /topics?begin=value&end=value2 但这不是我要找的(如果 DateRange 会喜欢 10 个字段使 10 个参数我认为真的太多了) 有什么想法可以解决我的问题吗?

编辑 这是我的日期范围 class:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class DateRange {
    LocalDate begin;
    LocalDate end;
}

添加DateTimeFormat注释:

public class DateRange {

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate begin;

    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate end;

    // getter and setters
}

在控制器中接收对象:

@GetMapping(value = "/topics")
public Set<Integer> getTopicsInRange(DateRange dateRange) {
    return topicService.getTopicsInRange(dateRange);
}

并分别发送参数:

@Test
public void gettingTopicsInRangeShouldReturn200() {
    given()
    .queryParams("begin", LocalDate.of(2018, 1, 1).format(ISO_DATE),
        "end", LocalDate.of(2018, 2, 2))
    .when()
    .get("/topics")
    .then()
    .statusCode(200);
}

您需要一种方法将 DateRange class 转换为 String,反之亦然。由于您使用的是 Spring,因此可以这样做:

1) 添加转换逻辑

@Data
@AllArgsConstructor
@NoArgsConstructor
public class DateRange {

    LocalDate begin;
    LocalDate end;

    private static final String DELIMITER = "_";

    public static DateRange fromFormattedString(String source) {
        if (source != null) {
            String[] tokens = source.split(DELIMITER);
            if (tokens.length == 2) {
                return new DateRange(
                        LocalDate.parse(tokens[0]), // begin
                        LocalDate.parse(tokens[1])  // end
                );
            }
        }
        return null;
    }

    public String toFormattedString() {
        return begin + DELIMITER + end;
    }
}

2) 创建 Spring 转换器

import org.springframework.core.convert.converter.Converter;

public class DateRangeConverter implements Converter<String, DateRange> {

    @Override
    public DateRange convert(String source) {
        return DateRange.fromFormattedString(source);
    }
}

3) 注册这个转换器

这将允许 Spring 处理作为 @RequestParam-s

传递的 DateRange 对象
@Configuration
public class WebApiConfiguration extends WebMvcConfigurationSupport {
    ...
    @Override
    public FormattingConversionService mvcConversionService() {
        FormattingConversionService f = super.mvcConversionService();
        f.addConverter(new DateRangeConverter());
        return f;
    }
    ...
}

最后像这样使用:

.get(String.format("/topics?dateRange=%s", VALID_DATE_RANGE.toFormattedString())

或(使用原始字符串):

.get(String.format("/topics?dateRange=%s", "2018-1-1_2018-2-2")

但是:

尽管如此,我还是建议您使用单独的请求参数(开始、结束等),即使它们有 10 个,因为它是:

1) RESTful 方式

2)防错,因为传入的是订单请求参数,所以不严格。另一方面,将参数打包到单个对象中会迫使您注意参数顺序。此外,您必须将所有参数打包为字符串,因此不允许使用可选参数,否则解包逻辑可能会被破坏