尝试使用Spring MVC构建RESTful 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"
}
}
答案 0 :(得分:0)
你可以做的是让MyRestController
将结果包装成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
以对此自定义注释执行内省)。
答案 1 :(得分:0)
默认情况下,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>