应项目要求需要使用struts。以下是学习笔记
Struts2 框架的优点
了解了这几个主要的优点,会促使你考虑使用Struts2 :
POJO表单及POJO操作 - Struts2 去除掉了Struts框架中的Action Forms部分。在Struts2框架下,你可以用任何一POJO来接收表单输入,同样的,你可以把任一POJO视为一个Action类。
标签支持 - Struts2 改进了标签表单,而新的标签可让开发人员减少代码编写量。
AJAX支持 - Struts2 被认可接收进Web 2.0技术,并创建了功能非常类似于标准的Struts2 标签的AJAX标签,把AJAX支持整合进其结果中。
易于整合 - Struts有多种整合方式可使用,现在与其他类型的框架,如Spring、Tiles、SiteMesh之类的,整合更为容易了。
模板支持 - 支持使用模板生成视图。
插件支持 - 有大量的插件可用于Struts2,而使用插件可以增强和扩大Struts2 核心行为。
性能分析 - Struts2 为调试和配置应用程序提供综合的性能分析,此外,Struts也以嵌入调试工具的形式提供集成调试。
易于修改标签 - 在Struts2 中,可使用Freemarker的模板对标签标记进行调整,而修改标签不需要JSP或是Java知识,基本的HTML、XML和CSS知识就足够了。
促进减少配置 - Struts2 使用各种设置的默认值促进减少配置,而你不需要再配置什么除非是偏离了Struts2 设定的默认设置。
视图技术 - Struts2 为多种视图选项(JSP、Freemarker、Velocity、XSLT等)提供支持。
以上是使Struts2 成为准企业框架的十大优点。
Struts2 框架的缺点
尽管Struts2 有一大列的优点,但我们还是要提到关于它的一些仍需不断改进的缺点:
更大的学习曲线 - 使用Struts MVC,你必须要熟悉JSP、Servlet APIs标准以及一个大型、复杂的框架。
文档缺乏 - 相比于Servlet和JSP APIs标准,Struts的在线资源较少,许多初学者会发现Apache在线文档混乱并缺乏整理。
不够透明 - 相比于使用正常的基于Java的Web应用程序,使用Struts的应用程序有许多是进行在后台,这使得框架不易于理解。
最后说明一点,一个好的框架应该提供各种类型的应用程序都可以使用的通用行为,Struts2 是最好的Web框架之一,并频繁用于RIA(Rich Internet Applications)的发展。
Struts2 入门程序
依赖介绍
我们需要为每一个struts构建如下组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4plxwLNe-1629212907857)(struts2.assets/image-20210817090434951.png)]
pom.xml文件依赖
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- servlet依赖 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <!-- jstl依赖(el表达式) --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> </dependency> <!-- mysql依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.29</version> </dependency> <!-- struts依赖 --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.3.16.3</version> </dependency> <!-- <dependency>--> <!-- <groupId>org.apache.struts</groupId>--> <!-- <artifactId>struts2-core</artifactId>--> <!-- <version>2.5.14.1</version>--> <!-- </dependency>--> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging-api</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.23.1-GA</version> </dependency> <dependency> <groupId>org.apache.struts.xwork</groupId> <artifactId>xwork-core</artifactId> <version>2.3.16.3</version> </dependency> </dependencies>
项目结构如下
配置过滤器
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Struts 2</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <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> </web-app>
注意:不同版本的过滤器会有不同
web.xml配置核心过滤器
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>Struts 2</display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <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> </web-app>
创建Action类
package com.qijian.domain; import com.opensymphony.xwork2.Action; public class HelloWorldAction implements Action { private String name; public String execute() throws Exception { return "success"; } public String getName() { return name; } public void setName(String name) { this.name = name; } } /* 这是一个非常简单的具有“name”属性的类。对于“name”属性, 我们用标准的getter和setter方法,以及一个返回“success”字符串的执行方法。 Struts2 框架将创建一个“HelloWorldAction”类的对象, 并调用execute方法来响应用户的动作。你把你的业务逻辑放进execute方法里, 最后会返回字符串常量。简单的描述每个URL,你需要实现一个Action类, 你也可以用类名直接作为你的动作名,或者如下面内容所示使用 struts.xml 文件映射到其他name上。 */
编写配置文件(struts.xml固定)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <constant name="struts.devMode" value="true" /> <package name="helloworld" extends="struts-default"> <action name="hello" class="com.qijian.domain.HelloWorldAction" method="execute"> <result name="success">/helloworld.jsp</result> </action> </package> </struts>
创建试图首页文件(index.jsp)
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Hello World</title> </head> <body> <h1>Hello World From Struts2</h1> <form action="hello"> <label for="name" id="name">Please enter your name</label><br/> <input type="text" name="name"/> <input type="submit" value="Say Hello"/> </form> </body> </html>
创建返回页面(success.xml)
<%@ page contentType="text/html; charset=UTF-8" %> <%@ taglib prefix="s" uri="/struts-tags" %> <html> <head> <title>Hello World</title> </head> <body> Hello World, <s:property value="name"/> </body> </html> <%--Taglib指令告知Servlet容器这个页面将使用Struts2 标签, 并且这些标签会被s放在前面。s:property 标签显示Action类“name”属性的值, 这个值是使用HelloWorldAction类的 getName() 方法返回的。--%>
在客户端浏览器上单击 index.jsp 中的超链接时,会发送一个 helloWorld.action 请求,该请求被核心过滤器拦截后,会通过 struts.xml 文件中的配置找到请求对应的 HelloWorldAction,并默认调用 elloWorldAction 中的 execute() 方法返回逻辑视图名,然后再通过配置文件找到并转发给对应的视图页面 success.jsp 中,最后生成响应内容并输出响应的返回结果。
struts2 执行的完整流程
从图 1 所示的流程图中可以看出,一个请求在 Struts2 框架中的处理大概可以分为以下几个步骤。
1)首先客户端浏览器发送一个请求(HttpServletRequest)。
2)接着程序会调用 StrutsPrepareAndExecuteFilter,然后询问 ActionMapper 这个请求是否需要调用某个 Action。
3)如果 ActionMapper决定需要调用某个 Action,StrutsPrepareAndExecuteFilter 会把请求的处理交给 ActionProxy。
4)ActionProxy通过配置管理器(Configuration Manager)从配置文件(struts.xml)中读取框架的配置信息,从而找到需要调用的 Action 类。
5)ActionProxy 会创建一个ActionInvocation 的实例。
6)ActionInvocation使用命名模式调用 Action,在调用 Action 前,会依次调用所有配置的拦截器(Intercepter1、Intercepter2……)。
7)一旦 Action 执行完,则返回结果字符串,ActionInvocation 就会负责查找结果字符串对应的 Result,然后执行这个 Result。通常情况下 Result 会调用一些模板(JSP 等)呈现页面。
8)产生的 Result 信息返回给ActionInvocation,在此过程中拦截器会被再次执行(顺序与 Action 执行之前相反)。
9)最后产生一个HttpServletResponse 的响应行为,通过StrutsPrepareAndExecuteFilter反馈给客户端。
strust2 配置文件
上面我们会发现和我们平时使用的结构一点不一样,struts2的配置文件不是放在resources下。如果直接放在那里就会读取不了。这时需要配置maven资源过滤配置
<!--配置Maven 对resource文件 过滤 --> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.xls</include> <include>**/*.xlsx</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources>
配置文件结构如下
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <!--文件的根元素--> <struts> <!--<constant>元素用常量的配置--> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="true" /> <!--<package>元素用于包配置,包用于组织 Action 和拦截器等信息,每个包都是由零个或多个拦截器以及 Action 所组成的集合。--> <package name="default" namespace="/" extends="struts-default"> <!--配置Action--> <action name="index" class="Xxx"/> <!--配置Result--> <result type="dispatcher"> <param name="location">/index.jsp</param> </result> </action> </package> <!-- <include>元素用于包含配置 --> <include file="example.xml"/> </struts>
文件配置常用的配置
常量的配置通常使用以下三种方式。
- 在
struts.xml
文件中使用 <constan
> 元素配置常量(常用方式)。 - 在
struts.properties
文件中配置常量。 - 在 web.xml 文件中通过
<init-param>
元素配置常量。
常量配置
struts.xml 文件中通过 <constant…/> 元素配置常量时,需要指定两个必填的属性 name 和 value。其中 name 属性用于指定常量的常量名,value 属性用于指定常量的常量值。
<struts> <!--设置默认编码集为UTF-8--> <constant name="struts.il8n.encoding" value="UTF-8" /> <!--设置使用开发模式--> <constant name="struts.devMode" value="true" /> </struts>
包配置
包用于管理Action
和拦截器,每个包就是多个 Action
、多个拦截器、多个拦截器引用的集合。在 struts.xml
文件中,使用<package>
元素定义包配置,每个 <package>
元素都定义了一个包配置
<package name="default" namespace="/" extends="struts-default"> ... </package>
name:必填属性,用于指定该包的名称(该名称在配置文件中必须是唯一的),此名称是该包被其他包引用的 Key。
namespace:可选属性,用于定义该包的命名空间。
extends:可选属性,用于指定该包继承自其他包。其属性值必须是另一个包的 name 属性值,但该属性值通常都设置为 struts-default,这样该包中的 Action 就具有了 Struts2 框架默认的拦截器等功能。
包含配置
Struts2只会读取struts.xml
文件,一旦通过多个 XML 文件配置 Action
,就必须通过 <include>
元素包含其他配置文件。
<struts> <!--不指定路径,默认在src下时的方式--> <include file="struts-post.xml"/> <include file="struts-user.xml"/> <include file="struts-dept.xml"/> <!--配置文件在具体包中时的方式 --> <include file="com/mengma/action/struts-product.xml"/> </struts>
file 属性用于指定被包含配置文件的名称。如果被包含的配置文件在 src
或resources
路径下,则直接指定文件名即可,如果被包含的配置文件在具体的包中,则需要引入被包含文件的包路径。
Struts2 Action配置
Action 是用于处理请求操作的,它是由StrutsPrepareAndExecuteFilter 分发过来的
Action 是框架的核心类,被称为业务逻辑控制器,主要用于实现对用户请求的处理。
一个Action 类代表一次请求或调用,每个请求的动作都对应一个相应的 Action类。也就是说,用户的每次请求,都会转到一个相应的Action类中,由这个 Action 类进行处理。简而言之,Action 就是用于处理一次用户请求的对象。
实现 Action 控制类通常采用两种方式,分别是实现Action 接口和继承 ActionSupport类。接下来分别对它们进行讲解,具体如下。
实现Action接口
Acton实现了应该实现的规范
Action接口的具体代码
package com.opensymphony.xwork2; public interface Action { public static final String SUCCESS = "success"; public static final String NONE = "none"; public static final String ERROR = "error"; public static final String INPUT = "input"; public static final String LOGIN = "login"; public String execute() throws Exception; } //execute() 方法是 Action 类的默认请求处理方法,该方法返回一个字符串,而上面五个字符串常量的作用是统一 execute() 方法的返回值。
继承 ActionSupport
类
package com.qijian.domain; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private static final long serialVersionUID = 1L; @Override public String execute() throws Exception{ return super.execute(); } }
ActionSupport是 Action 接口的默认实现类,所以继承ActionSupport就相当于实现了 Action 接口。除 Action 接口以外,ActionSupport 类还实现了Validateable、ValidationAware、TextProvider、LocaleProvider 和 Serializable 等接口,这为用户提供了更多的功能。
ActionSupport 类中提供了许多默认方法,这些默认方法包括数据校验的方法、默认的处理用户请求的方法等。如果开发者的 Action 类继承 ActionSupport类,会大大简化 Action 的开发。
需要注意的是,由于自定义的 Action 类继承了ActionSupport 类,因此必须定义一个变量 serialVersionUID。
private static final long serialVersionUID = 1L;
配置Action
配置 Action 主要就是配置 struts.xml 文件中 Action 的映射信息。Action 映射是指向一个请求的 URL 映射到一个 Action 类,当一个请求匹配某个 Action 名称时,Struts2 框架就使用这个 Action 确定如何处理请求。
strus.xml
文件是通过元素对请求的Action和Action类进行配置的。
<action name="userAction" class="com.mengma.action.UserAction" method="add"> ... </action>
使用通配符
在一个 Action 类中可能有多个业务逻辑处理方法,在配置 Action 时,就需要使用多个 元素。这时就需要使用通配符了。
<package name="user" namespace="/user" extends="struts-default"> <action name="userAction_*" class="com.mengma.action.UserAction" method="{1}"> <result>/index.jsp</result> </action> </package>
*在上述代码中,method 属性值中的数字 1 表示匹配第 1 个 。当客户端发送/user/userAction_login.action 这样的请求时, 元素的 name 属性值就被设置成 userAction_login,method属性值就被设置成 login。当客户端发送 /user/userAction_register.action 这样的请求时, 元素的 name 属性值就被设置为 userAction_register,method属性值也被设置成 register。
另外,对 元素也可以采用通配符配置,代码如下所示:
<result>/(1).jsp</result>
当客户端发送userAction_login这样的请求时, 元素被设置成跳转到login.jsp页面。当客户端发送 userAction_register这样的请求时, 元素被设置成跳转到register.jsp页面。
Action访问Servlet API
通过 ActionContext 访问
通常开发时需要访问 Servlet API 中的 HttpServletRequest、HttpSession 和ServletContext 三个接口,它们分别对应 JSP 内置对象 request、session 和 application。
ActionContext是 Action 执行的上下文对象,在 ActionContext中保存了 Action 执行所需要的所有对象,包括 request、session 和 application 等。
示例
ActionContext context = ActionContext.getContext(); context.put("name","mengma"); context.getApplication().put("name","mengma"); context.getSession().put("name","mengma");
案例
login.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>登录页面</title> <style type="text/css"> input[type=text],input[type=password]{width:150px} </style> </head> <body> <div align="center"> <form action="login" method="post"> 用户名:<input type="text" name="username"/><br/> 密 码:<input type="password" name="password"/><br/> <input type="reset" value="重置"/> <input type="submit" value="登录"/> </form> </div> </body> </html>
success.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>登录成功页面</title> </head> <body> <p>${success }<br/></p> <h2>用户登录信息</h2> 用户名:${username }<br/> 密码:${password }<br/> </body> </html>
error
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>登录失败页面</title> </head> <body> <p>${error }<br/></p> </body> </html>
web.xml添加过滤器
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <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> </web-app>
创建LoginAction类,继承ActionSupport类
package com.qijian.domain; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private String username; // 用户名 private String password; // 密码 // username的getter和setter方法 public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } // password的getter和setter方法 public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String execute() throws Exception { System.out.println(username); System.out.println(password); // 获取ActionContext对象 ActionContext context = ActionContext.getContext(); if ("admin".equals(username) && "123456".equals(password)) { // 将用户名和密码信息放入context对象中 context.put("username", username); context.put("password", password); context.put("success", "用户登录成功!"); return SUCCESS; } else { // 定义登录失败的错误信息 context.put("error", "用户名或密码错误,请重新登录!"); return ERROR; } } }
struts.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="default" extends="struts-default"> <action name="login" class="com.qijian.domain.LoginAction"> <result name="success">/success.jsp</result> <result name="error">/error.jsp</result> </action> </package> </struts>