【问题标题】:Spring & Jackson(REST): Modify request body before reaching to controller : Add default values to properties if properties are not present in json rqSpring&Jackson(REST):在到达控制器之前修改请求正文:如果json rq中不存在属性,则将默认值添加到属性
【发布时间】:2020-01-22 23:27:01
【问题描述】:

我正在使用 Spring mvc 5.0.8jackson 2.9.8

开发 Rest APIs

如果客户端的 json 请求中不存在分页属性,我想为每个请求设置默认分页。

我通过从 HttpRequestEntity 类构造函数创建 Pagination 对象来实现这一点,但是如果 json 请求中存在分页请求,则 jackson 创建在调用 HttpRequestEntity 的 setter 方法(setPagination(Pagination pagination)) 之前,通过调用 Pagination 类的默认构造函数来增加一个 Pagination 对象强>类。

JackSon 如果 JSON 请求中不存在属性,则既不会创建属性对象也不会触发属性设置器方法

我也尝试过使用 Interceptor prepreHandle

request.setAttribute("pagination", new Pagination());

但这不会更新 HttpServletRequest's 正文,我必须使用 Controller's 参数接收该属性,该参数应使用 @RequestAttribute 进行注释。

根据我的理解 HttpMessageConverter 只映射 HttpServletRequest 正文与 spring 注释 @RequestBody

Json 请求

{
   //not sending pagination
   /*
   "pagination":{
      "offset":0,
      "limit:50
    },
    */
    "data":{
        "requestUrl":"some value"
        ...
    },
    "timeStamp":"Mon Sep 23 2019 02:15:47 GMT+0530 (India Standard Time)"
}

控制器

@RestController
@RequestMapping("/api/v1")
public class LocaldbController {

    @Autowired
    private LocaldbService localdbService;

    @PostMapping("/apidetails/filter")
    public void getAllApiDetails(@RequestBody HttpRequestEntity<ApiDetailsFilterDto> requestEntityDto) {

        System.out.println(requestEntityDto.getPagination().getLimit());
    }
}
public class HttpRequestEntity<T> {

    public Pagination pagination;
    private T data;
    private String timeStamp;

    public HttpRequestEntity() {
        this.pagination = new Pagination(); //To set Default value
    }

    public Pagination getPagination() {
        return pagination;
    }
    public T getData() {
        return data;
    }
    public String getTimeStamp() {
        return timeStamp;
    }
    public void setTimeStamp(String timeStamp) {
        this.timeStamp = timeStamp;
    }

    public void setPagination(Pagination pagination) {
        this.pagination = pagination;
    }

}
public class Pagination {

    private int offset = 0;
    private int limit = 50;

    public Pagination() {
        System.out.println("pagination");
    }

    public int getOffset() {
        return offset;
    }
    public int getLimit() {
        return limit;
    }

    public void setOffset(int offset) {
        this.offset = offset;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }
}

所以任何人都可以告诉我,如果 JSON 请求中不存在属性,如何将 默认值 设置为 属性

感谢您的关注。期待您的回复。

【问题讨论】:

标签: java spring rest pagination jackson


【解决方案1】:

如果您想从分页的构造函数创建一个对象,请再次检查 setter 分页方法

public void setPagination(Pagination pagination) {
If(this.pagination!=null)
this.pagination==null//contructor object set to null
        this.pagination = pagination;
    }

}

我不知道您的实际要求为什么不创建动态分页对象。检查 get Pagination 是否为 null 创建分页对象。创建一个服务类并从控制器调用服务类以获取您的数据,该服务类检查所有数据,如果它为空,则动态创建分页对象意味着如果杰克逊不会命中 setter 方法......可能会有所帮助...

【讨论】:

  • 我想为所有请求添加默认值
【解决方案2】:

我不完全知道请求反序列化背后的逻辑是什么,但我可能建议您将 new Pagination() 调用从构造函数移到字段声明,因为如果某些 Java 可能不会调用构造函数中的逻辑反射魔法发生了。

public class HttpRequestEntity<T> {

    public Pagination pagination = new Pagination();
    ...

我想指出的另一件事是,您不应该担心创建冗余对象,因为像垃圾收集器这样的机制的存在只是为了不必担心内存管理。

编辑:
好的,我看到您很固执地检查是否发送了分页。如果您需要对此进行检查,则说明您做错了错误,因为默认数据应指示默认行为(默认逻辑)并且不应以任何方式阻止您的逻辑。

你也不应该担心每次都会创建默认对象,因为 Java 的内存管理非常高效。

但是,如果您真的想检查分页是默认值还是实际由客户端发送,请使用装饰器模式。

public class HttpRequestEntity<T> {

    public Pagination pagination = new DefaultPagination();
    ...
}

public final class DefaultPagination extends Pagination {
    public DefaultPagination() {
        super();
    }

    @Override
    public void setOffset(int offset) {
        throw new IllegalStateException("Default pagination's state change not allowed");
    }

    @Override
    public void setLimit(int limit) {
        throw new IllegalStateException("Default pagination's state change not allowed");
    }
}

然后你可以检查分页是否为instanceOf DefaultPagination

【讨论】:

  • 我检查了 HttpRequestEntity 类对象是通过调用它的默认构造函数来创建的
  • 如果我可以在创建分页对象之前检查会更方便,如果没有那么我想创建默认对象
  • 如果默认对象将被实际数据替换,为什么需要检查?
  • 看我通过实现上面的代码来满足我的要求,但我想知道是否有任何其他最好的选择来做到这一点。如果我能从 Interceptor 的 中进行管理,那就太好了preHandle,因为拦截器可以在到达控制器之前完成它。感谢您的回复。
  • 是的,我可以做到。这是我正在做的更好的方法。再次感谢您。
猜你喜欢
  • 2018-11-28
  • 2016-04-01
  • 2019-08-16
  • 2018-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-09
  • 2016-02-11
相关资源
最近更新 更多