学习视屏地址https://www.bilibili.com/video/av13748042/index_1.html#page=1
文件配置
- 导入9个必备jar到classes
- 复制struts.xml到src下
复制web.xml
struts.xml下文件解释:
配置后可以不用重启服务器
区分重名
package
—寻址顺序
localhost:8080/web项目 –> struts.xml –> namespace –> action –> result
namespace
决定了action的访问路径, 默认为”“,表示可以接受所有路径的action
namespace可以写成/ 或者 /xxx/yyy 对应的action访问路径为/index.action, /xxx/index.action, 或/xxx/yyy/index.action, namespace最好也用模块来进行命名, namespace如果要自定义,必须要以’/’开头
struts.xml 内容
1.package
1.干什么: 类似于代码包, 区别不同的action, 要配置action,必须要首先写package标签, 在package里面才能配置action
2. name属性: 区分不同package
3. extends属性: 继承struts-default, 才有action的功能
4. namespace属性: 和action中的name属性组合, 默认不写为’/’
2.action
1.name属性: 同action的name值不能相同,和package中的namespace属性组合
2.class属性: action类的全路径
3.method属性:action默认执行action中的excute方法, 使用这个属性后可以指定自定义的方法
result
1.根据action类的方法的返回值, 配置到不同的路里面,
2. name属性: 和action类方法的返回值一样
3. type属性: 配置如何到路径中(转发或重定向) 默认是转发
include (分模块开发)
用来引入package文件
action类3种编写方式
- 创建普通类, 不继承任何类, 不实现任何接口, 写上execute()
- 实现接口
import com.opensymphony.xwork2.Action;
public class MyAction implements Action{
public String execute(){
//return "Hello_struts";
return SUCCESS; //本身就是一个字符串
}
}
3.继承类
import com.opensymphony.xwork2.ActionSupport;
public class OneAction extends ActionSupport{
@Override
public String execute() throws Exception {
return super.execute();
}
}
excute()
返回值 可以是String 还可以是void
若要返回空的String 可以先继承类, 在返回Action.NONE
此方法返回的非空字符串在struts.xml必须要有对应的name,否则会网页报错
访问action类的三种方法
- 使用action标签的method属性, 在这个属性里执行action的方法
*创建一个action类使用自定义的方法, 可以不适用execute(),需要在struts.xml中配置methon
public class OneAction extends ActionSupport{
public String add(){
System.out.println("add..");
return "hello";
}
public String update(){
System.out.println("update..");
return NONE;
}
}
*struts.xml, 通过访问localhost:8080/项目名/addAction 就会跳转到Hello.jsp上去
<struts>
<!-- 定义常量, devMode 开发模式, 不用重启tomcat -->
<constant name="struts.devMode" value="true" />
<package name="default" namespace="/" extends="struts-default">
<action name="addAction" class="struts2.OneAction" method="add"><!-- uri根据name来访问 -->
<result name="hello">
Hello.jsp
</result>
</action>
<action name="updateAction" class="struts2.OneAction" method="update"></action>
</package>
</struts>
- 使用通配符方式
action类同上
struts.xml, {1}表示填充*号
<package name="default" namespace="/" extends="struts-default">
<action name="action_*" class="struts2.OneAction" method="{1}">
<result name="hello">Hello.jsp</result>
</action>
</package>
通配符解释
https://www.bilibili.com/video/av13748042/index_6.html#page=17
3. 动态访问(不用)
全局结果页面
创建两个action 类,要求两个action都会调到同一个jsp上可以在struts.xml中这么写(也叫做局部结果页面)
<package name="default" namespace="/" extends="struts-default">
<action name="one" class="struts2.OneAction">
<result name="success">/success.jsp</result>
</action>
<action name="tow" class="struts2.TowAction">
<result name="success">/success.jsp</result>
</action>
</package>
由于这么写导致action重复, 这时候就可以用全局结果页面,配置如下,在package下添加global-results标签
<package name="default" namespace="/" extends="struts-default">
<global-results>
<result name="success">/success.jsp</result>
</global-results>
<action name="one" class="struts2.OneAction"></action>
<action name="tow" class="struts2.TowAction"></action>
</package>
注意: 当同时存在全局和局部页面时,优先局部
Result标签的type属性
1) 规定如何到指定路径里面(重定向 or 转发)
2) 属性值:
*默认值为转发(dispatcher)
*重定向为(redirect)
*重定向到另一个action(redirect-action) ,如下, 访问towaction则会定向到one在到success.jsp页面
<action name="one" class="struts2.OneAction">
<result name="success">/success.jsp</result>
</action>
<action name="tow" type="redirect-action" class="struts2.TowAction">
<result name="success">one</result>
</action>
*转发到另一个action (chain)
在action类中获取表单的数据
由于action没有request对象, 不能直接使用request对象,struts提供3种方式来获取:
1.使用ActionContet类获取
2.使用ServletActionContext类获取
3.使用接口注入方式(不做要求)
1.使用ActionContet类获取
//获取ActionContext对象
ActionContext context = ActionContext.getContext();
//得到表单数据
Map<String, Object> map = context.getParameters();
//key是唯一值
Set<String> keys = map.keySet();
//遍历内容
for (String key : keys){
Object[] obj = (Object[])map.get(key); //得到value
System.out.println(Arrays.toString(obj));
}
2.使用ServletActionContext类获取
//直接得到request
HttpServletRequest request = ServletActionContext.getRequest();
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(username+password+"ha");
在action中操作3个作用域
1.request域
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("req","reqValue");
2.session域
HttpSession session = request.getSession();
session.setAttribute("sess", "sessValue");
3.ServletContext 域
ServletContext context = ServletActionContext.getServletContext();
context.setAttribute("context", "contextValue");
将表单数据封装到实体类中
1)原始方式需要new出实体对象通过构造或set()进行封装
2)struts提供的封装:
一. 属性封装
1. 在action类中定义同form表单name相同名称的变量,并生成get,set方法就已经实现了封装
public class Form1Action extends ActionSupport{
String username;
String password;
@Override
public String execute() throws Exception {
System.out.println(username+password);
return NONE;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
二. 使用模型接口方式 使用ModelDriven接口
public class Form1Action extends ActionSupport implements ModelDriven<User>{
//创建对象, 前提是表单name和实体类的属性相同
User user = new User();
public String execute() throws Exception {
return NONE;
}
@Override
public User getModel() {
return user;
}
}
三. 表达式封装
1.在action里声明实体类
2.生成实体类变量的set和get方法
3.在表单输入项的name属性里面写表达式形式
要在表单中写 上对象.属性作为name
username:<input name="user.username" /><br/>
password:<input name="user.password"><br>
action类, 需要创建对象,生成对象的get,set
public class Form1Action extends ActionSupport{
//创建对象, 前提是表单name和实体类的属性相同
User user = new User();
public String execute() throws Exception {
System.out.println(user.toString());
return NONE;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
表达式封装和模型封装的区别:
模型封装一个action只能实例化一个类(应为接口的泛型只能指定一个), 表达式封装可以实例化多个类, 只要在action中创建相应类对象并生成get,set方法, 在jsp中使用对象.属性给表单组件name起名即可
封装数据到list集合
1.在action中声明list, 并生成list的get,set方法
2.在表当输入项中写表达式
jsp 中每个list表示一个user对象
<form action="${pageContext.request.contextPath}/form1" method="post">
username:<input name="list[0].username" /><br/>
password:<input name="list[0].password"><br><br>
username:<input name="list[1].username" /><br/>
password:<input name="list[1].password"><br>
<input type="submit">
</form>
action
public class Form1Action extends ActionSupport{
List<User> list = new ArrayList<User>();
public String execute() throws Exception {
System.out.println(list);
return NONE;
}
public List<User> getList() {
return list;
}
public void setList(List<User> list) {
this.list = list;
}
}
封装数据到map集合
1.在action中声明map, 并生成map的get,set方法
2.在表当输入项中写表达式
ognl
在jsp页面引入标签库
<%@ taglib uri="/struts-tags" prefix="s" %>
在jsp页面得到字符串长度:
<body>
<s:property value="'aaa'.length()"/>
</body>
值栈
什么是值栈
以前把数据防盗域对象中,在页面使用el表达式获取, 在struts2中,值栈类似域对象, 可以存(在action类中存)取(在页面取)值
servlet 和 action的区别
servlet 默认在第一次访问的时候创建,创建一次,单实例对象
action 访问的时候创建,没访问一次都会创建一个新的action,多实例对象, 在每个action对象中都有一个值栈对象
值栈对象
值栈中有两种结构
- root(是list集合)
- context(是map集合)
查看两种结构:
在jsp页面到入struts2标签库,并写代码:
<%– 使用struts2标签查看值栈结构 –%>
此时页面就会出现debug超链接, 点击后会显示root和context
向值栈中存数据
1.获取值栈对象, 调用值栈的set方法
ValueStack stack = context.getValueStack(); //得到值栈对象
stack.set(“username”, “xxxx”);
在jsp中获取设置的值
<body>
<s:property value="username"/>
</body>
2.获取值栈对象, 调用值栈的push方法
ValueStack stack = context.getValueStack(); //得到值栈对象
stack.push(“abcde”);
获取push的值,push设置的只有值,没有名称, 当每次push都会把值放入名为top的数组中 ,我们可以从数据中取出(数组写法是struts2规定的 ,不用纠结)
<body>
<s:property value="[0].top"/>
</body>
3.在action定义变量, 生成变量的get方法(一般使用这个方法)
public class Form1Action extends ActionSupport{
String name;
public String getName() {
return name;
}
public Form1Action() {
System.out.println("执行。。。");
}
public String execute() throws Exception {
name = "cdab";
return "hello";
}
}
案列:向值栈中存放对象
1. 定义对象,生成get方法
2.在excute中设置对象值
3.访问此action转发的页面的debug连接后, 会看到root中有user对象值
public class Form1Action extends ActionSupport{
User user = new User();
public User getUser() {
return user;
}
public Form1Action() {
System.out.println("执行。。。");
}
public String execute() throws Exception {
user.setUsername("zs");
user.setPassword("1234");
return "hello";
}
}
案列:在值栈中存放List对象
public class Form1Action extends ActionSupport{
List<User> list = new ArrayList<User>();
public List<User> getList() {
return list;
}
public Form1Action() {
System.out.println("执行。。。");
}
public String execute() throws Exception {
User user1 = new User();
user1.setUsername("zs");
user1.setPassword("123");
User user2 = new User();
user2.setUsername("zs");
user2.setPassword("123");
list.add(user1);
list.add(user2);
return "hello";
}
}
在值栈中获取数据
- 获取字符串, 在action类中设置字符串变量, 并生成get()方法
jsp页面
<body>
<s:property value="name"/>
</body>
2.获取对象数据
<body>
<s:property value="user.username"/>
<s:property value="user.password"/>
</body>
3.获取list数据
1)第一种方式 ,比较局限
<body>
<s:property value="list[0].username"/>
<s:property value="list[0].password"/>
</body>
2)第二种方式, 使用遍历方法,常用
<s:iterator value="list">
<s:property value="username"/>
<s:property value="password"/>
</s:iterator>
3)第三种方式, 这种类似于for遍历list,u为每个list对象, 必须使用#号开头
<body>
<s:iterator value="list" var="u">
<s:property value="#u.username"/>
<s:property value="#u.password"/>
</s:iterator>
</body>
用el表示式获取list数据
<c:forEach items="${list }" var="user">
${user.username }
${user.password }
</c:forEach>
el表达式为什么能取到值栈的数据
request对象getAttribute()中获取域对象的值,如果没有 ,则会到值栈中获取值,在把值放进域对象中
“#”号的操作
在action类中向request域中放值
public class Form1Action extends ActionSupport{
public Form1Action() {
System.out.println("执行。。。");
}
public String execute() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("req","reqvalue");
return "hello";
}
}
在jsp页面中使用#获取request域值
<body>
<s:property value="#request.req"/>
</body>
%使用
使用%{#request.req} 才能取到域对象的值
s:textfield 是struts2封装的一个
<s:textfield name="username" value="%{#request.req}"></s:textfield>