1 Struct2 ?
Struct2是一个基于MVC设计模式的Web应用层框架。
Struct2中用action取代了Servlet,action是类,里面对Servlet的一些操作进行了封装,可以大大简化代码的复杂度,已经解决了传统Servlet的一些弊端,需要注意的是,action并不是一个脱离Servlet的东西,其底层依然是Servlet 。
2 一个案例入门Struct2
前记 : Struct2开发包与资源下载 , 本文用struct-2.3.24版本 。
案例目标: 使用Struts2框架完成用户的添加功能,使用普通Servlet完成用户列表功能(下一篇中讲解struts2搭配ognl操作值栈的方法)。
2.1 搭建项目环境
Struts2用到的jar包: 导入struts-2.3.24\apps\struts2-blank.war\WEB-INF\lib
下的所有jar包 。
JSTL表达式的jar包(myEclipse不需要) : 自行下载或文尾下载项目中有。
MySQL,创建数据库: create database db_strut ;
DAO采用JPA的开发https://blog.csdn.net/zyqblog/article/details/80725763
User实体类注解配置如下:
/**
* User实体类
* @author zhaoyuqiang
*
*/
@Entity
@Table(name="tb_user")
public class User {
@Id
@Column(name="user_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long userId;
@Column(name="user_name")
private String userName ;
@Column(name="user_age")
private Integer userAge ;
@Column(name="user_phone")
private String userPhone ;
/*
* 此处省略getter和setter方法
*/
}
2.2 配置核心过滤器(web.xml)
过滤器在服务器启动时创建,创建时执行init()方法,该方法会加载配置文件(包含自己创建的struts.xml,以及web.xml和自带的配置文件等)
web.xml
<!--导入约束,该约束在struct-2.3.24\apps\struts2-blank.war\WEB-INF\web.xml中有-->
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
上ctrl+点击,导入struct-2.3.24\src文件夹。
2.3 添加用户.jsp与用户列表.jsp
addUser.jsp
<form action="${pageContext.request.contextPath}/user_addUser.action" method="post">
用户名:<input type="text" name="userName" /><br>
年 龄:<input type="text" name="userAge" /><br>
电 话:<input type="text" name="userPhone" /><br>
<input type="submit" value="添加"/>
</form>
listAll.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<a href="${pageContext.request.contextPath}/user_findAll">点击这里查看所有用户</a>
<table>
<tr>
<td>名字</td>
<td>年龄</td>
<td>手机</td>
</tr>
<c:forEach items="${listUser}" var="user">
<tr>
<td>${user.userName}</td>
<td>${user.userAge}</td>
<td>${user.userPhone}</td>
</tr>
</c:forEach>
</table>
2.4 编写action类
action是一个普通类,完全不用继承或实现任何接口用来完成action的编写,但Struts2提供了2种方法来让action的编写变的更加方便,一种是实现一个Action接口,另一种是继承ActionSupport,而第二张是比较常用的,因为ActionSupport类中提供了很多的默认方法,比Action接口更加强大。
package edu.kmust.action;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import edu.kmust.entity.User;
import edu.kmust.service.UserService;
/**
* User web层
* @author zhaoyuqiang
*
*/
public class UserAction extends ActionSupport implements ModelDriven<User>{
private UserService userService = new UserService()
private User user = new User(); //创建实体类对象
/**
* 添加用户
* @return
*/
public String addUser() {
/**
* struts获取表单并封装数据(方法2): 常用
* 模型驱动封装,要求:
* 1. 表单输入项name属性值和实体类属性名一致
* 2. action要实现ModelDriven<实体类名>接口
* 3. 在action里面手动创建实体类对象
* 4. 实现该接口的getModel方法,并且返回实体类对象
* 完成上述3个要求后,struts2会自动把表单数据封装到实体类对象中
*
*/
/*System.out.println(user.getUserName()+","+user.getUserAge()+","+user.getUserPhone());*/
userService.addUser(user);
return "success_addUser" ;
}
/**
* 查询所有用户
* @return
*/
public String findAll() {
List<User> listUser = userService.findAll();
/**
* 利用Servlet的方式操作域对象 :
* 使用ServletActionContext类
* 只演示request域,session和ServletContext是类似的。
*/
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("listUser", listUser);
return "success_findAll" ;
}
/**
* 跳转到添加页面
* @return
*/
public String toaddPage() {
return "success_toAddPage" ;
}
/**
* 实现ModelDriven接口中的方法
*/
@Override
public User getModel() {
// TODO Auto-generated method stub
return user;
}
}
上述action中,查询所有用户功能用到的是Servlet的那一套原始方法(Struts2+OGNL操作值栈的方法下一篇中说明),添加用户方法中,获取表单数据并封装的方法是Struts2框架中的模型驱动封装方法,这是最常用的方法,除此之外还有其他一些方法:
- Struts框架提供的另一种方法:属性封装
public class UserAction extends ActionSupport {
//定义实体类变量,并生成setter方法
private String userName ;
private int userAge ;
private String userPhone ;
public void setUserName(String userName) {
this.userName = userName;
}
public void setUserAge(int userAge) {
this.userAge = userAge;
}
public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
}
/**
* 添加用户
* @return
*/
public String addUser() {
/**
* struts获取表单并封装数据(方法1)
* 属性封装,要求:
* 1. 在action成员变量位置定义实体变量,要求该变量与表单输入项的name属性之一样
* 2. 生成变量的set方法
* 完成上述两点,则struts2自动把表单数据封装到该实体变量中,缺点是把数据封装到对象中时依然需要最原始的方式
*/
User user = new User();
user.setUserName(userName);
user.setUserAge(userAge);
user.setUserPhone(userPhone); System.out.println(user.getUserName()+","+user.getUserAge()+","+user.getUserPhone());
return "success_addUser" ;
}
}
- Struts框架提供的还有一种方法:表达式封装
public class UserAction extends ActionSupport {
//声明实体类,并且生成set和get方法
private User user ;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
/**
* 添加用户
* @return
*/
public String addUser() {
/**
* struts获取表单并封装数据(方法3)
* 表达式封装,(也可以叫做属性封装的另一种方法),要求:
* 1. action中声明实体类
* 2. 生成实体类的set和get方法
* 3. 表单输入项目的name属性值写表达式形式
* 完成上述3个要求后,struts2会自动把表单数据封装到声明的实体类中
*
*/ System.out.println(user.getUserName()+","+user.getUserAge()+","+user.getUserPhone());
return "success_addUser" ;
}
}
<form action="${pageContext.request.contextPath}/user_add.action" method="post">
用户名:<input type="text" name="user.userName" /><br>
年 龄:<input type="text" name="user.userAge" /><br>
电 话:<input type="text" name="user.userPhone" /><br>
<input type="submit" value="添加"/>
</form>
- Sevlet提供的两种方法:属性封装
/**
* 利用Servlet获取表单数据并封装(方法1) :
* 使用ActionContext类获取
*/
ActionContext context = ActionContext.getContext();
Map<String, Object> map = context.getParameters() ;
//遍历map,查看获取的表单数据
Set<String> keys = map.keySet();
for(String key: keys) {
Object[] obj = (Object[]) map.get(key);
System.out.println(Arrays.toString(obj));
}
/**
* 利用Servlet获取表单数据并封装(方法2) :
* 使用ServletActionContext类获取表单数据 (习惯使用)
*/
HttpServletRequest request = ServletActionContext.getRequest();
String userName = request.getParameter("userName");
int userAge = Integer.valueOf(request.getParameter("userAge"));
String userPhone = request.getParameter("userPhone") ;
//封装到实体类对象中
User user = new User();
user.setUserName(userName);
user.setUserAge(userAge);
user.setUserPhone(userPhone);
System.out.println(user.getUserName()+","+user.getUserAge()+","+user.getUserPhone());
2.5 配置核心配置文件(struts.xml)
根据分模块开发的思想,我的个人配置文件写在了action包下struts_zhaoyuqiang.xml
,核心配置文件struts.xml在src下(名称位置固定)。
struts_zhaoyuqiang.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
导入约束,在struct-2.3.24\apps\struts2-blank.war\WEB-INF\src\java中struts.xml文件,里面有下面的约束
-->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!--
package标签
name : 类似于区分不同类的包一样,该名字用来区分不同action,没有实际意义
extends : 固定值,用来说明package里面配置的类具有Action功能
namespace : 与action标签里面的name值构成访问路径,可以不写
-->
<package name="userDemo" extends="struts-default" namespace="/">
<!--
action标签
name : 指定Action处理请求的URL
class : 指定Action对应的类
method : 指定请求Action时调用的方法,通配符方法,例如user_*_*_*,则{1}、{2}、{3}分别表示从左往右的三个*
result标签
name : 方法返回值
type : dispatcher:跳转到某一个页面
redirect : 重定向到某一页面
redirectAction : 重定向到某一action,路径写目标action的name属性值
-->
<action name="user_*" class="edu.kmust.action.UserAction" method = "{1}">
<result name="success_findAll">/jsp/user/listAll.jsp</result>
<result name="success_toAddPage">/jsp/user/addUser.jsp</result>
<result name="success_addUser" type="redirectAction">user_findAll</result>
</action>
<!-- 上面的通配符表示法是为了简化代码,也可以用下面的普通方法 -->
<!-- <action name="user_toAddPage" class="edu.kmust.action.UserAction">
<result name="success_toAddPage">/jsp/user/addUser.jsp</result>
</action>
<action name="user_addUser" class="edu.kmust.action.UserAction">
<result name="success_addUser" type="redirectAction">user_findAll</result>
</action>
<action name="user_findAll" class="edu.kmust.action.UserAction">
<result name="success_findAll">/jsp/user/listAll.jsp</result>
</action> -->
</package>
</struts>
struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
导入约束,在struct-2.3.24\apps\struts2-blank.war\WEB-INF\src\java中struts.xml文件,里面有下面的约束
-->
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!--
constant标签 : 常量的配置
struts.i18n.encoding :设置编码,用于表单提交数据时的中文乱码处理
-->
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<!-- 导入自己配置的文件 -->
<include file="edu/kmust/action/struts_zhaoyuqiang.xml"></include>
</struts>
3 执行过程分析
上述过程的反射代码,可以写成如下:
Class clazz = Class.forName("action全路径");
Method m = clazz.getMethod("execute"); //得到名称是execute的方法
Object obj = m.invoke(); //方法执行
4 本文代码资源下载
本文完整运行代码下载地址:
! 等本系列写完一起上传 。