Http Post with request content type form not working in Spring MVC 3

后端 未结 7 1551
旧时难觅i
旧时难觅i 2020-12-02 11:13

code snippet:

@RequestMapping(method = RequestMethod.POST)//,  headers = \"content-type=application/x-www-form-urlencoded\")
public ModelAndView create(@Req         


        
相关标签:
7条回答
  • 2020-12-02 11:44

    Unfortunately FormHttpMessageConverter (which is used for @RequestBody-annotated parameters when content type is application/x-www-form-urlencoded) cannot bind target classes (as @ModelAttribute can).

    Therefore you need @ModelAttribute instead of @RequestBody. If you don't need to pass different content types to that method you can simply replace the annotation:

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

    Otherwise I guess you can create a separate method form processing form data with the appropriate headers attribute:

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

    EDIT: Another possible option is to implement your own HttpMessageConverter by combining FormHttpMessageConverter (to convert input message to the map of parameters) and WebDataBinder (to convert map of parameters to the target object).

    0 讨论(0)
  • 2020-12-02 11:49

    I was having HTTP response code of 415

    My problems were resolved when I added Content Type to request header

    e.g

    "Content-Type: application/json"

    0 讨论(0)
  • 2020-12-02 11:54

    At the heart of the problem, we wish to accept both application/json and application/x-www-form-urlencoded Content-types with the same request handler.

    To do this, I use the @RequestBody, which was already working for application/json for me (and generally others from the threads I've found, but there is extra work so application/x-www-form-urlencoded can be used with @RequestBody.

    First, create a new HttpMessageConverter capable of changing the request input to an object. I do this by reusing the FormHttpMessageConverter, which is already capable of changing the input to a MultiValueMap. I then change the MultiValueMap to a regular Map, and use Jackson to turn the Map to the desired object.

    Here is the code for the 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("");
        }
    }
    

    There are many different ways a Spring app might pick up that message converter. For me, it was accomplished in an XML file:

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean class="com.terminal.core.services.config.ObjectHttpMessageConverter"/>
        </mvc:message-converters>
    </mvc:annotation-driven>
    
    0 讨论(0)
  • 2020-12-02 11:57

    I use this code for convert html form to json .

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

    and use single quotations was wrong . I changed ' ' to " " and problem solved.

    0 讨论(0)
  • 2020-12-02 11:59

    Using @ModelAttribute is indeed the preferred way to deal with form parameters.

    0 讨论(0)
  • 2020-12-02 11:59

    Below worked for me

    On server side:

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

    On client side:

    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 讨论(0)
提交回复
热议问题