
理解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.xml中配置了
正确使用Struts 2 JSON插件
要正确地从Struts 2 Action返回JSON数据给AJAX请求,关键在于让Struts 2 JSON插件接管JSON的序列化过程。这意味着Action类不应该手动写入响应流,而是应该将需要转换为JSON的数据封装为Action的属性,并通过公共的Getter方法暴露出来。JSON插件会自动检测这些属性并将其序列化。
核心思想:
- 定义可序列化属性: 在Action类中定义一个属性(例如Map、List、自定义Java Bean等),用于存储要返回的JSON数据。
- 提供公共Getter方法: 为这个属性提供一个公共的Getter方法。JSON插件会通过反射调用这个Getter方法来获取数据并进行序列化。
- 移除手动写入代码: 从Action的execute方法中移除所有手动写入HttpServletResponse的代码。
- 配置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 jsonData;
// 提供公共的Getter方法,JSON插件会通过此方法获取数据
// 注意:方法名通常是 "get" + 属性名首字母大写
public Map 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
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"%>
Property Testing
3. Struts.xml 配置 (struts.xml)
Struts配置也保持不变,因为json-default包和result type="json"是正确使用JSON插件的基础。
重要提示:
- 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响应。










