用于在发送到客户端之前重新构造控制器响应的Spring引导响应筛选器



我有几个spring-boot-rest控制器,我希望向客户端发送一个标准的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

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

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:我尝试了filter选项,但不明白如何绕过它。在doFilter((中检索响应.getOutputStream((后卡住了。

希望有人能帮忙?

只需将所有响应封装到一个decorator对象中。

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

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

您使用的response.getOutputStream和过滤器都是与servlet相关的类,我认为您可以在没有它们的情况下做到这一点。只需创建自定义响应类,然后根据需要添加字段即可。在控制器中,只需返回新的ResponseEntity(HttpStatus.OK,"您的消息"(:我不知道这是否是你想要的行为。

最新更新