9

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"
                      }

   }  
4

2 に答える 2

0

デフォルトでは、Spring MVC は org.springframework.http.converter.json.MappingJacksonHttpMessageConverter を使用して、Jackson を介して JSON をシリアライズ/デシリアライズします。

それが素晴らしいアイデアかどうかはわかりませんが、問題を解決する 1 つの方法は、このクラスを拡張し、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>
于 2013-01-24T13:05:27.323 に答える
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 コードから独立させます。Spring が自動的に JSON にシリアル化されるように、Jackson をクラスパスに含める必要があるようです (詳細については、こちらを参照してください)。

編集

もっと一般的なものが必要なようです...だから、ここに提案があります。

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

これに関する主な問題: @RequestMapping は、MyControllerおそらく何らかのカスタム アノテーションに置き換える必要があります (そして、このカスタム アノテーションでイントロスペクションを実行するように適応findMethodWithRequestMappingします)。

于 2013-01-23T16:57:56.843 に答える