Post Http z formularzem typu request content nie działa w Spring MVC 3
Fragment kodu:
@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");
}
Po otrzymaniu żądania otrzymałem kod statusu Http 415: Serwer odmówił tego żądania, ponieważ jednostka żądania jest w formacie, który nie jest obsługiwany przez żądany zasób dla żądanej metody ().
Jeśli zmienię kod na ten:
Fragment kodu:
@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");
}
Dostanę metodę 405 niedozwoloną. Zabawne jest to, że w nagłówku allow odpowiedzi znajduje się lista GET I POST jako dozwolonych metod.
Mam klasę, która Odwzorowanie 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;
}
}
Skopiowane z wiosennych przykładów. działa świetnie z typem zawartości JSON.
Bardziej ogólnym pytaniem jest to, jak sprawić, by programy obsługi żądań MVC spring działały z różnymi typami żądań. Każda rada będzie bardzo mile widziana.
7 answers
Niestety FormHttpMessageConverter
(który jest używany dla @RequestBody
- parametry z adnotacją, gdy typem zawartości jest application/x-www-form-urlencoded
) nie mogą wiązać klas docelowych (jak @ModelAttribute
może).
Dlatego potrzebujesz @ModelAttribute
zamiast @RequestBody
. Jeśli nie musisz przekazywać różnych typów zawartości do tej metody, możesz po prostu zastąpić adnotację:
@RequestMapping(method = RequestMethod.POST)
public ModelAndView create(@ModelAttribute UserAccountBean account) { ... }
W przeciwnym razie można utworzyć osobną metodę przetwarzania danych formularza z odpowiednim atrybutem headers
:
@RequestMapping(method = RequestMethod.POST,
headers = "content-type=application/x-www-form-urlencoded")
public ModelAndView createFromForm(@ModelAttribute UserAccountBean account) { ... }
EDIT: inny możliwy opcja jest zaimplementowanie własnej HttpMessageConverter
przez połączenie FormHttpMessageConverter
(do konwersji wiadomości wejściowej na mapę parametrów) i WebDataBinder
(do konwersji mapy parametrów na obiekt docelowy).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-02 20:34:51
Miałem kod odpowiedzi HTTP 415
Moje problemy zostały rozwiązane, gdy dodałem Content Type do nagłówka żądania
E. g
"Content-Type: application / json"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-20 19:43:17
W samym sercu problemu, chcemy zaakceptować zarówno application / json, jak i application / x-www-form-urlencoded Content-types z tym samym handlerem żądań.
Aby to zrobić, używam @RequestBody, który już działał dla application / json dla mnie (i ogólnie innych z wątków, które znalazłem, ale jest dodatkowa praca, więc application/x-www-form-urlencoded może być używany z @RequestBody.
Najpierw Utwórz nowy HttpMessageConverter, który może zmienić wejście żądania na obiekt. Robię to przez ponowne użycie FormHttpMessageConverter, który jest już w stanie zmienić wejście na wielowartościową mapę. Następnie zmieniam mapę wielowartościową na zwykłą mapę i używam Jacksona, aby obrócić mapę na żądany obiekt.
Oto kod dla 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("");
}
}
Istnieje wiele różnych sposobów, w jaki aplikacja Spring może odebrać ten konwerter wiadomości. Dla mnie zostało to zrealizowane w pliku XML:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="com.terminal.core.services.config.ObjectHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-27 03:17:41
Używanie @ ModelAttribute jest rzeczywiście preferowanym sposobem radzenia sobie z parametrami formularza.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-08 10:37:35
Uĺźycie JSONA rĂłwnieĹź mi dziaĹ ' aĹ 'o, przypuszczam, Ĺźe sprawia, Ĺźe interpreter JSON pobiera dane z ciaĹ' a. Próbowałem użyć PUT, co jest nieco trudniejsze. Możesz przeczytać mój post o tym tutaj.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-28 07:48:16
Poniżej działa dla mnie
Po stronie serwera:
@RequestMapping(value = "test", method = RequestMethod.POST, consumes = {"application/xml", "application/json"})
@ResponseStatus(HttpStatus.OK)
public @ResponseBody
String methodName(@RequestBody EntityClassName entity) {
Po stronie klienta:
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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-01 06:40:50
Używam tego kodu do konwersji formularza html na json .
function ConvertFormToJSON(form) {
var array = $(form).serializeArray();
var json = {};
$.each(array, function() {
json[this.name] = this.value || '';
});
return json;
}
I użycie pojedynczych cytatów było błędne . Zmieniłem na "" i problem rozwiązany.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-27 06:45:27