【问题标题】:Add custom header to REST PUT request将自定义标头添加到 REST PUT 请求
【发布时间】:2019-11-14 03:27:26
【问题描述】:

我有一个使用带有 Angular 前端的 Spring Boot 2.1.8 的应用程序。我已经使用@RepositoryRestResource 定义了我的存储库。 Spring Boot 应用程序基本上为 Angular 提供了一个 REST API。该应用程序定义了几个业务实体,REST 响应为每个实体提供了 CRUD 功能。以下是其中一个实体的典型 repo 接口:

// REST resouce /api/privgroups
@RepositoryRestResource(collectionResourceRel = "privgroups", path = "privgroups")
public interface PrivGroupRepository extends CrudRepository<PrivGroup, Long>
{
   List<PrivGroup> findAll();
}

GETing 和单个实体、POSTing(创建实体)和 PUTing(更新实体)都可以正常工作,但我想在更新(HTTP PUT)实体时返回自定义标头。 Angular 端将使用标头来显示特定于该实体的自定义 toastr 消息。由于存储库还实现了 REST 接口,我不确定如何添加会根据目标实体更改的特定标头。

我开发的应用程序包含一个 REST 控制器,该控制器调用一个服务,该服务又调用一个存储库。在这种情况下,我有更多的控制权,可以轻松地返回自定义标题,如下所示:

@PutMapping("/{id}")
public ResponseEntity<MyEntity> updateMyEntity(@PathVariable("id") Long id, @RequestBody MyEntity myEntity)
{
    MyEntity updatedEntity = this.MyEntityService.updateMyEntity(MyEntity);
    return ResponseEntity.ok()
        .header("X-Save", "MyEntity")
        .body(updatedEntity);
}

我可以使用更新的“内置”技术来实现这一点吗?我知道我可以使用过滤器添加标题,并且我已经阅读了有关该主题的几篇文章。我认为很难识别正在更新的实体,我不确定这是最好的方法。

请注意这篇文章: Rest API - how add custom headers? 真的老了。 Spring数据休息文档https://docs.spring.io/spring-data/rest/docs/current/reference/html/ 没有关于该主题的任何具体内容。

【问题讨论】:

    标签: spring-boot spring-data-rest


    【解决方案1】:

    我最近使用过 Spring Data Rest,但没有找到任何“内置”技术。但是,您可以通过在使用 @ControllerAdvice 注释的类中实现 ResponseBodyAdvice 接口来实现。我是这样得到的:

    @ControllerAdvice
    public class PutMyEntityBodyAdvice implements ResponseBodyAdvice<Object> {
    
        @Override
        public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    
            // Write the condition to check if beforyBodyWrite should be called
            return returnType.getParameterType().equals(ResponseEntity.class);
        }
    
        @Override
        public Object beforeBodyWrite(Object object, MethodParameter returnType, MediaType selectedContentType,
                                      Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                      ServerHttpRequest request, ServerHttpResponse response) {
    
            // Check if it is a PUT request for MyEntity object
            if (HttpMethod.PUT.equals(request.getMethod()) && object instanceof PersistentEntityResource) {
                PersistentEntityResource persistentEntityResource = (PersistentEntityResource) object;
                if (persistentEntityResource.getContent().getClass().equals(MyEntity.class)) {
                    // Add custom header or manipulate response object
                    response.getHeaders().add("X-Save", "MyEntity");
                }
            }
            return object;
        }
    }
    

    【讨论】:

    • 使用这种技术对我来说效果很好。我能够将我的标题更改隔离到一个类中,并且也可以轻松添加与 POST 相关的标题。
    • 请注意,HTTP DELETE 操作不适用于此方法。我相信这是因为 http DELETE 的 Spring Data REST 接口不返回 ResponseEntity 类型的对象。事实上,DELETE 操作应该返回“无内容”204。
    【解决方案2】:

    @pepevalbe 的回答看起来很有希望。

    替代方案可能是 - 正如您所建议的 - 使用标准 Servlet 过滤器或 Spring HandlerInterceptor。

    要解决在这种情况下获取对修改实体的引用的问题,您可以注册一个 Spring Data Rest 事件侦听器,该事件侦听器将简单地将对修改实体的引用存储在 ThreadLocal 存储中,从那里可以在过滤器中检索它或处理程序拦截器。

    https://www.baeldung.com/java-threadlocal

    https://docs.spring.io/spring-data/rest/docs/current/reference/html/#events.application-listener

    【讨论】:

      猜你喜欢
      • 2016-11-14
      • 2017-12-14
      • 1970-01-01
      • 2013-11-13
      • 2018-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多