Подтвердить что ты не робот

Http Post с формой типа содержимого запроса, не работающей в Spring MVC 3

фрагмент кода:

@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 Метод не допускается. Забавно, что в заголовке ответа есть ответ, он перечисляет 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 работать с разными типами содержимого запроса. Любые советы будут очень признательны.

4b9b3361

Ответ 1

К сожалению FormHttpMessageConverter (который используется для @RequestBody -аннотированных параметров, когда тип содержимого application/x-www-form-urlencoded) не может связывать целевые классы (как @ModelAttribute can).

Поэтому вам нужно @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) { ... }

EDIT: Еще один возможный вариант - реализовать собственный HttpMessageConverter, объединив FormHttpMessageConverter (чтобы преобразовать входное сообщение в карту параметров) и WebDataBinder (чтобы преобразовать карту параметров в целевой объект).

Ответ 2

У меня был HTTP-код ответа 415

Мои проблемы были устранены, когда я добавил Content Type для запроса заголовка

например

"Content-Type: application/json"

Ответ 3

В основе проблемы мы хотим принять и Content-типы application/json и application/x-www-form-urlencoded с тем же обработчиком запросов.

Для этого я использую @RequestBody, который уже работал для приложения /json для меня (и, как правило, другие из тем, которые я нашел, но есть дополнительная работа, поэтому application/x-www-form-urlencoded может использоваться с @RequestBody.

Сначала создайте новый HttpMessageConverter, способный изменять ввод запроса на объект. Я делаю это, повторно используя 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

Использование @ModelAttribute действительно является предпочтительным способом обработки параметров формы.

Ответ 5

Использование JSON также работало для меня, я полагаю, это делает интерпретатор JSON для получения данных из тела. Я пытался использовать PUT, хотя это немного сложнее. Вы можете прочитать мое сообщение об этом здесь.

Ответ 6

Ниже работал у меня

На стороне сервера:

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

Ответ 7

Я использую этот код для преобразования html-формы в json.

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

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

                        return json;
                    }

и использование одиночных котировок было неправильным. Я изменил "на" и "решить проблему".