struts2学习

主要内容

  • stuts2入门
  • struts2数据操作

Struts2 概述

  1. struts2框架应用javaee三层结构中的web层框架

  2. struts2 是struts1和webwork基础上发展全新的框架、

  3. struts2解决问题

  1. struts2 版本
    struts2-2.3.24

  2. web层常用框架

    • struts2
    • springMVC

struts2 框架入门

第一个例子

  1. 老规矩导入jar包
  1. 创建action
1
2
3
4
5
6
7
8
9
public class HelloAction {
/*
(1)每次访问servlet的时候,都会访问service方法
- 写类继承HTTPServlet,重写类里面的方法
(2)访问action的时候
每次访问action默认执行execute方法 */
public String execute(){
return "ok";}
}
  1. 配置action类访问路径
    (1)、创建struts2核心配置文件
    核心配置文件必须是固定名称和位置
    位置必须是再src下面,名称必须是struts.xml
    (2)、引入dtd约束
1
2
3
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">

(3)、action配置

1
2
3
4
5
6
7
<package name="hellodemo" extends="struts-default" namespace="/">
<!-- name: 访问名称 -->
<action name="hello" class="cn.shelhon.action.HelloAction">
<!-- 配置方法的返回值到页面 -->
<result name="ok">/hello.jsp</result>
</action>
</package>

访问路径
http://127.0.0.1:8080/struts2/hello.action

(4) 配置struts2过滤器

在Tomcat上面运行的时候,发现一直各种报错

1
2
严重: Exception starting filter struts2
java.lang.ClassNotFoundException: org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

估计是在idea的时候,运行Tomcat时,maven依赖那里出现了问题。导入缺少了jar包,Tomcat运行不起来。最后在项目结构Artifacts里available Elements右键把里面的jar包导入到lib文件夹里。

!!还有就是一定要把struts2.xml文件放到resources文件夹里

基本流程:


查看源码

class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter

过滤器在服务启动的时候创建,创建过滤器时候执行init方法

  • 在init方法中主要是加载配置文件
    包含自己创建的配置文件和struts2自带的配置文件
    主要注意struts.xml和web.xml

struts 配置

struts2核心配置文件

  1. 名称和位置是固定的
    固定是在src里面,名字是struts.xml
    但是由于用了maven,所以位置是在src的resources里面

  2. 在配置文件中主要三个标签 package、action、result,标签里面的属性

标签package

1、 类似于代码包,区别不同的action,要配置action,必须首先写package标签,在package里面才能 配置action

2、 package标签属性

(1)name属性

  • name属性值跟功能本身没有关系的,
  • 在一个配置文件中可以写多个package标签,name属性值不能相同的

(2)extends属性

extends = “struts-default”

  • 属性值固定的,struts-default

  • 写了这个属性之后,在package里面配置的类具有action功能

(3)namespace属性

  • namespace属性值和action标签里面的name属性值构成访问路径

标签action

1、action标签配置action访问路径

2 、action标签属性

(1)name属性

  • namespace属性值和action标签里面的name属性值构成访问路径

  • 在package标签里面写多个action标签,但是action的name属性值不能相同的

(2)class属性

  • action全路径

(3)method属性

  • 比如在action里面默认执行的方法execute方法,但是在action里面写其他的方法

  • 让action里面多个方法执行,使用method进行配置

标签result

1 、根据action的方法返回值,配置到不同的路径里面

2 、result标签属性

(1)name属性

  • 和方法返回值一样
/hello.jsp

(2)type属性

  • 配置如何到路径中(转发或者重定向)

  • type属性默认值 做转发操作

struts2常量配置

  1. struts2框架,帮我们实现一部分功能,struts2里面有常量,在常量里面封装一部分功能

  2. struts2默认的常量位置(记住)

    xxxxxxx/org\apache\struts\struts2-core\2.3.24\struts2-core-2.3.24.jar!\org\apache\struts2\default.properties

  3. 修改struts2默认常量值

(1)常用的方式

  • 在struts.xml中进行配置

(2)还有两种方式(了解)

  • 在src下面创建 struts.properties,进行修改

  • 在web.xml进行配置

  1. 介绍最常用常量

struts.i18n.encoding=UTF-8

(1)表单提交数据到action里面,在action可以获取表单提交数据,

(2)表单提交数据有中文,有乱码问题,解决:

  • post提交直接设置编码

  • get提交做编码转换

(3)如果在action获取表单通过post方式提交中文,中文乱码问题帮解决了,不需要自己处理问题

分模块开发

  1. 单独写配置文件hello.xml,把配置文件引入到核心配置文件中
1
2
<!-- 引入hello.xml -->
<include file="hello.xml"></include>

这样就可以在工作的时候,大家一起协同办公

action编写方式

  1. action编写有三种方式

第一种 创建普通类,这个不继承任何类,不实现任何接口

1
public class HelloAction{}

第二种 创建类,实现接口 Action

1
2
3
4
5
6
//实现接口
public class UserAction implements Action {
public String execute() throws Exception {
return null;
}
}

第三种 创建类,继承类 ActionSupport(一般使用)

1
2
3
//继承类
public class PersonAction extends ActionSupport {
}

访问action里面的方法

  1. 有三种方式实现

第一种 使用action标签的method属性,在这个属性里面写执行的action的方法

第二种 使用通配符方式实现

第三种 动态访问实现(不用)

  1. 演示错误

(1)如果action方法有返回值,在配置文件中没有配置,出现错误

Message No result defined for action cn.shelhon.action.HelloAction and result success

(2)在action里面的方法有返回值,如果有返回值时候类型必须是String

(3)action里面的方法可以没有返回值,没有返回值时候,在result标签不需要配置

  • 把方法写成void

  • 让返回值,返回 ”none”

在idea创建新的模块的时候,放到Tomcat上面一直没办法运行新的struts.xml的配置,然后在运行设置里面的把原来的给移除了,加上新创建的就能运行了

  1. 使用action标签method属性

(1). 创建action,创建多个方法

1
2
3
4
5
6
7
8
9
10
11
12
public class BookAction extends ActionSupport {
//添加
public String add(){
System.out.println("add----");
return NONE;
}
//修改
public String update(){
System.out.printf("update---");
return NONE;
}
}

(2). 使用method配置

1
2
3
4
5
6
7
<!-- 配置action的方法访问 -->
<package name="demo1" namespace="/" extends="struts-default">
<action name="method" class="cn.shelhon.method.BookAction" method="add">
</action>
<action name="method1" class="cn.shelhon.method.BookAction" method="update">
</action>
</package>

缺陷:action每个方法都需要配置,如果action里面有多个方法,配置很多的action

  1. 使用通配符实现(重点)

(1) 在action标签里面name属性,name属性值里面写 符号 * 星号

  • *理解: 表示匹配任意内容

    • 比如访问hello,* 可以匹配到

    • 比如访问add,* 可以匹配到

1
2
3
4
5
6
7
8
9
10
<!-- 配置通配符方法 -->
<package name="tongpei" extends="struts-default" namespace="/">

<!-- name属性值里面要写一个符号 *
(1)执行 action里面的add方法,访问book_add
(2)执行 action里面的update方法,访问book_update 上面两个路径使用book_*可以匹配到
-->

<action name="book_*" method="{1}" class="cn.shelhon.method.BookAction"></action>
</package>

这种方法的话,访问就是用book_add.action ,或者book_update.action来实现
如果name的属性值=”*”的话,那么访问就是输入add.action,或者update.action就可以实现。


结果页面配置

  1. result标签配置action方法的返回值到不同的路径里面

  2. 创建两个action,执行默认的方法execute方法,让两个action的方法都返回success,返回success之后,配置到同一个页面里面

(1)如果多个action,方法里面返回值相同的,到页面也是相同的,这个时候可以使用全局结果页面配置

1
2
3
4
5
6
7
8
9
10
<package name="demo1" extends="struts-default" namespace="/">

<action name="book" class="cn.shelhon.action.BookAction" method="execute">
<result name="success">/hello.jsp</result>
</action>

<action name="orders" class="cn.shelhon.action.OrdersAction" method="execute">
<result name="success">/hello.jsp</result>
</action>
</package>

修改后代码

1
2
3
4
5
6
7
8
9
10
<package name="demo1" extends="struts-default" namespace="/">
<!-- 全局结果页面配置 -->
<global-results>
<result name="success">hello.jsp</result>
</global-results>
<action name="book" class="cn.shelhon.action.BookAction" method="execute">
</action>
<action name="orders" class="cn.shelhon.action.OrdersAction" method="execute">
</action>
</package>

但是要注意的是,这个全局变量是在package里面用的

  1. 局部结果页面
1
2
3
<action name="book" class="cn.shelhon.action.BookAction" method="execute">
<result name="success">/hello.jsp</result>
</action>

如果同时配置了局部和全局结果页面,最后以局部变量为准

Result标签的type属性

  1. result标签里面除了name属性之外,还有一个属性 type属性
    type属性:如何到路径里面(转发还是重定向)

  2. type属性值
    (1)默认值,做转发操作,值是 dispatcher
    就是说在浏览器上面的地址还是看到
    http://localhost:8080/struts2Day02/book.action
    但是实际内容是hello.jsp的内容
    (2)做重定向操作,值是 redirect
    输入http://localhost:8080/struts2Day02/book.action
    然后链接变成了http://localhost:8080/hello.jsp
    (3)上面两个值dispatcher、redirect,这两个值一般针对到页面中配置

  3. 配置到其他的action里面

Action获取表单提交数据

  1. 之前web阶段,提交表单到servlet里面,在servlet里面使用request对象里面的方法获取,getParameter,getParameterMap

  2. 提交表单到action,但是action没有request对象,不能直接使用request对象

  3. action获取表单提交数据主要三种方式
    (1)使用ActionContext类
    (2)使用ServletActionContext类
    (3)使用接口注入方式(一般不用)

使用ActionContext类获取

Map getParameters() : 返回一个包含所有HTTPSServletRequest参数信

  • 因为这方法不是静态的方法,所以需要创建ActionContext类的对象
  • 这个ActionContext不是new出来的

static ActionContext getContext() :获取当前线程的ActionContext对象

  1. 具体演示

(1)创建表单,提交表单到action里面

(2)在action使用ActionContext获取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public String execute() throws Exception {
// 第一种方式 使用ActionContext类获取
// 1获取Action Context
ActionContext context =ActionContext.getContext();
//2 调用方法得到表单数据
// key是表单输入项的name属性值,value值是输入的值
Map<String,Object> map = context.getParameters();
Set<String> keys =map.keySet();
for (String key :keys){
//根据key得到value
//数据形式:因为输入项里面可能有复选的情况
Object[] obj = (Object[]) map.get(key);
System.out.println(Arrays.toString(obj));
}
return NONE;
}
1
2
3
<package name="demo2" namespace="/" extends="struts-default">
<action name="form1" class="cn.shelhon.action.form.Form1Demo">
</action>

使用ServletActionContext类获取

调用类里面静态方法,得到request对象

1
2
3
4
5
6
7
8
9
10
public String execute() throws Exception {
//第一种方式,使用ServletActionContext类获取
//1使用ServletActionContext获取request对象
HttpServletRequest request = ServletActionContext.getRequest();
String username = request.getParameter("username");
String password = request.getParameter("password");
String address = request.getParameter("address");
System.out.println(username+password+address);
return NONE;
}

使用接口注入(了解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Form3Demo extends ActionSupport implements ServletRequestAware {
//使用接口方式
private HttpServletRequest request;
public void setServletRequest(HttpServletRequest request) {
this.request=request;
}
public String execute() throws Exception {
String username = request.getParameter("username");
String password = request.getParameter("password");
String address = request.getParameter("address");
System.out.println(username+password+address);
return NONE;
}
}

在action操作域对象

1
2
3
4
5
6
7
8
9
10
//操作三个域 // 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("contextname","contextValue");
return NONE;

Struts2封装获取表单数据方式

原始方式获取表单封装到实体类对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public String execute() throws Exception {
// 使用servletActionContext获取表单数据封装到实体类对象里面
// 1获取表单数据 HttpServletRequest request = ServletActionContext.getRequest();
String username = request.getParameter("username");
String password = request.getParameter("password");
String address = request.getParameter("address");

//2 把数据封装到实体类对象里面
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setAddress(address);
System.out.println(user);
return NONE;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class User {
private String username;
private String password;
private String address;
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;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", address='" + address + '\'' +
'}';
}

属性封装

  1. 实现过程
    (1)使用表达式封装可以把表单数据封装到实体类对象里面

第一步 在action里面声明实体类

1
<action name="data1" class="cn.shelhon.data.DataDemo1Action"> </action>

第二步 生成实体类变量的set和get方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class DataDemo1Action extends ActionSupport {
//定义变量
//变量的名称和表单的name属性一样
private String username;
private String password;
private String address;
// 生成变量的set和get方法
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
System.out.println(username+" "+password+" "+address);
this.password = password;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String execute() throws Exception {
return NONE;
}
}

模型驱动封装(重点)

  1. 使用模型驱动方式,可以直接把表单数据封装到实体类对象里面

  2. 实现步骤

(1)action实现接口 ModelDriven

1
public class DataDemo2Action extends ActionSupport implements ModelDriven<User> {}

(2)实现接口里面的方法 getModel方法

  • 把创建对象返回
1
2
3
4
5
6
7
8
9
10
public class DataDemo2Action extends ActionSupport implements ModelDriven<User> {

public User getModel() {
return user;
}
@Override
public String execute() throws Exception {
return NONE;
}
}

(3)在action里面创建实体类对象

1
2
3
public User getModel() {
return user;
}
  1. 使用模型驱动和属性封装注意问题:
    在一个action中,获取表单数据可以属性封装,使用模型驱动封装,不能同时使用属性封装和模型驱动封装获取同一个表单数据。如果同时使用,执行模型驱动。

表达式封装(会用)

  1. 实现过程
    (1)使用表达式封装可以把表单数据封装到实体类对象里面
    第一步 在action里面声明实体类
    private User user;
    第二步 生成实体类变量的set和get方法
1
2
3
4
5
6
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}

第三步 在表单输入项的name属性值里面写表达式形式

1
2
3
4
5
username:<input type="text" name="user.username"/>
<br/>
password:<input type="text" name="user.password"/>
<br/>
address:<input type="text" name="user.address"/>

比较表达式封装和模型驱动封装

使用表达式封装和模型驱动封装都可以把数据封装到实体类对象里面
不同点:
(1)使用模型驱动只能把数据封装到一个实体类对象里面
在一个action里面不能使用模型驱动把数据封装到不同的实体类对象里面
(2)使用表达式封装可以把数据封装到不同的实体类对象里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class DataDemo3Action extends ActionSupport {
//声明实体类
private User user;
private Book book;
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
//生成实体类变量的set和get方法
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String execute() throws Exception {
System.out.println(user);
System.out.println(book.getBname());
return NONE;
}
1
2
3
4
5
6
7
8
9
10
11
<form action="${pageContext.request.contextPath}/data3.action" method="post">
username:<input type="text" name="user.username"/>
<br/>
password:<input type="text" name="user.password"/>
<br/>
address:<input type="text" name="user.address"/>
<br/>
bname:<input type="text" name="book.bname"/>
<br/>
<input type="submit" value="提交"/>
</form>

封装到集合里面

  1. 封装数据到List集合

第一步 在action声明List

1
private List<User> list;

第二步 生成list变量的set和get方法

第三步 在表单输入项里面写表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<form action="${pageContext.request.contextPath}/list.action" method="post">
username:<input type="text" name="list[0].username"/>
<br/>
password:<input type="text" name="list[0].password"/>
<br/>
address:<input type="text" name="list[0].address"/>
<br/>
<br/>
username:<input type="text" name="list[1].username"/>
<br/>
password:<input type="text" name="list[1].password"/>
<br/>
address:<input type="text" name="list[1].address"/>
<br/>
<input type="submit" value="提交"/>

  1. 封装数据到Map集合

第一步 声明map集合
private Map map;
第二步 生成get和set方法

1
2
3
4
5
6
public Map<String,User> getMap() {
return map;
}
public void setMap(Map<String,User> map) {
this.map = map;
}

第三步 在表单输入项的name属性值里面写表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<form action="${pageContext.request.contextPath}/map.action" method="post">
<!-- 设置key的值 ['key值']
设置value值 -->
username:<input type="text" name="map['one'].username"/>
<br/>
password:<input type="text" name="map['one'].password"/>
<br/>
address:<input type="text" name="map['one'].address"/>
<br/>
<br/>
username:<input type="text" name="map['two'].username"/>
<br/>
password:<input type="text" name="map['two'].password"/>
<br/>
address:<input type="text" name="map['two'].address"/>
<br/>
<input type="submit" value="提交"/>
</form>

Just for fun!
------------- 文章已经到尾 -------------