web-dev-qa-db-ja.com

Spring RESTコントローラーでのHTTPヘッダーの読み取り

SpringベースのREST AP​​IでHTTPヘッダーを読み取ろうとしています。 this に従いました。しかし、私はこのエラーを受け取っています:

クラスJava.lang.Stringのメッセージ本文リーダーが見つかりませんでした。
ContentType:application/octet-stream

私はJavaとSpringが初めてなので、これを理解することはできません。

これは私の呼び出しがどのように見えるかです:

@WebService(serviceName = "common")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public interface CommonApiService {

    @GET
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/data")
    public ResponseEntity<Data> getData(@RequestHeader(value="User-Agent") String userAgent, @DefaultValue ("") @QueryParam("ID") String id);
}

試してみました@Context:この場合、HTTPHeaderはnullです。

HTTPヘッダーから値を取得する方法は?

29
Ashwani K

表示されるエラーは、RequestHeaderとは関係がないようです。

そして、Spring RESTサービスを JAX-RS と混同しているように見える場合、メソッドのシグネチャは次のようになります。

@RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "data")
@ResponseBody
public ResponseEntity<Data> getData(@RequestHeader(value="User-Agent") String userAgent, @RequestParam(value = "ID", defaultValue = "") String id) {
    // your code goes here
}

また、RESTクラスには次のような注釈が必要です。

@Controller
@RequestMapping("/rest/")


実際の質問に関して、HTTPヘッダーを取得する別の方法は、 HttpServletRequest メソッドに追加し、そこから目的のヘッダーを取得します。

例:

@RequestMapping(produces = "application/json", method = RequestMethod.GET, value = "data")
@ResponseBody
public ResponseEntity<Data> getData(HttpServletRequest request, @RequestParam(value = "ID", defaultValue = "") String id) {
    String userAgent = request.getHeader("user-agent");
}

HttpServletRequestのインジェクションについて心配する必要はありません。Springがあなたのためにその魔法を行うからです;)

64

コントローラーのRESTヘッダーの読み方の例を紹介します。コントローラーは、読み取りが必要なデータがある場合にのみ、要求タイプとしてapplication/jsonを受け入れます。あなたの問題は、Springが処理方法を知らないアプリケーション/オクテットストリームを持っていることだと思う。

通常、私のコントローラーは次のようになります。

@Controller
public class FooController {
    @Autowired
    private DataService dataService;

    @RequestMapping(value="/foo/", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<Data> getData(@RequestHeader String dataId){
        return ResponseEntity.newInstance(dataService.getData(dataId);
    }

ここで、バックグラウンドで多くのコードを実行しているので、分解します。

ResponseEntityは、すべてのコントローラーが返すカスタムオブジェクトです。新しいインスタンスを作成できる静的ファクトリーが含まれています。 My Data Serviceは標準のサービスクラスです。

魔法は舞台裏で発生します。JSONを使用しているため、SpringにJacksonを使用してHttpRequestオブジェクトをマッピングし、処理対象を認識させる必要があります。

これを行うには、設定の<mvc:annotation-driven>ブロック内でこれを指定します

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper" ref="objectMapper" />
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

ObjectMapperはcom.fasterxml.jackson.databind.ObjectMapperの単なる拡張であり、Jacksonが実際にリクエストをJSONからオブジェクトにマッピングするために使用するものです。

オクテットストリームをオブジェクトに読み込むことができるマッパーまたはSpringが処理できるものを指定していないため、例外が発生していると思われます。ファイルをアップロードしようとしている場合、それはまったく別のことです。

そのため、コントローラーに送信されるリクエストには、dataIdというヘッダーが追加されているだけです。

これをリクエストパラメータに変更し、@RequestParam String dataIdを使用してリクエストからIDを読み取る場合、リクエストは次のようになります。

contactId : {"fooId"} 

この要求パラメーターは、必要に応じて複雑にすることができます。オブジェクト全体をJSONにシリアル化し、要求パラメーターとして送信すると、Springは(Jacksonを使用して)Javaオブジェクトにシリアル化して、すぐに使用できる状態になります。

コントローラーの例:

@RequestMapping(value = "/penguin Details/", method = RequestMethod.GET)
@ResponseBody
public DataProcessingResponseDTO<Pengin> getPenguinDetailsFromList(
        @RequestParam DataProcessingRequestDTO jsonPenguinRequestDTO)

送信済みリクエスト:

jsonPengiunRequestDTO: {
    "draw": 1,
    "columns": [
        {
            "data": {
                "_": "toAddress",
                "header": "toAddress"
            },
            "name": "toAddress",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "fromAddress",
                "header": "fromAddress"
            },
            "name": "fromAddress",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "customerCampaignId",
                "header": "customerCampaignId"
            },
            "name": "customerCampaignId",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "penguinId",
                "header": "penguinId"
            },
            "name": "penguinId",
            "searchable": false,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "validpenguin",
                "header": "validpenguin"
            },
            "name": "validpenguin",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": {
                "_": "",
                "header": ""
            },
            "name": "",
            "searchable": false,
            "orderable": false,
            "search": {
                "value": "",
                "regex": false
            }
        }
    ],
    "order": [
        {
            "column": 0,
            "dir": "asc"
        }
    ],
    "start": 0,
    "length": 10,
    "search": {
        "value": "",
        "regex": false
    },
    "objectId": "30"
}

自動的にシリアル化されてDataProcessingRequestDTOオブジェクトに戻された後、使用可能な状態のコントローラーに渡されます。

ご覧のとおり、これは非常に強力であり、1行のコードを記述することなく、JSONからオブジェクトにデータをシリアル化できます。 @RequestParamおよび@RequestBodyに対してこれを行うことができます。これにより、パラメーターまたはリクエストボディ内のJSONにそれぞれアクセスできます。

具体的な例を示したので、リクエストタイプをapplication/jsonに変更しても問題はないはずです。

7
JamesENL