【问题标题】:Spring boot response filter for restructuring controller response before sending to client用于在发送到客户端之前重构控制器响应的 Spring Boot 响应过滤器
【发布时间】:2020-08-01 04:16:53
【问题描述】:

我有几个 Spring Boot 休息控制器,我希望将标准 JSON 响应结构发送到客户端。

标准响应将由 responseTime、apiResponseCode、status、apiName、response(根据 api 有所不同)组成。见下文:

{
"responseTime": "2020-04-19T08:36:53.001",
"responseStatus": "SUCCESS",
"apiResponseCode": "SUCCESS",
"apiName": "PROPERTY_STORE_GET_PROPERTIES",
"response": [
    {
        "propertyName": "app.name",
        "propertyValue": "property-store"
    }
]
}

为此,我创建了以下模型类:

package com.example.response.model;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.example.constants.ApiResponseCode;
import com.example.constants.Status;

public class ApplicationResponse<T> implements Serializable {
   private static final long serialVersionUID = -1715864978199998776L;
   LocalDateTime responseTime;
   Status responseStatus;
   ApiResponseCode apiResponseCode;
   String apiName;
   T response;

   public ApplicationResponse(LocalDateTime responseTime, Status status, 
          ApiResponseCode apiRespCode, String apiName, T response) {
    this.responseTime = responseTime;
    this.responseStatus = status;
    this.apiResponseCode = apiRespCode;
    this.apiName = apiName;
    this.response = response;
}

// getters and setters

为了创建一个通用的响应包装器,我在响应工具类下面创建了。

import java.time.LocalDateTime;
import com.example.constants.ApiResponseCode;
import com.example.constants.Status;
import com.example.response.model.ApplicationResponse;

public class ResponseUtil {
    public static <T> ApplicationResponse<T> createApplicationResponse(String 
         apiName, T response) {
         return new ApplicationResponse<>(LocalDateTime.now(), 
               Status.SUCCESS, ApiResponseCode.SUCCESS, apiName,
               response);
}

private ResponseUtil() {
}
}

现在的问题是我来自控制器的响应应该以标准方式序列化。下面显示的是我的控制器方法。

package com.example.propertystore.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RestController;
import com.example.constants.ApiResponseCode;
import com.example.constants.Status;
import com.example.exception.ApplicationException;
import com.example.exception.ApplicationExceptionHelper;
import com.example.propertystore.constants.PropertyStoreApiName;
import com.example.propertystore.dto.PropertyDTO;
import com.example.propertystore.entity.Property;
import com.example.propertystore.service.PropertyStoreService;
import com.example.response.ResponseUtil;
import com.example.response.model.ApplicationResponse;

@RestController
public class PropertyStoreControllerImpl implements PropertyStoreController {

@Autowired
PropertyStoreService propertyStoreService;

@Autowired
ApplicationExceptionHelper exceptionHelper;

@Override
public ApplicationResponse<List<PropertyDTO>> getProperties() throws ApplicationException {
    ApplicationResponse<List<PropertyDTO>> response = null;
    try {
        response = ResponseUtil.createApplicationResponse(
            PropertyStoreApiName.PROPERTY_STORE_GET_PROPERTIES.toString(),
                propertyStoreService.getProperties());
    } catch (Exception e) {
        exceptionHelper.raiseApplicationException( HttpStatus.INTERNAL_SERVER_ERROR, Status.FAILURE,
                ApiResponseCode.INTERNAL_SERVER_ERROR,
                PropertyStoreApiName.PROPERTY_STORE_GET_PROPERTIES.toString(), null);
    }
    return response;
}}

对于当前的实现,我必须在我的控制器中通过调用 ResponseUtil.createApplicationResponse() 来转换响应。这将使用 createApplicationResponse() 方法调用来处理整个控制器方法。

我想探索的是,是否有任何更简洁的方法可以使用 servlet 过滤器或 AOP 来实现这一点?

PS:我尝试了过滤选项,但不明白如何处理它。在 doFilter() 中检索 response.getOutputStream() 后卡住了。

希望有人能帮忙?

【问题讨论】:

  • 也许可以更改 Jackson ObjectMapper 或注册自定义转换器?

标签: java spring spring-boot servlets


【解决方案1】:

只需将所有响应包装到一个装饰器对象中。

class ResponseDecorator<T> {
  //global.fields (time,code, status.....)
  T response;
}

然后将此响应包装器包装到ResponseEntity

【讨论】:

    【解决方案2】:

    您使用的 response.getOutputStream 和过滤器是与 servlet 相关的类,我认为没有它们您也可以做到这一点。只需创建您的自定义响应类并添加您想要响应的字段即可。比在控制器中,只需返回 new ResponseEntity(HttpStatus.OK,"your message"): 不知道这是不是你想要的行为。

    【讨论】:

    • 问题是我希望代码是通用的,所以说我的控制器 1 返回 List 并且控制器 2 返回 Map ...我想要的是它应该是在一处变形。如果我在控制器级别进行转换,我将引入代码重复,这是我想避免的。
    猜你喜欢
    • 1970-01-01
    • 2017-06-09
    • 2020-08-11
    • 1970-01-01
    • 2022-11-04
    • 1970-01-01
    • 2020-02-29
    • 1970-01-01
    • 2015-11-04
    相关资源
    最近更新 更多