Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何使用SpringMVC设计通用响应生成器/RESTfulWeb服务?_Java_Rest_Spring Mvc - Fatal编程技术网

Java 如何使用SpringMVC设计通用响应生成器/RESTfulWeb服务?

Java 如何使用SpringMVC设计通用响应生成器/RESTfulWeb服务?,java,rest,spring-mvc,Java,Rest,Spring Mvc,尝试使用SpringMVC构建RESTfulWeb服务 控制器应该返回特定的Java类型,但响应主体必须是通用信封。如何做到这一点 到目前为止,我掌握了以下代码部分: 控制器方法: @Controller @RequestMapping(value = "/mycontroller") public class MyController { public ServiceDetails getServiceDetails() {

尝试使用SpringMVC构建RESTfulWeb服务

控制器应该返回特定的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;

    }
对客户的预期最终回复应如下所示:

   {

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

   }  

您可以使用
MyRestController
将结果包装成
响应
,如下所示:

@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”原样:

@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
以对该自定义注释执行内省)。

默认情况下,SpringMVC使用org.springframework.http.converter.json.MappingJacksonHttpMessageConverter通过Jackson对json进行序列化/反序列化

我不确定这是否是个好主意,但解决问题的一种方法是扩展此类,并重写writeInternal方法:

公共类CustomMappingJacksonHttpMessageConverter扩展了MappingJacksonHttpMessageConverter{
@凌驾
受保护的void writeInternal(对象对象,HttpOutputMessage outputMessage)引发IOException,HttpMessageGenetWritableException{
super.writeInternal(新响应(对象,“操作正常”),outputMessage;
}
}
如果您使用的是XML配置,则可以如下所示启用自定义转换器:

@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");
    }
}


如果您使用的是Jackson或FlexJson,为什么不能在方法中返回响应对象呢?JSON序列化程序应该能够序列化任何复杂对象。但我仍然希望控制器返回特定于请求的java类型。我认为它更简洁、更直观。另外,在构建响应对象时有一些锅炉板代码,所以我只想从一个地方开始,我推荐的方法与@ben75所述的方法相同:创建包装器对象,返回它,让Jackson处理JSON的序列化。我一直都是这么看的。您可以直接返回对象,也可以使用Jackson转换为字符串并返回该字符串。当我并不真正关心生成的JSON是什么样子时,我使用了前一种方法(即我控制接收器,因此我可以让它做任何需要的事情),当我不控制接收器时,我使用了后一种方法(即其他人指定了格式)。关键是(at)ResponseBody告诉Spring获取返回的任何内容并将其用作HttpResponse主体,还有一些来自Spring的漂亮的PFM使用Jackson将对象自动转换为JSON。我甚至使用(at)ResponseBody返回二进制文件,比如图像。问题是我想避免多次编写新的Response()。我希望实现控制器方法的人不必知道响应信封,只需返回一个特定的类型,拦截器就可以采用该类型并插入到响应信封中。非常感谢您的全面回复。但我真的想避免使用包装器控制器,而且我也不太喜欢使用反射。看起来我的最佳解决方案将来自reidarok在下面写的东西。你能分享一下你的见解吗?谢谢,看起来不错。但这意味着这个转换器将用于我所有的控制器?我需要它只是为了一个特定的…有可能吗?基本上,我的想法是覆盖MappingJacksonJsonView并使用自定义视图作为特定控制器的视图,但这似乎不起作用。出于某些原因,spring总是使用默认的jackson视图。我真的不知道如何为单个控制器设置特定的转换器。单调乏味,但也许可以接受的解决方案是为这个特定的控制器创建一个单独的spring上下文(即servlet)?
@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");
    }
}