如何使用Spring MVC设计通用的响应构建器/REST风格的Web服务?

6xfqseft  于 2022-11-14  发布在  Spring
关注(0)|答案(3)|浏览(108)

尝试使用Spring MVC构建REST风格的Web服务。
控制器应该返回特定的Java类型,但是响应主体必须是一个通用的信封。
以下代码部分是我目前所拥有的:
控制器方法:

@Controller
    @RequestMapping(value = "/mycontroller")
    public class MyController {

        public ServiceDetails getServiceDetails() {
             return new ServiceDetails("MyService");
        }
    }

响应信封:

public class Response<T> {

        private String message;
        private T responseBody;

    }

ServiceDetails代码:

public class ServiceDetails {

        private String serviceName;

        public ServiceDetails(String serviceName) {
            this.serviceName = serviceName;
        }
    }

对客户的预期最终响应应显示为:

{

     "message" : "Operation OK"
     "responseBody" : {
                        "serviceName" : "MyService"
                      }

   }
atmip9wb

atmip9wb1#

你可以用MyRestController把结果 Package 在Response中,如下所示:

@Controller
@RequestMapping(value = "/mycontroller")
public class MyRestController {

    @Autowired
    private MyController myController;

    @RequestMapping(value = "/details")
    public @ResponseBody Response<ServiceDetails> getServiceDetails() {
         return new Response(myController.getServiceDetails(),"Operation OK");
    }
}

这个解决方案保持了原始的MyController独立于REST代码。看起来你需要在类路径中包含Jackson,这样Spring就可以自动序列化为JSON(详细信息请参见this)。

编辑

看起来你需要更通用的东西...所以这里有一个建议。

@Controller
@RequestMapping(value = "/mycontroller")
public class MyGenericRestController {

    @Autowired
    private MyController myController;

    //this will match all "/myController/*"
    @RequestMapping(value = "/{operation}")
    public @ResponseBody Response getGenericOperation(String @PathVariable operation) {
          Method operationToInvoke = findMethodWithRequestMapping(operation);
          Object responseBody = null;
          try{
               responseBody = operationToInvoke.invoke(myController);
          }catch(Exception e){
               e.printStackTrace();
               return new Response(null,"operation failed");
          }
         return new Response(responseBody ,"Operation OK");
    }

    private Method findMethodWithRequestMapping(String operation){
         //TODO
         //This method will use reflection to find a method annotated
         //@RequestMapping(value=<operation>)
         //in myController
         return ...
    }
}

并保持原始的“myController”几乎不变:

@Controller
public class MyController {

    //this method is not expected to be called directly by spring MVC
    @RequestMapping(value = "/details")
    public ServiceDetails getServiceDetails() {
         return new ServiceDetails("MyService");
    }
}

主要问题:MyController中@RequestMapping可能需要替换为一些自定义注解(并调整findMethodWithRequestMapping以在此自定义注解上执行内省)。

v2g6jxz6

v2g6jxz62#

默认情况下,Spring MVC使用org.springframework.http.converter.json.MappingJacksonHttpMessageConverter通过Jackson对JSON进行序列化/反序列化。
我不确定这是否是个好主意,但解决问题的一种方法是扩展该类,并覆盖writeInternal方法:

public class CustomMappingJacksonHttpMessageConverter extends MappingJacksonHttpMessageConverter {

    @Override
    protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        super.writeInternal(new Response(object, "Operation OK"), outputMessage);
    }
}

如果使用XML配置,则可以按如下方式启用自定义转换器:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="path.to.CustomMappingJacksonHttpMessageConverter">
    </mvc:message-converters>
</mvc:annotation-driven>
ekqde3dh

ekqde3dh3#

请尝试以下解决方案。
1.创建一个单独的类,如ResponseEnvelop。它必须实现ResponseBodyAdvice接口。
1.使用***@ControllerAdvice*注解上面的类
1.自动联机
HttpServlet请求**
1.根据您的要求覆盖方法。请参考以下内容。

@Override
  public boolean supports(
      MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    if (httpServletRequest.getRequestURI().startsWith("/api")) {
      return true;
    }
    return false;
  }

@Override
  public Object beforeBodyWrite(
      Object body,
      MethodParameter returnType,
      MediaType selectedContentType,
      Class<? extends HttpMessageConverter<?>> converterType,
      ServerHttpRequest request,
      ServerHttpResponse response) {

    if (((ServletServerHttpResponse) response).getServletResponse().getStatus()
            == HttpStatus.OK.value()
        || ((ServletServerHttpResponse) response).getServletResponse().getStatus()
            == HttpStatus.CREATED.value()) {
      return new EntityResponse(Constants.SUCCESS, body);
    }
    return body;
  }

相关问题