boxmoe_header_banner_img

Hello! 欢迎来到悠悠畅享网!

文章导读

Struts 2 AJAX JSON响应处理指南


avatar
作者 2025年9月3日 11

Struts 2 AJAX JSON响应处理指南

本教程详细阐述了在struts 2中处理ajax JSON响应的正确方法。针对常见的问题,即AJAX请求收到解析错误或进入错误回调,本文指出直接通过HttpServletResponse写入json并同时使用json结果类型是错误的。核心解决方案是利用Struts 2 JSON插件的特性,将待序列化的数据封装为Action的属性(如map),并通过公共Getter方法暴露,让插件自动完成JSON序列化,从而确保AJAX请求成功接收并解析JSON数据。

理解Struts 2 JSON插件的工作机制

在使用struts 2处理ajax请求并返回json数据时,开发者常会遇到json解析错误或ajax请求进入错误回调函数的问题。这通常源于对struts 2 json插件工作原理的误解。

最初的尝试可能是在Action中手动获取HttpServletResponse的Writer,然后将JSON字符串直接写入响应流,同时在struts.xml中配置result type=”json”。例如:

初始Action代码片段(错误示范):

public class PropertyTesting extends ActionSupport {     public String execute() {         JSONObject obj  = new JSONObject();         obj.put("Name", "PersonName");         obj.put("ID", "PersonID");         try {             ServletActionContext.getResponse().getWriter().write(obj.toJSONString());         } catch (IOException e) {             e.printStackTrace();         }         return SUCCESS;     } }

对应的Struts.xml配置:

<struts>    <constant name="struts.devMode" value="true"/>    <package name="WebTesting" extends="json-default">         <action name="PropertyTesting" class="org.testing.PropertyTesting" >             <result type="json"></result>         </action>    </package> </struts>

这种做法的问题在于:当struts.xml中配置了<result type=”json”></result>时,Struts 2的JSON插件会尝试自动序列化Action类中的属性(通常是那些带有公共getter方法的属性)为JSON格式。如果Action中同时手动写入了响应流,就会导致输出冲突或数据格式不符合预期,从而引发前端AJAX的解析错误。JSON插件预期由它自己来控制响应的输出,而不是由Action手动写入。

正确使用Struts 2 JSON插件

要正确地从Struts 2 Action返回JSON数据给AJAX请求,关键在于让Struts 2 JSON插件接管JSON的序列化过程。这意味着Action类不应该手动写入响应流,而是应该将需要转换为JSON的数据封装为Action的属性,并通过公共的Getter方法暴露出来。JSON插件会自动检测这些属性并将其序列化。

核心思想:

  1. 定义可序列化属性: 在Action类中定义一个属性(例如Map、List、自定义Java Bean等),用于存储要返回的JSON数据。
  2. 提供公共Getter方法: 为这个属性提供一个公共的Getter方法。JSON插件会通过反射调用这个Getter方法来获取数据并进行序列化。
  3. 移除手动写入代码: 从Action的execute方法中移除所有手动写入HttpServletResponse的代码。
  4. 配置json结果类型: 确保struts.xml中Action的结果类型为json,并且所在的包继承了json-default。

示例代码与实现

以下是基于上述原则修正后的Action类和相关配置:

1. Action类 (PropertyTesting.java)

import java.util.HashMap; import java.util.Map; import com.opensymphony.xwork2.ActionSupport;  public class PropertyTesting extends ActionSupport {      // 定义一个Map属性,用于存储需要序列化的数据     private Map<String, String> jsonData;       // 提供公共的Getter方法,JSON插件会通过此方法获取数据     // 注意:方法名通常是 "get" + 属性名首字母大写     public Map<String, String> getJsonData() {         return jsonData;     }      @Override     public String execute() {         // 在execute方法中初始化并填充Map         jsonData = new HashMap<>();         jsonData.put("Name", "PersonName");         jsonData.put("ID", "PersonID");          // 返回SUCCESS,让Struts 2的JSON结果类型处理响应         return SUCCESS;     } }

说明:

  • 我们定义了一个Map<String, String> jsonData作为Action的私有属性。
  • 提供了公共的getJsonData()方法。JSON插件会查找Action中所有具有公共Getter方法的属性,并尝试将其序列化。通常,插件会序列化Action自身的所有属性,但可以通过root参数或excludeProperties等配置进行更精细的控制。在此简单场景下,插件会序列化jsonData。
  • execute()方法现在只负责准备数据并设置到jsonData属性中,不再手动写入响应。

2. jsp页面 (PropertyTesting.jsp)

前端AJAX代码保持不变,因为它已经正确地设置了dataType:”json”,期望接收JSON数据。

<%@ page language="java" contentType="text/html; charset=UTF-8"     pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%>  <html> <head> <meta charset="UTF-8"> <title>Property Testing</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script type="text/JavaScript"> function invokeAjax() {     $.ajax(     {         type:"POST",         url:"PropertyTesting", // 请求Action的URL         dataType:"json",       // 期望接收JSON数据         success: function(responseText)         {             // 成功接收并解析JSON数据             console.log("Success:", responseText);               console.log("Name:", responseText.Name); // 访问JSON数据             console.log("ID:", responseText.ID);         },         error: function(xhr, status, error)         {             // 如果出现错误,这里会打印错误信息             console.log("Error Status:", status);             console.log("Error Message:", error);             console.log("Response Text:", xhr.responseText);         }     }); } </script> </head> <body>     <button type="button" onclick="invokeAjax()" >Submit</button> </body> </html>

3. Struts.xml 配置 (struts.xml)

Struts配置也保持不变,因为json-default包和result type=”json”是正确使用JSON插件的基础。

<struts>    <constant name="struts.devMode" value="true"/>    <package name="WebTesting" extends="json-default">         <action name="PropertyTesting" class="org.testing.PropertyTesting" >             <result type="json"></result>         </action>    </package> </struts>

重要提示:

  • extends=”json-default”:确保你的包继承了json-default,这样才能使用json结果类型。
  • result type=”json”:告诉Struts 2,这个Action的结果应该通过JSON插件进行序列化。
  • struts.devMode:在开发模式下设置为true有助于调试,会提供更详细的错误信息。

总结与注意事项

  • 让插件来做: Struts 2 JSON插件设计用于自动序列化Action的属性。避免在Action中手动写入响应流,这会与插件的功能冲突。
  • 属性与Getter: 任何你希望序列化为JSON的数据都应该作为Action的私有属性,并提供公共的Getter方法。这是JSON插件发现并序列化数据的机制。
  • Action非单例: Struts 2的Action是每次请求都会创建新的实例,因此不必担心在Action中定义属性会导致线程安全问题。你可以放心地在Action中创建和操作实例变量。
  • 数据类型 JSON插件可以序列化各种Java对象,包括Map、List、自定义的Java Bean等。对于简单的键值对,Map是一个非常方便的选择。
  • 调试: 如果仍然遇到问题,请检查浏览器的网络请求,查看服务器返回的原始响应内容。同时,确保struts.devMode为true以获取更详细的Struts 2日志。

通过遵循这些指导原则,你将能够更高效、更稳定地在Struts 2应用中处理AJAX JSON响应。



评论(已关闭)

评论已关闭