【问题标题】:Jackson Field filter in Spring MVCSpring MVC 中的 Jackson Field 过滤器
【发布时间】:2018-06-14 18:08:19
【问题描述】:

我有一个 Spring Boot 应用程序,我需要从 RequestParam 中过滤响应正文

例子:

  // DTO
   public class PersonDTO
   {
      private Long id;
      private String firstName;
      private String lastName;
   }

   // Controller
   public class PersonController
   {
      @GetMapping(value = "/person")
      public ResponseEntity<List<PersonDTO>> getPerson(@RequestParam(required = false) String filters)
      {
         List<PersonDTO> personList = myservoce.getPerson();
         return new ResponseEntity<List<PersonDTO>>(personList, HttpStatus.OK);
      }
   }

客户端查询示例:

返回所有没有字段过滤器的人

http://localhost:8080/person

[
  {
    "id": 123,
    "firstName": "toto1",
    "lastName": "titi2"
  },
  {
    "id": 345,
    "firstName": "toto2",
    "lastName": "titi2"
  }
]

返回所有人,响应只包含名字和姓氏: http://localhost:8080/person?filters=firstName,lastName

[
  {
    "firstName": "toto1",
    "lastName": "titi2"
  },
  {
    "firstName": "toto2",
    "lastName": "titi2"
  }
]

我找到了这个 API “jackson-dynamic-filter”,但是过滤器被用作这样的注释:

public class PersonController
{
   @FilterOutAllExcept({"firstName", "lastName"})
   @GetMapping(value = "/person")
   public ResponseEntity<List<PersonDTO>> getPerson( @RequestParam(required = false) String filters )
   {
      List<PersonDTO> personList = myservoce.getPerson();
      return new ResponseEntity<List<PersonDTO>>(personList, HttpStatus.OK);
   }
}

在我的情况下,我无法使用此 API,因为字段过滤器列表由客户端管理,并且每次调用都可能不同,而我的真实有效负载 D 包含很多字段

我也找到了这个 API “jackson-antpathfilter”,但它对我不起作用,而且响应类型是 MappingJacksonValue 而不是 ResponseEntity>

知道如何使用 spring 应用程序配置这个用例吗?

【问题讨论】:

  • 这里有同样的问题。我不敢相信没有一种干净简单的方法可以做到这一点。您是否找到了解决此问题的另一种方法而不是您写的答案?我尝试更改 spring 配置以检索 ObjectMapper 并在使用 ResponseEntity 调用 return 之前对其进行配置,但后来我遇到了其他类型的奇怪问题,我不知道如何解决,这让我觉得这不是正确的方法解决问题。
  • 我在下面添加了一个临时解决方案

标签: java json spring spring-mvc jackson


【解决方案1】:

我暂时找到了这个解决方案:

@ControllerAdvice
public class JsonFilterAdvice implements ResponseBodyAdvice<List<?>>
{

   @Override
   public List<?> beforeBodyWrite(
      List<?> arg0,
      MethodParameter arg1,
      MediaType arg2,
      Class<? extends HttpMessageConverter<?>> arg3,
      ServerHttpRequest arg4,
      ServerHttpResponse arg5)
   {
      HttpServletRequest servletRequest = ((ServletServerHttpRequest) arg4).getServletRequest();
      String[] params = servletRequest.getParameterValues("filters");
      if (params != null)
      {
        // parse object and set field to null
      }
      return arg0;
   }

   @Override
   public boolean supports(MethodParameter arg0, Class<? extends HttpMessageConverter<?>> arg1)
   {
      // return true if method parameters contain 'filters' field
      return true;
   }

欢迎提出其他建议

【讨论】:

    【解决方案2】:

    您可以将Jackson lib的注释@JsonIgnore添加到过滤字段id:

    public class PersonDTO implements Serializable
    {
      @JsonIgnore
      private Long id;
      private String firstName;
      private String lastName;
    }
    

    【讨论】:

    • PersonDto 只是一个例子!在这个例子中,过滤器可以是一些字段(id & firstName)(lastName & firstName)(id)(firstName)的组合......所以如果我们为特定字段添加注释@JsonIgnore,过滤器不能是动态的,请看我的回答
    【解决方案3】:

    这是来自我的网络服务,您可以使用此代码并适应您的模型和存储库。从此您可以创建一个通用服务并在需要时调用修改后的版本。

        @RequestMapping(value = "/entidades/{id}/campos", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
        @ApiOperation(value = "Retrieves requested object fields", response = Entidade.class)
        public ResponseEntity<Map<String, Object>> getFields(@Valid @PathVariable Long id, @RequestParam String campos) {
            final Optional<Entidade> ent = entidadeRepository.findById(id);
            final String[] camposArr = campos.split(",");
    
            if (ent.isPresent()) {
                final Entidade e = ent.get();
                Map<String, Object> result = new HashMap<>();
                for (String campo : camposArr) {
                    String methodName = "get" + (campo.substring(0, 1).toUpperCase() + campo.substring(1));
    //                System.out.println(campo);
                    try {
                        Method method = e.getClass().getMethod(methodName);
    //                    System.out.println(method.invoke(e));
                        result.put(campo, method.invoke(e));
                    } catch (Exception err) {
                    }
    
                }
                return new ResponseEntity<>(result, HttpStatus.OK);
    
            }
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-10
      • 1970-01-01
      • 2021-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多