2013-01-23 21 views
6

Cố gắng xây dựng một dịch vụ web RESTful bằng Spring MVC.Tôi làm cách nào để thiết kế một Dịch vụ web phản hồi/RESTful chung bằng cách sử dụng Spring MVC?

Bộ điều khiển phải trả về các loại Java cụ thể, nhưng phần thân phản hồi phải là một phong bì chung. Điều này có thể giải quyết như thế nào?

Những phần sau của mã là những gì tôi có cho đến nay: Phương pháp

Bộ điều khiển:

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

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

đáp ứng phong bì:

public class Response<T> { 

     private String message; 
     private T responseBody; 

    } 

ServiceDetails mã:

public class ServiceDetails { 

     private String serviceName; 

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

Dành trả lời cuối cùng cho các khách hàng sẽ xuất hiện như:

{ 

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

    } 
+0

Nếu bạn đang sử dụng Jackson hoặc FlexJson, tại sao bạn không thể trả lại đối tượng phản hồi trong phương pháp của mình? Trình serializer JSON có thể tuần tự hóa bất kỳ đối tượng phức tạp nào. – CodeChimp

+0

Tôi đang sử dụng jackson. nhưng tôi vẫn muốn bộ điều khiển trả về các loại java yêu cầu cụ thể. tôi nghĩ rằng nó sạch hơn và trực quan hơn. –

+0

cộng với có một số mã tấm nồi hơi vào việc xây dựng đối tượng phản hồi, vì vậy tôi muốn làm điều đó chỉ từ một nơi –

Trả lời

0

Những gì bạn có thể làm là có một MyRestController chỉ gói kết quả trong một Response như thế này:

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

Giải pháp này giữ nguyên MyController độc lập của bạn từ mã REST của bạn. Có vẻ như bạn cần phải bao gồm Jackson trong classpath của bạn để mùa xuân sẽ tự động một cách kỳ diệu serialize để JSON (xem this để biết chi tiết)

EDIT

Có vẻ như bạn cần một cái gì đó chung chung hơn ... vì vậy đây là lời đề nghị.

@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 ... 
    } 
} 

Và giữ gốc "MyController" của bạn gần như là nó là:

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

vấn đề lớn với điều này: các @RequestMapping trong MyController cần có thể được thay thế bằng một số chú thích tùy chỉnh (và thích ứng findMethodWithRequestMapping để thực hiện nội dung về chú thích tùy chỉnh này).

+0

điều là tôi muốn tránh viết Phản hồi mới() nhiều lần. tôi muốn cho người thực hiện các phương pháp điều khiển để không phải nhận thức được phong bì Response, nhưng chỉ trả về một loại cụ thể và cho interceptor để lấy loại đó và chèn vào phong bì phản ứng. –

+0

Còn về trường tin nhắn thì sao? Ai đó cần điền nó ở đâu đó ... – ben75

+0

@Eli vừa chỉnh sửa bài đăng của tôi với đề xuất chung chung hơn – ben75

0

Theo mặc định, Spring MVC sử dụng org.springframework.http.converter.json.MappingJacksonHttpMessageConverter để tuần tự hóa/deserialize JSON thông qua Jackson.

Tôi không chắc chắn nếu đó là một ý tưởng tuyệt vời, nhưng là một cách để giải quyết vấn đề của bạn là mở rộng lớp này, và ghi đè lên các phương pháp 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); 
    } 
} 

Nếu bạn đang sử dụng cấu hình XML, bạn có thể bật trình chuyển đổi tùy chỉnh như sau:

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

trông đẹp mắt. nhưng điều đó có nghĩa là bộ chuyển đổi này sẽ được sử dụng cho tất cả các bộ điều khiển của tôi? tôi cần nó chỉ cho một cụ thể ... là nó có thể? về cơ bản những gì tôi mặc dù là để ghi đè lên các MappingJacksonJsonView và sử dụng xem tùy chỉnh như xem cho bộ điều khiển cụ thể, nhưng điều đó dường như không hoạt động. mùa xuân luôn sử dụng chế độ xem jackson mặc định vì một số lý do –

+0

Tôi thực sự không chắc chắn cách đặt một công cụ chuyển đổi cụ thể cho chỉ một bộ điều khiển duy nhất. Tẻ nhạt, nhưng có lẽ một giải pháp có thể chấp nhận được là tạo ra một bối cảnh mùa xuân riêng biệt (tức là servlet) cho bộ điều khiển cụ thể này? – reidarok

Các vấn đề liên quan