简体   繁体   English

Spring 启动响应过滤器,用于在发送到客户端之前重组 controller 响应

[英]Spring boot response filter for restructuring controller response before sending to client

I have a couple of spring boot rest controllers, and I want a standard JSON response structure to be sent to the client.我有几个 spring 启动 rest 控制器,我想要一个标准的 JSON 响应结构发送给客户端。

The standard response will be composed of responseTime, apiResponseCode, status, apiName, response ( which will vary based on the api).标准响应将由 responseTime、apiResponseCode、status、apiName、response(根据 api 不同)组成。 See below:见下文:

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

To achieve this, I have created below model class:为了实现这一点,我在下面创建了 model class:

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

To create a generic response wrapper, I have created below response util class.为了创建一个通用的响应包装器,我在下面创建了响应工具 class。

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() {
}
}

Now the ask is that my response from controller should get serialized in the standard way.现在的问题是我对 controller 的回复应该以标准方式序列化。 Shown below is my controller method.下面显示的是我的 controller 方法。

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;
}}

With the current implementation what I'll have to do is that in my controllers I will have to transform the response by calling ResponseUtil.createApplicationResponse() .对于当前的实现,我要做的是在我的控制器中,我必须通过调用ResponseUtil.createApplicationResponse()来转换响应。 This is going to litter the entire controller methods with the createApplicationResponse() method call.这将使用createApplicationResponse()方法调用乱扔整个 controller 方法。

What I wanted to explore is that if there is any cleaner way of achieving this using servlet filters or AOP?我想探索的是,是否有任何更清洁的方法可以使用 servlet 过滤器或 AOP 来实现这一点?

PS: I tried filter option, but couldn't understand how to proceed around it. PS:我尝试了过滤选项,但不明白如何处理它。 Got stuck after retrieving the response.getOutputStream() in doFilter().在 doFilter() 中检索 response.getOutputStream() 后卡住了。

Hope someone can help?希望有人可以帮忙?

Just wrap all your responses into a decorator object.只需将所有响应包装到装饰器 object 中即可。

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

Then wrap this response wrapper into the ResponseEntity然后将此响应包装器包装到ResponseEntity

The response.getOutputStream that you used and filters are servlet related classes, and i think you can do that without them.Just make your custom response class and add fields however you want your response.您使用的 response.getOutputStream 和过滤器是与 servlet 相关的类,我认为您可以在没有它们的情况下做到这一点。只需进行自定义响应 class 并添加字段,但您需要您的响应。 Than in the controller, just return new ResponseEntity(HttpStatus.OK,"your message "): I don't know if this is the behavior you want.比在 controller 中,只需返回 new ResponseEntity(HttpStatus.OK,"your message"):我不知道这是否是您想要的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM