浅出:Struts2框架如何优雅地返回JSON数据
在现代Web开发中,前后端分离架构已成为主流趋势,后端服务专注于提供API接口,而前端则负责数据的展示和交互,在这种模式下,JSON(JavaScript Object Notation)因其轻量级、易于解析和阅读的特性,成为了前后端数据交换的事实标准,Struts2作为一款成熟且功能强大的Java Web框架,也提供了非常便捷的方式来处理JSON数据的返回,本文将探讨Struts2框架返回JSON数据的几种主流方法,从配置到代码实现,助您这一核心技能。
核心原理:拦截器与结果类型
要理解Struts2如何返回JSON,首先需要了解其两大核心概念:拦截器和结果类型。
-
拦截器:Struts2的核心是拦截器栈,当请求到达时,它会按照预设的顺序依次通过一系列拦截器,对于JSON返回,最关键的拦截器是
json拦截器(通常位于defaultStack中),这个拦截器会自动将Action中的特定属性序列化为JSON格式的字符串,并设置正确的响应头(如Content-Type: application/json)。 -
结果类型:在
struts.xml配置文件中,<result>标签的type属性决定了Action执行完成后,Struts2如何响应客户端请求,默认的类型是dispatcher(用于服务器端转发),而我们要使用的就是json类型,当type="json"时,Struts2会调用json拦截器来处理响应。
了解了这两个概念后,我们来看具体的实现方式。
使用 json 结果类型(最常用)
这是最直接、最常用的方法,适用于大多数场景,其核心思想是:在Action中定义需要返回给前端的属性,然后在struts.xml中配置一个type="json"的结果。
第一步:创建Action
创建一个普通的POJO(Plain Old Java Object)作为我们的Action,这个POJO的属性将作为JSON数据的键值对。
// User.java
public class User {
private String name;
private int age;
private String email;
// 必须有无参构造函数
public User() {}
// getter 和 setter 方法
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
创建一个Action类来处理请求并准备数据。
// GetUserAction.java
import com.opensymphony.xwork2.ActionSupport;
public class GetUserAction extends ActionSupport {
private User user;
private String status = "success";
private String message = "User data retrieved successfully.";
// Action 的执行方法
public String execute() {
// 模拟从数据库或其他服务获取数据
this.user = new User();
this.user.setName("张三");
this.user.setAge(30);
this.user.setEmail("zhangsan@example.com");
return SUCCESS; // 返回逻辑视图名
}
// getter 和 setter 方法
// Struts2 会自动调用这些 getter 方法来获取要序列化的数据
public User getUser() {
return user;
}
public String getStatus() {
return status;
}
public String getMessage() {
return message;
}
}
关键点:
- Action可以是一个简单的POJO,也可以继承
ActionSupport。 - 所有需要被序列化到JSON中的属性,都必须提供标准的
getter方法,Struts2正是通过调用这些getter来获取数据的。 - Action的
execute()方法返回一个逻辑视图名(如SUCCESS),这个名称将用于匹配struts.xml中的<result>配置。
第二步:配置 struts.xml
在struts.xml中,为我们的Action配置一个type="json"的结果。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<package name="default" extends="struts-default">
<action name="getUser" class="com.example.GetUserAction">
<!-- 配置一个 type="json" 的结果 -->
<result name="success" type="json">
<!-- 可选:指定根节点名称,默认为action的类名(首字母小写) -->
<param name="root">user</param>
</result>
</action>
</package>
</struts>
配置解析:
<result name="success" type="json">:表示当Action返回SUCCESS时,使用json结果类型来处理响应。<param name="root">user</param>:这是一个可选但常用的参数,它告诉json拦截器,将getUser()方法返回的对象作为JSON的根节点,如果不配置,默认会将整个Action对象序列化,导致结果类似{"user":{...}, "status":"success", "message":"..."},如果配置了root="user",则只会序列化user对象,结果为{"name":"张三", "age":30, "email":"..."}。
第三步:测试
启动Tomcat等服务器,通过浏览器或API工具(如Postman、curl)访问Action的URL:
http://localhost:8080/your-project-name/getUser.action
你将收到类似以下的JSON响应:
// 当 <param name="root">user</param> 时
{
"name": "张三",
"age": 30,
"email": "zhangsan@example.com"
}
// 当没有 <param name="root">user</param> 时
{
"user": {
"name": "张三",
"age": 30,
"email": "zhangsan@example.com"
},
"status": "success",
"message": "User data retrieved successfully."
}
使用 @ResponseBody 注解(更现代的方式)
如果你正在使用Struts2与Spring或Spring Boot集成,或者希望采用更符合现代Java Web开发习惯的方式,可以使用@ResponseBody注解,这种方式需要引入struts2-rest-plugin或struts2-convention-plugin,并配置好Spring。
其原理是:通过@ResponseBody注解,告诉框架将方法的返回值直接作为HTTP响应体的内容,并自动通过Jackson或Gson等库序列化为JSON。
示例代码
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.ParentPackage;
import org.apache.struts2.convention.annotation.Result;
import org.springframework.stereotype.Controller;
import com.opensymphony.xwork2.ActionSupport;
// 假设项目已集成Spring
@Controller
@ParentPackage("json-default") // 使用专门用于JSON的包
@Namespace("/api")
public class JsonRestController extends ActionSupport {
@Action(value = "user/{id}", results = {
@Result(type = "json", name = "success", params = {"root", "user"})
})
public String getUserById() {
// ... 获取用户逻辑 ...
this.user = new User();
this.user.setName("李四");
this.user.setAge(25);
this.user.setEmail("lisi@example.com");
return SUCCESS;
}
private User user;
public User getUser() {
return user;
}
}
这种方式更加灵活,尤其是在构建RESTful API时,可以与@Action、@Namespace等注解完美结合,实现基于注解的配置,减少XML的编写量。
高级配置与常见问题
在实际开发中,我们可能需要对JSON的输出进行更精细的控制。
忽略或排除特定属性
默认情况下,Action的所有getter方法都会被序列化,如果某个属性(如密码、内部ID)不希望被返回,可以使用@JSON注解来忽略它。
public class User {
// ... 其他属性
@JSON(serialize=false) // 忽略这个属性的序列化
private String passwordHash;
public String getPasswordHash() {
return passwordHash;
}
}
处理日期格式
默认情况下,日期会被序列化为一个长整型时间戳,为了获得更友好的格式(如yyyy-MM-dd HH:mm:ss),可以进行如下配置:
在struts.xml中全局配置:
<constant name="struts.json.dateFormat" value="yyyy-MM-dd HH:mm:ss"/>
或在Action属性上使用@JSON注解:
public class User {


还没有评论,来说两句吧...