ExtJS 4 Spring 3文件上传。服务器发送错误的响应内容类型

时间:2011-08-11 09:20:17

标签: json spring extjs upload response

我使用ExtJS 4前端和Spring 3作为后端创建文件上传。文件上传有效,但服务器的响应内容类型错误。当我使用杰克逊序列化的{success:true}发送Map<String, Object>时,ExtJS会返回错误

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>

为什么我的回复包含<pre>标记?我已经搜索并found out我应该将响应类型更改为text/html。但changing content type in servlet response没有帮助

@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}";
}

我的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 个答案:

答案 0 :(得分:2)

您需要将响应的内容类型设置为“text / html”。 如果内容类型是“application / json”则会出现此问题。这很奇怪。

答案 1 :(得分:1)

如果只需要返回成功值,则可以返回布尔值:

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

    return true; //or false
}

答案 2 :(得分:0)

嗯,这不是最好的解决方案,但它解决了这个问题。我创建了一个类,里面有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。对于更复杂的课程,您必须更改它。

答案 3 :(得分:0)

我认为你可以使用Spring的@RequestMapping注释的“produce”属性:

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

在配置文件中,您应该使此Content-Type可用:

<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中可用,可能在旧版本中它不起作用。