web-dev-qa-db-ja.com

Spring MVC 3で機能しないリクエストコンテンツタイプフォームを持つHTTPポスト

コードスニペット:

@RequestMapping(method = RequestMethod.POST)//,  headers = "content-type=application/x-www-form-urlencoded")
public ModelAndView create(@RequestBody UserAccountBean account) {
    try{
        accounts.put(account.assignId(), account);
    }catch(RuntimeException ex)
    {
        return new ModelAndView("account/registerError");
    }
    return new ModelAndView("account/userVerification");
}

リクエストを受信した後、取得したのはHTTPステータスコード415です。リクエストエンティティの形式が、リクエストされたメソッド()のリクエストされたリソースでサポートされていないため、サーバーはこのリクエストを拒否しました。

コードをこれに変更すると:

コードスニペット:

@RequestMapping(method = RequestMethod.POST,headers = "content-type=application/x-www-form-urlencoded")
public ModelAndView create(@RequestBody UserAccountBean account) {
    try{
        accounts.put(account.assignId(), account);
    }catch(RuntimeException ex)
    {
        return new ModelAndView("account/registerError");
    }
    return new ModelAndView("account/userVerification");
}

405 Method not allowedが表示されます。おかしなことは、応答の許可ヘッダーにあり、許可されたメソッドとしてGETおよびPOSTをリストします。

JOSNマッピングを行うクラスがあります:

@Component
public class JacksonConversionServiceConfigurer implements BeanPostProcessor {

private final ConversionService conversionService;

@Autowired
public JacksonConversionServiceConfigurer(ConversionService conversionService) {
    this.conversionService = conversionService;
}

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof AnnotationMethodHandlerAdapter) {
        AnnotationMethodHandlerAdapter adapter = (AnnotationMethodHandlerAdapter) bean;
        HttpMessageConverter<?>[] converters = adapter.getMessageConverters();
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJacksonHttpMessageConverter) {
                MappingJacksonHttpMessageConverter jsonConverter = (MappingJacksonHttpMessageConverter) converter;
                jsonConverter.setObjectMapper(new ConversionServiceAwareObjectMapper(this.conversionService));
            }               
        }
    }
    return bean;
}

}

Springの例からコピー。 JSONコンテンツタイプに最適です。

より一般的な質問は、Spring mvcリクエストハンドラを異なるリクエストコンテンツタイプで動作させる方法です。どんなアドバイスも大歓迎です。

35
Bobo

残念ながらFormHttpMessageConverter(コンテンツタイプが@RequestBodyのときにapplication/x-www-form-urlencodedアノテーション付きパラメーターに使用)は、ターゲットクラスをバインドできません(@ModelAttributeのように)。

したがって、@ModelAttributeの代わりに@RequestBodyが必要です。そのメソッドに異なるコンテンツタイプを渡す必要がない場合は、注釈を単純に置き換えることができます。

@RequestMapping(method = RequestMethod.POST)
public ModelAndView create(@ModelAttribute UserAccountBean account) { ... }

そうでなければ、適切なheaders属性を使用してフォームデータを処理する別のメソッドフォームを作成できると思います。

@RequestMapping(method = RequestMethod.POST, 
    headers = "content-type=application/x-www-form-urlencoded") 
public ModelAndView createFromForm(@ModelAttribute UserAccountBean account) { ... }

編集:別の可能なオプションは、HttpMessageConverter(入力メッセージをパラメーターのマップに変換する)とFormHttpMessageConverter(マップを変換する)を組み合わせて、独自のWebDataBinderを実装することです。ターゲットオブジェクトへのパラメーターの)。

55
axtavt

415のHTTP応答コードがありました

リクエストヘッダーにコンテンツタイプを追加すると問題が解決しました

例えば

「コンテンツタイプ:application/json」

22
user1306828

問題の中心にあるのは、同じリクエストハンドラでapplication/jsonとapplication/x-www-form-urlencoded Content-typesの両方を受け入れることです。

これを行うために、私はすでにapplication/jsonで動作していた@RequestBodyを使用します(そして一般的に私が見つけたスレッドの他のものですが、application/x-www-form-urlencodedを使用できるように余分な作業があります@RequestBodyを使用します。

まず、オブジェクトへの要求入力を変更できる新しいHttpMessageConverterを作成します。これを行うには、FormHttpMessageConverterを再利用します。FormHttpMessageConverterは、MultiValueMapへの入力を既に変更できます。次に、MultiValueMapを通常のマップに変更し、Jacksonを使用してマップを目的のオブジェクトに変更します。

HttpMessageConverterのコードは次のとおりです。

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import Java.io.IOException;
import Java.util.List;
import Java.util.Map;

/**
 * <p>Converts HTTP requests with bodies that are application/x-www-form-urlencoded or multipart/form-data to an Object
 * annotated with {@link org.springframework.web.bind.annotation.RequestBody} in the the handler method.
 *
 * @author Jesse Swidler
 */
public class ObjectHttpMessageConverter implements HttpMessageConverter<Object> {

    private final FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
    private final ObjectMapper objectMapper = new ObjectMapper();

    private static final LinkedMultiValueMap<String, String> LINKED_MULTI_VALUE_MAP = new LinkedMultiValueMap<>();
    private static final Class<? extends MultiValueMap<String, ?>> LINKED_MULTI_VALUE_MAP_CLASS
            = (Class<? extends MultiValueMap<String, ?>>) LINKED_MULTI_VALUE_MAP.getClass();

    @Override
    public boolean canRead(Class clazz, MediaType mediaType) {
        return objectMapper.canSerialize(clazz) && formHttpMessageConverter.canRead(MultiValueMap.class, mediaType);
    }

    @Override
    public boolean canWrite(Class clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return formHttpMessageConverter.getSupportedMediaTypes();
    }

    @Override
    public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        Map<String, String> input = formHttpMessageConverter.read(LINKED_MULTI_VALUE_MAP_CLASS, inputMessage).toSingleValueMap();
        return objectMapper.convertValue(input, clazz);
    }

    @Override
    public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws UnsupportedOperationException {
        throw new UnsupportedOperationException("");
    }
}

Springアプリがそのメッセージコンバーターを取得する方法は多数あります。私にとっては、XMLファイルで実現されました。

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="com.terminal.core.services.config.ObjectHttpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>
4
jswidler

@ModelAttributeを使用することは、実際にフォームパラメーターを処理するための推奨される方法です。

2
Rossen

JSONを使用してもうまくいきましたが、JSONインタープリターが本体からデータを取得できると思います。しかし、私はPUTを使用しようとしていましたが、これは少し難しいです。それについての私の投稿を読むことができます こちら

0
TheZuck

このコードを使用して、htmlフォームをjsonに変換します。

function ConvertFormToJSON(form) {
                        var array = $(form).serializeArray();
                        var json = {};

                        $.each(array, function() {
                            json[this.name] = this.value || '';
                        });

                        return json;
                    }

そして、単一引用符を使用するのは間違っていました。 「」を「」に変更し、問題を解決しました。

0
Amin Arab

以下は私のために働いた

サーバー側:

 @RequestMapping(value = "test", method = RequestMethod.POST, consumes = {"application/xml", "application/json"})
        @ResponseStatus(HttpStatus.OK)
        public @ResponseBody
        String methodName(@RequestBody EntityClassName entity) {

クライアント側:

String json = new JSONStringer().object()
                        .key("key").value("value")
                        .endObject()
                        .toString();
StringEntity se = new StringEntity(json);
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
request.setEntity(se);
HttpResponse response = client.execute(request);
0
Deepti Kohli