[英]Modify HTTP code when Serialize skipping objects conditionally that meet a Custom Criteria with Jackson (Spring boot)
因此,我能够按照提供的链接对满足自定义标准的 Jackson 有条件地跳过对象进行序列化。 链接: https : //www.baeldung.com/jackson-serialize-field-custom-criteria
注意:我可以在没有过滤器的情况下做到这一点。
所以我基本上在做什么,检查一个属性,如果它没有设置,我跳过返回整个对象。 所以我得到了什么(基于教程示例):
HTTP: 200
PATH: /users
RESPONSE:
[
{
"name":"john"
},
{
"name":"adam",
"address":{
"city":"ny",
"country":"usa"
}
}
]
但是如果我们遇到一个案例返回一个隐藏的单个用户,我们将面临这样的问题:
HTTP: 200
PATH: /users/tom
RESPONSE: /**empty response**/
在这种特殊情况下,我想返回一个带有 404 错误代码的 HTTP 响应,而不是像 jackson 那样的 200。 调试时,Jackson 在控制器之后序列化,所以我无法拦截它。
我正在考虑实现拦截器,它可以拦截杰克逊响应编写器,然后如果为空,则返回 404 错误代码。
...我没有想法,经验泄漏。 :/
有谁知道如何做到这一点?
编辑::20200323
按照@Tomoki_Sato 的回答,我找到了解决方案。 在尝试了他的回答后,它首先不起作用。 经过调查,问题出在类型不匹配上。
在我的控制器中,我总是返回ResponseEntity<?>
,它没有实现Hideable
类。
所以我的解决方案就是这样,支持ResponseEntity<<? implements Hideable>>
ResponseEntity<<? implements Hideable>>
&& <? implements Hideable>
<? implements Hideable>
响应:
@RestControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Hideable> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
//if returnType is <? implements hideable>
if (Hideable.class.isAssignableFrom(returnType.getParameterType()) && MappingJackson2HttpMessageConverter.class.isAssignableFrom(converterType)) {
return true;
}
//if returnType is ResponseEntity<<? implements hideable>>
List<Type> actualTypeArguments = Lists.newArrayList(((ParameterizedType) returnType.getGenericParameterType()).getActualTypeArguments());
if (actualTypeArguments.isEmpty()) {
return false;
}
try {
Class<?> responseClass = Class.forName(actualTypeArguments.get(0).getTypeName());
return Hideable.class.isAssignableFrom(responseClass) && MappingJackson2HttpMessageConverter.class.isAssignableFrom(converterType);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return false;
}
@Override
public Hideable beforeBodyWrite(
Hideable hideable, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response
) {
if (hideable == null || hideable.isRemoved()) {
response.setStatusCode(HttpStatus.NOT_FOUND);
return null;
}
return hideable;
}
}
谈到效率,我没有测试过,我相信我们必须在许多类型上测试它,比如ResponseEntity<List<? implements Hideable>>
ResponseEntity<List<? implements Hideable>>
, ResponseEntity<Set<? implements Hideable>>
ResponseEntity<Set<? implements Hideable>>
....
在理论上,我相信@RestControllerAdvice
不会在这里干扰,并且 JSON 序列化器正在率先转换响应......我不知道。
我希望这对其他人有帮助:)
您可以通过实现ResponseBodyAdvice
在 Jackson 编写响应之前自定义ResponseBodyAdvice
。
如果您想在user
为 null 或hidden
时设置404
HTTP 状态代码,您的ResponseBodyAdvice
实现将是这样的:
@ControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice<Hidable> {
/**
* Supports `? extends Hidable`, `ResponseEntity<? extends Hidable>` and
* `HttpEntity<? extends Hidable>` handled by
* `MappingJackson2HttpMessageConverter`
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
if (!MappingJackson2HttpMessageConverter.class.isAssignableFrom(converterType)) {
return false;
}
Class<?> parameterType = returnType.getParameterType();
// if returnType is <? extends Hidable>
if (Hidable.class.isAssignableFrom(parameterType)) {
return true;
}
// if returnType is ResponseEntity<? extends Hidable> or HttpEntity<? extends
// Hidable>
if (HttpEntity.class.isAssignableFrom(parameterType)) {
Type[] actualTypeArguments = ((ParameterizedType) returnType.getGenericParameterType())
.getActualTypeArguments();
if (actualTypeArguments == null || actualTypeArguments.length != 1) {
return false;
}
try {
return Hidable.class.isAssignableFrom(Class.forName(actualTypeArguments[0].getTypeName()));
} catch (ClassNotFoundException e) {
// e.g. returnType is ResponseEntity<List<Hideable>>
e.printStackTrace();
}
}
return false;
}
@Override
public Hidable beforeBodyWrite(Hidable hidable, MethodParameter returnType, MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
ServerHttpResponse response) {
if (hidable == null || hidable.isHidden()) {
response.setStatusCode(HttpStatus.NOT_FOUND);
return null;
}
return hidable;
}
}
编辑::20200324
我根据上面EDIT::20200323 中的代码片段改进了我的答案,以便ResponseBodyAdvice
不仅可以支持Hidable
还可以支持ResponseEntity
和HttpEntity
。
我想建议您检查HttpEntity
( ResponseEntity
的超类)是否可以从parameterType
分配,以便您可以防止您的ResponseBodyAdvice
支持意外的参数类型,如List<Hidable>
。 如果ResponseBodyAdvice
支持List<Hidable>
, ClassCastException
发生在beforeBodyWrite
。
也可以看看
Spring 框架文档 - Web on Servlet Stack - 1.1.6。 拦截
ResponseBodyAdvice 的 Java 文档
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.