【问题标题】:Spring JSON causes problems when the Spring framework is upgraded from 3.0.2 to 3.2.0Spring JSON 在 Spring 框架从 3.0.2 升级到 3.2.0 时会出现问题
【发布时间】:2012-12-27 19:42:14
【问题描述】:

我正在使用 Spring 框架版本 3.0.2 和 Hibernate (NetBeans 6.9.1) 处理 Web 应用程序。后来我才知道,正如我之前的questions 中提到的那样,有一个错误导致上传多个文件时出现问题。

我已经完成了获得解决方案的努力,但未能成功。因此,我将Spring版本升级为3.2.0

在早期版本 (3.0.2) 中,AJAX 与 Jackson 1.9.8(其下载 page)可以正常工作,但在更高版本 (3.2.0) 中,一切正常,但 AJAX 调用会在任何地方发出错误警报JavaScript 代码。

有一种场景,当在国家选择框中选择了一个国家时,对应的状态列表与DAO一起从Spring控制器中检索出来。 Spring控制器中与URL映射的方法如下,

@RequestMapping(value="ajax/GetStateList", method=RequestMethod.GET)
public @ResponseBody List<Object[]> getStateSelectBox(HttpServletRequest request)
{
    return cityService.getStateSelectBox(request.getParameter("countryId"));
}   

在国家选择框中选择国家时调用该方法。 getStateSelectBox() 方法在 DAO 类之一中定义如下,

@Service
@Transactional(readOnly = true, propagation=Propagation.REQUIRES_NEW)
public final class CityDAO implements CityService
{
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }

    @SuppressWarnings("unchecked")
    public List<Object[]> getStateSelectBox(String id)
    {
        List<Object[]> list = sessionFactory.getCurrentSession()
                          .createQuery("select s.stateId, s.stateName from StateTable s where countryId.countryId=:id order by s.stateId")
                          .setParameter("id", Long.parseLong(id)).list();

       for(Object[]o:list)
       {
           System.out.println(o[0]+" : "+o[1]);
       }
       return list;
   }
}

foreach 循环只是为了演示,它显示了与 AJAX 请求提供的 countryId 相对应的所有状态及其 id,但 List 不返回给 JSP。

用于发送此 AJAX 请求的 JavaScript 代码会发出错误警报。 JSON映射似乎存在一些问题。同样的事情也适用于早期版本的 Spring 框架 (3.0.2)。我不确定为什么这会导致更高版本的 Spring 3.2.0 出现问题。 Spring 3.2.0 版有什么我可能会丢失的吗?


如果您需要查看 JavaScript 代码,实现此目的的完整 JavaScript 代码如下。

function getStates(countryId)
{
    if(countryId==""||countryId==null||countryId==undefined||isNaN(countryId))
    {
        var str="<select id='cmbStates' name='cmbStates' onchange='errorMessage(this.value);' class='validate[required] text-input'><option value=''>Select</option></select>";
        $('#stateList').html(str);
        alert("Please select an appropriate option.");
        return;
    }

    var div=document.createElement("div");
    div.id="temp";
    document.body.appendChild(div);

    $.ajax({
        datatype:"json",
        type: "GET",
        contentType: "application/json",
        url: "/wagafashion/ajax/GetStateList.htm",
        data: "countryId=" + countryId+"&t="+new Date().getTime(),
        success: function(response)
        {
            if(typeof response==='object'&&response instanceof Array)
            {                            
                var str="<select id='cmbState' name='cmbState' onchange='errorMessage(this.value);' class='validate[required] text-input'><option value=''>Select</option>";
                var l=response.length;

                for(var i=0;i<l;i++)
                {
                    str+="<option value='"+response[i][0]+"'>"+$('#temp').text(response[i][1]).html()+"</option>";
                }
                str+="</select>";
                $('#stateList').html(str); // select box is written to #stateList div
                $('#temp').remove();
            }
        },
        error: function(e)
        {
            alert('Error: ' + e);
        }
    });
}            

可以肯定的是,Jackson 库位于类路径中,我在服务器端没有收到任何错误或异常。 AJAX 请求成功,它通过 Spring 进入 DAO,从数据库中检索到 List&lt;Object[]&gt; 类型的列表,但它不是 JSON 对 JSP 的响应(可以/应该映射到 JavaScript 数组)。据推测,JSON 映射似乎缺少某些东西,但早期版本的 Spring 并非如此。


编辑:

我尝试在 3.0.2 和 3.2.0 两个框架中解析 List&lt;Object[]&gt;,例如

List<Object[]> list = cityService.getStateSelectBox(request.getParameter("countryId"));
ObjectMapper objectMapper=new ObjectMapper();
try
{
    objectMapper.writeValue(new File("E:/Project/SpringHibernet/wagafashionLatest/temp.json"), list);
}
catch (IOException ex){}

文件temp.json 包含以下字符串。

[[21,"Gujarat"],[22,"Maharashtra"],[23,"Kerala"],[24,"New Delhi"]]

在这两种情况下(使用两个框架)。因此,两种情况下的 JSON 响应似乎应该相同。

temp.json文件也可以反序列化如下。

try
{
    ObjectMapper mapper=new ObjectMapper();
    List<Object[]> list = mapper.readValue(new File("E:/Project/SpringHibernet/wagafashionLatest/temp.json"), new TypeReference<List<Object[]>>() {});

    for(Object[]o:list)
    {
        System.out.println(o[0]+" : "+o[1]);
    }
} 
catch (IOException ex) 
{

}

它工作正常,foreach 循环遍历List&lt;Object[]&gt; 类型的List。因此,问题可能是由 Spring 框架本身引起的。还需要什么,我不确定。为什么杰克逊没有映射它?

【问题讨论】:

  • 一位聪明的老程序员教我,“阅读错误,修复错误”。始终在您的问题中包含实际的错误消息,这会使一切变得更容易。
  • 在 jQuery 的错误部分中由alerbox 发出和警告的错误是Error: [object Object]。我看不到其他任何东西。
  • 在 chrome 或 firebug 中,您应该能够在执行警报的 error: 部分设置断点,然后您可以查看 e javascript 变量。
  • 谷歌浏览器显示此错误 - Failed to load resource: the server responded with a status of 406 (Not Acceptable)
  • 可以肯定的是,我在dispatcher-servlet.xml 文件中有&lt;mvc:annotation-driven /&gt;

标签: ajax json spring jquery spring-json


【解决方案1】:

我在 Spring 论坛上有相同的 post。最终对我有用的问题的答复中的解决方案需要配置dispatcher-servlet.xml文件,如下所示。

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="favorPathExtension" value="false" />
    <property name="favorParameter" value="false" />
    <property name="ignoreAcceptHeader" value="false" />
    <property name="mediaTypes" >
        <value>
            atom=application/atom+xml
            html=text/html
            json=application/json
            *=*/*
        </value>
    </property>
</bean>

这导致 JSON 与 Jackson 1.9.8 和 Spring 3.2.0 一起工作。这归功于对该问题的所有回复


我的整个 dispatcher-servlet.xml 文件现在如下所示。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">


    <context:component-scan base-package="controller" />
    <context:component-scan base-package="validatorbeans" />

    <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager" />
    <bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
        <property name="favorPathExtension" value="false" />
        <property name="favorParameter" value="false" />
        <property name="ignoreAcceptHeader" value="false" />
        <property name="mediaTypes" >
            <value>
                atom=application/atom+xml
                html=text/html
                json=application/json
                *=*/*
            </value>
        </property>
    </bean>


    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="index.htm">indexController</prop>

            </props>
        </property>
    </bean>

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />

    <bean name="indexController"
          class="org.springframework.web.servlet.mvc.ParameterizableViewController"
          p:viewName="index" />
</beans>

【讨论】:

    【解决方案2】:

    我使用的是 Spring 3.1.3,我发现 Jackson 映射尝试在响应中创建根对象。这与 Jackson2 映射器有关。我还没有尝试过使用较旧的 Jackson 映射器。如果您还升级了 Jackson,您可能会遇到同样的问题。

    过去,对象数组会被映射为

    [{name:'name1',id:4},{name:'name2',id:6}]
    

    现在我发现他们为对象提供了一个自动生成的对象名称,所以它返回类似于

    { objectArray: [{name:'name1',id:4},{name:'name2',id:6}]}
    

    所以你需要引用response.objectArray[0]而不是能够直接引用response[0]

    无论如何,JSON 响应的格式可能有所改变。您应该查看新响应并查看 javascript 中需要发生哪些更改才能使其映射新结构。

    【讨论】:

    • 当我尝试将成功处理程序从 success: function(response) 更改为 success: function(response.objectArray[0]) 时,它会报告编译器错误 - missing ) after formal parameters
    • 谷歌浏览器显示此错误 - Failed to load resource: the server responded with a status of 406 (Not Acceptable)
    • List&lt;Object[]&gt; 在我尝试在 3.0.2 和 3.2.0 这两个框架中都被解析为 [[21,"Gujarat"],[22,"Maharashtra"],[23,"Kerala"],[24,"New Delhi"]]
    • 您的回答开启了新的思考方式。非常感谢您的有用回答。
    • 很高兴你能成功。对我的回答投赞成票将不胜感激,因为它很有帮助,但你接受你的回答而不是我的回答可能更有意义,因为你的回答才是真正让你工作的人。感谢您更新您的工作解决方案。
    猜你喜欢
    • 1970-01-01
    • 2022-12-04
    • 1970-01-01
    • 2014-02-21
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2018-10-08
    • 2017-02-22
    相关资源
    最近更新 更多