1. 环境搭建
struts2是web层的框架,需要创建web工程。
1.1 导入jar包
导入struts的核心jar包,书写在项目的pom.xml文件中,内容如下:
<!--struts2 -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.5.13</version>
</dependency>
1.2 书写web.xml文件
struts2框架的入口及核心过滤器,书写在项目的WEB-INF下到的web.xml文件中,内容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!-- struts2的入口、核心过滤器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
注:其中<url-pattern>/*</url-pattern>表示拦截所有请求。
1.3 配置文件(struts.xml)
1) 创建struts.xml文件
struts2框架的核心配置文件,书写在项目的resource下struts.xml文件中,内容如下:
<?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>
</struts>
注:
1. 只是一个公共头,需要书写相应的请求处理类再添加配置。
2.文件名只能为struts.xml。
2) 书写请求处理类
Action接口,内容如下:
package com.opensymphony.xwork2;
public interface Action {
String SUCCESS = "success";
String NONE = "none";
String ERROR = "error";
String INPUT = "input";
String LOGIN = "login";
String execute() throws Exception;
}
SUCCESS --》 请求成功
NONE --》 请求资源找不到
ERROR --》 异常
INPUT --》 输入有错
LOGIN --》 登录出错请求处理类,通常约定叫Action,Action是一个接口我们可以通过实现该接口并实现该接口的方法,自定义请求处理类。
我们可以创建一个action包将创建的请求处理类都统一放到该包中。
例如: helloAction1请求处理类
package com.sunfeng.action;
import com.opensymphony.xwork2.Action;
public class HelloAction1 implements Action {
@Override
public String execute() throws Exception {
System.out.println("hello struts2");
return SUCCESS;
}
}
请求怎么进入到处理类中的?需要在struts.xml配置文件中配置对应关系。
3)配置请求与处理类的连接
<struts>
<package name="default" extends="struts-default">
<action name="hello" class="com.sunfeng.action.HelloAction">
<result name="success">hello1.jsp</result>
</action>
</package>
</struts>
作用:通过action标签将请求与处理请求的类绑定在一起。
属性解析:
package标签
name属性类似于命名空间可以自己随意命名。
extends属性是继承struts默认的处理请求参数的工具包(封装的有过滤器)。
action标签
name属性请求路径的地址(例: http://localhost:8080/hello)
class属性处理类的全限定名称
result标签
name属性是处理类返回的结果,标签内是对应的跳转界面。
4) 创建index.jsp文件
在webapp目录下创建一个index.jsp文件。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello1</title>
</head>
<body>
<h1>Hello Struts2</h1>
</body>
</html>
2. 参数映射
2.1 基本参数类型的映射
1) 书写请求处理类
在HelloAction2类中创建两个变量name与message,并书写对应的get,set方法。
作用: 用于接收参数,同时向页面返回数据。
set方法:会自动将前端对应的参数值设置到对应的属性中。
get方法:会自动将后端属性的值返回到前端。
package com.sunfeng.action;
import com.opensymphony.xwork2.Action;
public class HelloAction2 implements Action {
// 创建两个变量,并书写对应的get,set方法
private String name;
private String message;
@Override
public String execute() throws Exception {
System.out.println("接收到的name为:"+name);
System.out.println("接收到的message为:"+message);
message = "helloAction2";
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
2)书写配置文件对应关系
<struts>
<package name="default" extends="struts-default">
...
<action name="hello2" class="com.sunfeng.action.HelloAction2">
<result name="success">hello2.jsp</result>
</action>
</package>
</struts>
3)书写前端界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello2</title>
</head>
<body>
<h1>Struts2</h1>
<!-- 向后端发送数据 -->
<form name="hello" method="post">
<input name="name">
<input type="submit" value="提交">
</form>
<!-- 获取后端返回数据 -->
<p>${requestScope.message}</p>
</body>
</html>
4)测试
a)启动后前端界面
b)输入hello,提交后的后端输出
2.2 对象的映射
1)创建User对象(属性id,username)(get,set方法)(toString方法)
package com.sunfeng.pojo;
public class User {
private Integer id;
private String username;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
'}';
}
}
2)将User对象作为属性书写在请求处理类HelloAction3中
package com.sunfeng.action;
import com.opensymphony.xwork2.Action;
import com.sunfeng.pojo.User;
public class HelloAction3 implements Action {
private User user;
@Override
public String execute() throws Exception {
System.out.println("对象user的信息为:"+ user);
if (user!=null){
System.out.println("接收到的用户ID为:"+ user.getId());
System.out.println("接收到的用户名为:"+ user.getUsername());
}
return SUCCESS;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
3)书写配置文件对应关系
<struts>
<package name="default" extends="struts-default">
...
<action name="hello3" class="com.sunfeng.action.HelloAction3">
<result name="success">hello3.jsp</result>
</action>
</package>
</struts>
4)书写前端界面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello3</title>
</head>
<body>
<h1>Struts2</h1>
<!-- 向后端发送数据 -->
<form name="hello" method="post">
id:<input name="user.id">
username:<input name="user.username">
<input type="submit" value="提交">
</form>
</body>
</html>
3. struts.xml文件详解
3.1 constant标签
constant标签
功能: 用来配置常量,name属性是常量名,value属性是常量值。
作用: 可以改变Struts2的一些行为,比如UI标签的样式、编码格式等。
因为struts2默认的编码格式就是UTF-8,所以不用特意指定编码,中文也不会乱码。
<struts>
<!-- 设置请求后缀 -->
<constant name="struts.action.extension" value="do,html"></constant>
<!-- 设置编码,解决中文乱码 -->
<constant name="struts.i18n.encoding" value="utf-8"></constant>
<!-- 设置struts标签主题 -->
<constant name="struts.ui.theme" value="simple"></constant>
...
</struts>
注:请求后缀,指的是在请求路径的后边加的后缀(struts2默认的后缀是.action)
例如: http://localhost:8080/hello请求路径,可以使用 http://localhost:8080/hello.action访问。
自定义后缀:如果我们定义了后缀,那么默认的后缀就会失效,并且页面请求路径后必须携带自定义的后缀才能访问。
默认后缀:带不带后缀页面都可以访问路径。
3.2 package标签
<struts>
<package name="default" namespace="/" extends="struts-default">
...
</package>
</struts>
Struts2的package与java中的package类似,可以把同一个业务模块的action和result集中到一个包中,方便管理。不同的是Struts2的包可以继承。比如商品有增删改查操作,订单也有增删该查操作,我们可以将商品和订单的action分别放两个package中方便管理。
name属性是包的名字,一个struts.xml中可以有很多个package,通过name属性进行区分。
namespace是命名空间,/代表的是根目录。namespace的作用类似于SpringMVC中在Controller类上加@RequestMapping注解。相当于此包中所有的action前都加一个父路径。如:
<struts>
<package name="default" namespace="/user" extends="struts-default">
...
</package>
</struts>
上面这个name=login的action,在访问的时候路径就是/user/hello,注意添加了命名空间,跳转的前端界面就要使用绝对路径从webapp(/)开始。
extends属性是继承,通常都会继承struts-default,在struts-default中定义了大量的struts特性,如拦截器和参数处理的功能,如果不继承struts-default,会遇到参数无法绑定或找不到action类。
3.3 action标签
<struts>
<package name="default" extends="struts-default" namespace="/user">
...
<action name="login" class="com.sunfeng.action.LoginAction">
<result name="success">index.jsp</result>
<result name="error">error.jsp</result>
<result name="input">login.jsp</result>
</action>
</package>
</struts>
action标签用来处理请求和响应结果。
name属性是请求的名字,此处不需要加action。同一个package下的action不能重名。
class属性指定处理该请求的类,是类的全路径,默认的处理请求时会去类中找名为exeute的方法。如果不指定class,将默认ActionSupport为处理请求的类
result标签用来处理请求结果,name属性是Action类中返回的字符串。标签的值是要跳转的页面地址,name如果不写的话,默认是success。
4. Action类的配置
4.1 ActionSupport类
该类不仅实现了Action接口,还实现了如下图所示接口(数据校验,国际化),并提供了一些扩展方法,我们可以通过继承该类实现请求处理类。
ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable {
4.2 自定义业务方法
在前面的学习中,Action类中只有一个exeute()方法,可不可以在一个Action类中定义多个业务方法呢? 答案是肯定的。
例如:用户有注册和登录两个功能,我们可以把这两个功能写进同一个Action类:
a)书写UserAction类
package com.sunfeng.action;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport {
private String username;
private String password;
public String login(){
System.out.println("login success");
System.out.println("用户名:"+ username);
System.out.println("密码:"+ password);
return SUCCESS;
}
public String register(){
System.out.println("register success");
System.out.println("用户名:"+ username);
System.out.println("密码:"+ password);
return SUCCESS;
}
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;
}
}
注:
1. 继承ActionSupport可以书写自己的方法。
2. 自己书写的方法必须是public修饰,并且方法的返回值只能是String类型。
b)配置文件
怎么调用自己书写的方法?在配置文件的action标签中添加一个method属性。
<struts>
<package name="default" extends="struts-default" namespace="/user">
...
<action name="login" class="com.sunfeng.action.UserAction" method="login">
<result name="success">/login.jsp</result>
</action>
<action name="register" class="com.sunfeng.action.UserAction" method="register">
<result name="success">/register.jsp</result>
</action>
</package>
</struts>
method="login"表示要调用类中的login方法处理请求。如果找不到login()方法,Struts2会在类中查找doLogin()方法。如果都找不到,将报错。
注意:package有命名空间,跳转的前端界面前面要添加/
c)书写前端页面
login.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
</head>
<body>
<h1>Struts2</h1>
<!-- 向后端发送数据 -->
<form name="login" method="post">
用户名: <input name="username"><br>
密 码: <input name="password" type="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
register.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>register</title>
</head>
<body>
<h1>Struts2</h1>
<!-- 向后端发送数据 -->
<form name="register" method="post">
用户名: <input name="username"><br>
密码: <input name="password" type="password"><br>
<input type="submit" value="注册">
</form>
</body>
</html>
d)测试
启动程序:
1) 访问http://localhost:8080/struts/user/login.do路径进入登录界面:
填写信息登录,查看后端输出:
2) 访问http://localhost:8080/struts/user/register.do路径进入注册界面:
填写信息提交,查看后端输出:
4.2 动态方法调用
注:Struts2支持动态方法调用,但是不建议使用。仅做考点学习如果一个类中有多个业务方法,又不想给每个业务方法都配置一个action标签,可以使用动态方法调用。
语法:请求名!方法名.后缀
例:
当请求的格式是user!login.action时,代表调用UserAction中的login()方法处理当前请求。当请求的格式是user!register.action时,代表调用UserAction中的register()方法处理当前请求。
缺点: 路径中有!和方法名,不安全。
a)开启动态调用
<struts>
...
<!--允许调用动态方法-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<package ...>...</package>
</struts>
b)添加允许调用的方法
<struts>
...
<package name="default" extends="struts-default" namespace="/user">
<!--允许动态调用的方法,新版里新增的设置,必须在所有action之前-->
<global-allowed-methods>login,register</global-allowed-methods>
<action ...> ... </action>
</package>
</struts>
c)合并action
<struts>
...
<package name="default" extends="struts-default" namespace="/user">
<!-- name属性:设置统一的前缀,以user开口的请求都走这里 -->
<action name="user" class="com.sunfeng.action.UserAction">
<result name="success">/index.jsp</result><!--成功去首页-->
<result name="error">/error.jsp</result><!--失败去错误-->
</action>
</package>
</struts>
d)修改前端页面内容
修改前端页面的form表单的action属性指向的方法
<!-- 登录界面修改 -->
<form name="login" method="post" action="user/user!login.do">
<!-- 注册界面修改 -->
<form name="register" method="post" action="user/user!register.do">
e)测试
1)访问http://localhost:8080/struts/user/user!login.do路径,直接跳转到index.jsp页面。
2)访问http://localhost:8080/struts/login.jsp路径,进入登录页面,输入登录,查看后端输出:
4.3 使用通配符
使用方法与上面一致,都需要先开启动态调用,再添加调用方法。
另一种减少action数量的方法是使用通配符:
<action name="*User" class="com.sunfeng.action.UserAction" method="{1}">
<result name="success">/index.jsp</result>
<result name="error">{1}.isp</result><!--失败了就返回原来的页面-->
</action>
User匹配所有以User结尾的请求,method="{1}"中的{1}的就是User前的*。
如果请求的地址是loginUser.action,那么{1}匹配的就是login,就会去类中调用login()方法,并返回相应的结果。
访问方法,例:http://localhost:8080/struts/user/loginUser.do路径
4.4 默认Action
如果在struts.xml中找不到匹配的action,将会报错。可以设置一个默认的action。当所有请求都不匹配时,将匹配默认action。
<!-- 需要放在<global-allowed-methods>标签前面 -->
<default-action-ref name="default"/>
...
<action name="default">
<result>/error.jsp</result>
</action>
<default-action-ref>对当前的package有效
action标签的class省略将调用ActionSupport类。result的name省略将默认为success。注意default-action-ref必须在所有的action标签上面。也就是说default-action-ref出现在action标签之前,不然不符合DTD验证。
5. Result配置
常用结果有三种类型: dispatcher,redirect,redirectAction,chain
5.1 dispatcher
result默认的类型,一下两个标签是等价的:
<result name="success” type="dispatcher">index.jsp</result>
<result name="success">index.jsp</result>
dispatcher的结果等同于Servlet中的请求转发,
即:request.getRequestDispatcher("success.jsp").forward(request, response);
请求转发的意思:当前请求中的参数、属性在下一个页面或请求中仍然可以使用。
5.2 redirect
redirect是重定向,重定向之后,当前请求中的参数和属性在下一个页面或请求中将不能使用。
<result name="success" type="redirect">index.jsp</result>
相当于Servlet中的: response.sendRedirect("success.jsp");
5.3 redirectAction
redirectAction与redirect类似,不过redirectAction是重定向到某一个action
<action name="reg"class="action.UserAction" method="regist">
<result name="success" type="redirectAction">login.action</result>
<result name="error">regist.jsp</result>
</action>
如果要调用不同package下的action,需要在result中传参数:
<action name="login" class="com.sunfeng.action.UserAction" method="login">
<result name="success" type="redirectAction">
<!--调用不同package下的action-->
<param name="namespace">/</param>
<param name="actionName">hello.action</param>
<!--传递其它参数-->
<param name="username">123</param>
</result>
<result name="error">login.jsp</result>
</action>
5.4 chain
redirectAction不能共享request中的数据,如果想共享数据,可以将type设置为chain。
<action name="reg" class="com.sunfeng.action.UserAction" method="register">
<!--注意chain的action后面没有后缀-->
<result name="success" type="chain">login</result>
<result name="error">register.jsp</result>
</action>
5.5 动态结果
private String username;
private String page;
//getter/setter方法略
public string login() {
//参数和业务略
System.out.print]n("我是登录");
if ("admin".equals(username)) {//管理员去管理页
page = "admin_page";
} else {//其他人去用户页
page = "user_page";
}
return SUCCESS;
}
result配置