【问题标题】:@RestController with @ModelAttribute using custom setters@RestController 和 @ModelAttribute 使用自定义设置器
【发布时间】:2020-01-04 12:41:32
【问题描述】:

我有我的@RestController,他的参数映射到@ModelAttribute 以缩短参数列表。但是,某些属性必须转换为自定义对象(即 Long -> Instant)。我的问题是有没有办法让 spring 使用我的设置器来设置这些对象?

控制器映射

@GetMapping("/v1/my/path")
public Collection<Dto> getAll(@ModelAttribute MyRequest request) {
    return someSevice.doSomething(request);
}

ModelAttribute 类

public class MyRequest {
    private Instant startTime;
    private Instant endTime;
    private ZoneId timezone;

    // How can make spring use this setter to set start time?
    private void setStartTimeFromLong(Long startTime) {
        this.startTime = Instant.ofEpochSecond(startTime);
    }
}

【问题讨论】:

  • 也许没有办法实现
  • A custom InitBinder editor 可能是这里最直接的方法。也就是说,由于这是一个GET,通常的模型是“请求”是一组查询参数,我建议检查现有的 Spring 对 Querydsl 作为 MVC 参数的支持。

标签: java spring


【解决方案1】:

您始终可以为您的对象使用自定义反序列化

查看下一个link

public class ItemDeserializer extends StdDeserializer<Item> {

    public ItemDeserializer() {
        this(null);
    }

    public ItemDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Item deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        int id = (Integer) ((IntNode) node.get("id")).numberValue();
        String itemName = node.get("itemName").asText();
        int userId = (Integer) ((IntNode) node.get("createdBy")).numberValue();

        return new Item(id, itemName, new User(userId, null));
    }
}

【讨论】:

  • 这是一个 GET 请求,并非所有库都支持带有 GET 请求的 JSON 负载。如果您使用 Jackson,您的解决方案将使用 JSON 有效负载。不幸的是,在这种情况下我不能使用 JSON。感谢您的帮助!
  • 你试过了吗? :) Jackson with spring 不仅适用于 JSON body vales
  • 这是 Jackson 序列化,如果 OP 使用 @RequestBody 和 JSON,这将起作用,但不适用于 @ModelAttribute
  • 我没有,你是对的。但是,@chrylis 也有同样的看法。
  • @chrylis 您能否提供文档链接?我会有所帮助:)
【解决方案2】:

实现您自己的转换器似乎是解决此问题的最佳解决方案,因为无法注释用于填充 @ModuleAttribute 的 setter。

@Component
public class StringToInstantConverter implements Converter<String, Instant> {

    @Override
    public Instant convert(String epochSeconds) {
        return Instant.ofEpochSecond(Long.valueOf(epochSeconds));
    }
}

【讨论】:

  • 这是一个不错的方法,但你必须小心,你可能会遇到其他对象的意外转换器问题
  • 同意,每次我期望InstantString 将转换为Long,然后转换为Instant
猜你喜欢
  • 2021-06-16
  • 2013-01-25
  • 1970-01-01
  • 2015-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
相关资源
最近更新 更多