ExtJS 4 Spring 3 загрузка файла. Сервер отправляет неверный тип контента ответа - PullRequest
2 голосов
/ 11 августа 2011

Я создавал загрузку файлов, используя внешний интерфейс ExtJS 4 и Spring 3 в качестве внутреннего. Загрузка файла работает, но ответ с сервера имеет неправильный тип содержимого. Когда я посылаю {success:true}, используя Map<String, Object>, сериализованный Джексоном, ExtJS возвращает ошибку

<code>Uncaught Ext.Error: You're trying to decode an invalid JSON String: <pre style="word-wrap: break-word; white-space: pre-wrap;">{"success":true}

Почему мой ответ обернут тегом <pre>? Я искал и обнаружил , что я должен изменить тип ответа, например, на text/html. Но изменение типа контента в ответе сервлета не помогло

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody Map<String, Object> upload(
    FileUpload uploadItem, BindingResult result, HttpServletResponse response) {

    response.setContentType("text/html");

    // File processing   

    Map<String, Object> jsonResult = new HashMap<String, Object>();
    jsonResult.put("success", Boolean.TRUE);
    return jsonResult;
}

Когда я изменяю возвращаемое значение метода upload на String, все работает правильно, но я хочу вернуть Map и сделать его сериализованным Джексоном

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody String upload(
    FileUpload uploadItem, BindingResult result, HttpServletResponse response) {

    // File processing   

    return "{success:true}";
}

Конфигурация My Spring

<bean 
    id="stringHttpMessageConverter" 
    class="org.springframework.http.converter.StringHttpMessageConverter">
</bean>
<bean 
    id="jacksonMessageConverter" 
    class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>  
<bean    
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <ref bean="jacksonMessageConverter"/>
            <ref bean="stringHttpMessageConverter" />
        </list>
    </property>
</bean>

Как сказать Spring, чтобы он возвращал правильный тип содержимого? Почему ответ этого метода неверен, если ответ других методов интерпретируется правильно?

Ответы [ 4 ]

2 голосов
/ 05 сентября 2011

Вам необходимо задать тип содержимого ответа как "text / html".Если тип контента "application / json" будет иметь эту проблему.Странно.

1 голос
/ 31 декабря 2011

Вы можете вернуть логическое значение, если вам нужно только вернуть значение успеха:

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody boolean upload(
    FileUpload uploadItem, BindingResult result, HttpServletResponse response) {

    return true; //or false
}
0 голосов
/ 20 июля 2012

Я думаю, что вы можете использовать атрибут «производит» аннотации Spring @RequestMapping:

@RequestMapping(value = "/upload", method = RequestMethod.POST, produces = MediaType.TEXT_HTML_VALUE)
public @ResponseBody Map<String, Object> upload(
    FileUpload uploadItem, BindingResult result, HttpServletResponse response) {

    // File processing   

    Map<String, Object> jsonResult = new HashMap<String, Object>();
    jsonResult.put("success", Boolean.TRUE);
    return jsonResult;
}

В конфигурационном файле вы должны сделать этот тип контента доступным:

<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
    <property name="supportedMediaTypes">
        <array>
            <value>text/html</value>
            <value>application/json</value>
        </array>
    </property>
</bean>  

Это доступно в Spring 3.1.1.RELEASE, возможно, в старых версиях это не работает.

0 голосов
/ 17 января 2012

Ну, не совсем лучшее решение, но оно решает проблему.Я создал класс, который имеет Map внутри и метод для добавления параметров в Map.Также реализован метод toString().

public class ExtJSJsonResponse {

    /** Parameters to serialize to JSON */
    private Map<String, Object> params = new HashMap<String, Object>();

    /**
     * Add arbitrary parameter for JSON serialization. 
     * Parameter will be serialized as {"key":"value"};
     * @param key name of parameter
     * @param value content of parameter
     */
    @JsonIgnore
    public void addParam(String key, Object value) {
        params.put(key, value);
    }

    /**
     * Gets all parameters. Also is annotated with <code>@JsonValue</code>.
     * @return all params with keys as map
     */
    @JsonValue
    public Map<String, Object> getParams() {
        return params;
    }

    /**
     * Returns specified parameter by <code>key</code> as string "key":"value"
     * @param key parameter key 
     * @return  "key":"value" string or empty string when there is no parameter 
     *          with specified key
     */
    private String paramToString(String key) {
        return params.containsKey(key) 
            ? "\"" + key + "\":\"" + params.get(key) + "\""
            : "";
    }

    /**
     * Manually transforms map parameters to JSON string. Used when ExtJS fails 
     * to decode Jackson response. i.e. when uploading file.
     * @return 
     */
    @Override
    @JsonIgnore
    public String toString() {
        StringBuilder sb = new StringBuilder("{");
        String delimiter = "";

        for (String key : params.keySet()) {
            sb.append(delimiter);
            sb.append(paramToString(key));
            delimiter = ",";
        }

        sb.append("}");
        return sb.toString();
    }
}

Поэтому, когда происходит Uncaught Ext.Error: You're trying to decode an invalid JSON String, вы просто делаете это

@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody String upload(
    FileUpload uploadItem, BindingResult result, HttpServletResponse response) {
    ExtJSJsonResponse response = new ExtJSJsonResponse();

    // File processing
    response.addParam("success", true);
    response.addParam("message", "All OK");   

    return response.toString();
}

В других методах, которые не имеют проблем с сериализациейможно просто позвонить return response; и он будет автоматически сериализован.

Метод toString() будет работать только для простых классов, таких как String.Для более сложных классов вам придется изменить его.

...