JavaWeb开发之Struts 2
2018-04-30 本文已影响18人
平安喜乐698
目录
1. 框架简介
Struts2(Apache Struts 2,最初称为WebWork 2)
基于MVC设计模式的web应用程序框架(简洁、可扩展)。
简化整个开发周期(从构建、部署、到应用程序维护)。
可用于创建企业级Java web应用程序。
优点
1. POJO表单及POJO操作
Struts2 去除掉了Struts框架中的Action Forms部分。在Struts2框架下,可以用任何一POJO来接收表单输入。
2. 标签支持
Struts2 改进了标签表单,减少代码编写量。
3. AJAX支持
Struts2 被认可接收进Web 2.0技术,并创建了功能非常类似于标准的Struts2 标签的AJAX标签,把AJAX支持整合进其结果中。
4. 易于整合
Struts有多种整合方式可使用,现在与其他类型的框架,如Spring、Tiles、SiteMesh之类的,整合更为容易了。
5. 模板支持
支持使用模板生成视图。
6. 插件支持
有大量的插件可用于Struts2,而使用插件可以增强和扩大Struts2 核心行为。
7. 性能分析
Struts2 为调试和配置应用程序提供综合的性能分析,此外,Struts也以嵌入调试工具的形式提供集成调试。
8. 易于修改标签
在Struts2 中,可使用Freemarker的模板对标签标记进行调整,而修改标签不需要JSP或是Java知识,基本的HTML、XML和CSS知识就足够了。
9. 促进减少配置
Struts2 使用各种设置的默认值促进减少配置,而你不需要再配置什么除非是偏离了Struts2 设定的默认设置。
10. 视图技术
Struts2 为多种视图选项(JSP、Freemarker、Velocity、XSLT等)提供支持
缺点:
1. 更大的学习曲线
使用Struts MVC,你必须要熟悉JSP、Servlet APIs标准以及一个大型、复杂的框架。
2. 文档缺乏
相比于Servlet和JSP APIs标准,Struts的在线资源较少,许多初学者会发现Apache在线文档混乱并缺乏整理。
3. 不够透明
相比于使用正常的基于Java的Web应用程序,使用Struts的应用程序有许多是进行在后台,这使得框架不易于理解。
设计模式
基于MVC
M:模型层,负责管理数据(存储,提供,处理)
V:视图层,负责展示数据
C:控制层,负责将模型层中的数据展现给视图层
环境配置
JDK、Tomcat、MyEclipse
下载Struts2 http://struts.apache.org/download.cgi
架构
架构
架构说明
操作(Actions)
拦截器(Interceptors)
值栈(Value Stack)/OGNL
提供共同的路线、链接以及与其他组件之间的集成
结果(Result)/结果类型
视图
组件
web应用程序组件、Actions组件、拦截器组件、结果组件等。
MVC
控制器
通过Struts2 分派servlet过滤器以及拦截器进行实现
模型
通过Actions进行实现
视图
结果类型和结果的结合
一次请求的生命周期
1. 用户发送请求(页面)到服务器。
2. 核心控制器查看请求后确定适当的动作。
3. 使用验证、文件上传等配置拦截器功能。
4. 执行选择的动作来完成请求的操作。
5. 如果需要的话,配置的拦截器可做任何后期处理。
6. 最后,由视图显示结果并返回给用户。
示例:Hello World!
1. 创建Web项目
MyEclipse项目栏 | 右键New | Web Service Product
拷贝Struts2.5文件夹中的以下到WEB-INF的lib中
commons-fileupload-x.y.z.jar
commons-io-x.y.z.jar
commons-lang-x.y.jar
commons-logging-x.y.z.jar
commons-logging-api-x.y.jar
freemarker-x.y.z.jar
javassist-x.y.z.GA
ognl-x.y.z.jar
struts2-core-x.y.z.jar
2. Action
完整的业务逻辑并控制用户、模型以及视图间的交互。
src下新建包com.sst.cx | 新建HelloWorldAction
package com.sst.cx;
public class HelloWorldAction {
private String name;
public String execute() throws Exception {
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3. 视图
与用户进行交互,获取输入并呈现最终信息。
WebRoot下新建HelloWorld.jsp
<%@ 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>
修改index.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!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>
<!--调用action-->
<form action="hello">
<label for="name">Please enter your name</label><br/>
<!--传给action的name属性-->
<input type="text" name="name"/>
<input type="submit" value="Say Hello"/>
</form>
</body>
</html>
4. 配置文件
struts.xml、web.xml以及struts.properties
连接动作、视图以及控制器
在src文件夹下创建 struts.xml 文件
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>
<!--
constant
覆盖default.properties中定义的属性
struts.devMode属性允许我们在日志文件中查看更多的调试消息
-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<constant name="struts.devMode" value="true" />
<!--
package
name:唯一标识
namespace:action唯一命名空间
extends:继承,一般struts-default
abstract:如果标记为true,则package不能被直接使用。
-->
<package name="helloworld" namespace="/" extends="struts-default">
<global-allowed-methods>regex:.*</global-allowed-methods>
<!--
action
name: 访问时使用
-->
<action name="index">
<!--
result
name:默认值是“success”,即返回success时跳转到index.jsp
-->
<result>index.jsp</result>
</action>
<action name="hello" class="com.sst.cx.HelloWorldAction">
<result name="success">HelloWorld.jsp</result>
</action>
</package>
<!--
当文件过长时,可:
<include file="my-struts1.xml"/>
<include file="my-struts2.xml"/>
-->
</struts>
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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>StrutsTest</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- struts2的配置 ,所有请求会被struts过滤-->
<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>
5. 运行
创建Web项目
拷贝jar 、新建Action类
其他配置文件
除上述配置文件外,还有struts-config.xml以及struts.properties
struts-config.xml(连接View和Model组件,一般不用)
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">
<!--配置文件的根节点-->
<struts-config>
<!--
========== Form Bean Definitions ============
将ActionForm子类映射到name的位置
-->
<form-beans>
<form-bean name="login" type="test.struts.LoginForm" />
</form-beans>
<!--
========== Global Forward Definitions =========
将在webapp上的页面映射到name
-->
<global-forwards>
</global-forwards>
<!--
========== Action Mapping Definitions ========
操作映射
-->
<action-mappings>
<action
path="/login"
type="test.struts.LoginAction" >
<forward name="valid" path="/jsp/MainMenu.jsp" />
<forward name="invalid" path="/jsp/LoginView.jsp" />
</action>
</action-mappings>
<!--
========== Controller Definitions ========
配置Struts的内部
-->
<controller
contentType="text/html;charset=UTF-8"
debug="3"
maxFileSize="1.618M"
locale="true"
nocache="true"/>
<!--
plug-in
属性文件,它包含提示和错误消息
-->
</struts-config>
struts.properties文件
提供了一种机制来改变框架的默认行为。
配置的值将覆盖default.properties,也可以在web.xml中使用init-param配置,或在struts.xml中使用constant标签中配置。
位置:WEB-INF/classes下?
### When set to true, Struts will act much more friendly for developers
struts.devMode = true
### Enables reloading of internationalization files
struts.i18n.reload = true
### Enables reloading of XML configuration files
struts.configuration.xml.reload = true
### Sets the port that the server is run on
struts.url.http.port = 8080
- Action
是Struts2框架的核心
每个URL会映射到特定的action(对请求进行逻辑处理,将结果传给jsp)
必须有一个无参数方法返回String或Result对象,并且必须是POJO。如果没有指定则默认是使用execute()方法。
可以继承ActionSupport类(实现了六个接口,包括Action接口,可直接使用以下常量)
Action接口如下:
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;
}
- 拦截器
用于
在调用action之前提供预处理逻辑。
在调用action后提供后处理逻辑。
捕获异常,以便可以执行备用处理。
Struts2大部分功能基于拦截器
系统拦截器
alias
允许参数在请求之间使用别名。
checkbox
通过为未检查的复选框添加参数值false,以辅助管理复选框。
conversionError
将字符串转换为参数类型的错误信息放置到action的错误字段中。
createSession
自动创建HTTP会话(如果尚不存在)。
debugging
为开发人员提供一些不同的调试屏幕。
execAndWait
当action在后台执行时,将用户发送到中间的等待页面。
exception
映射从action到结果抛出的异常,允许通过重定向自动处理异常。
fileUpload
便于文件上传。
i18n
在用户会话期间跟踪选定的区域。
logger
通过输出正在执行的action的名称提供简单的日志记录。
params
设置action上的请求参数。
prepare
这通常用于执行预处理工作,例如设置数据库连接。
profile
允许记录action的简单分析信息。
scope
在会话或应用程序范围内存储和检索action的状态。
ServletConfig
提供可访问各种基于servlet信息的action。
timer
以action执行时间的形式提供简单的分析信息。
token
检查action的有效性,以防止重复提交表单。
validation
提供action的验证支持。
使用struts.xml的action下+
<interceptor-ref name="params"/> 传参
<interceptor-ref name="timer" /> 计时
自定义拦截器
扩展Interceptor接口(如下:)
public interface Interceptor extends Serializable{
void destroy();
void init();
String intercept(ActionInvocation invocation)
throws Exception;
}
如果不需要初始化或清理代码,可以扩展AbstractInterceptor类
struts.xml的
package下+
<interceptors>
<interceptor name="myinterceptor"
class="com.sst.cx.MyInterceptor" />
</interceptors>
action下+
<interceptor-ref name="myinterceptor" />
package com.sst.cx;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class MyInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
/* let us do some pre-processing */
String output = "Pre-Processing";
System.out.println(output);
/* let us call action or next interceptor */
/*每次调用invoke()时,ActionInvocation都会查询其状态,并执行下一个拦截器。当所有配置的拦截器都被调用时,invoke()将使得action本身被执行。*/
String result = invocation.invoke();
/* let us do some post-processing */
output = "Post-Processing";
System.out.println(output);
return result;
}
}
拦截器堆栈
拦截器很多时,便于管理
struts.xml的
package下+
<interceptor-stack name="basicStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="servlet-config"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
</interceptor-stack>
action下+
<interceptor-ref name="myinterceptor" />
- result结果类型
<result name="success"> /HelloWorld.jsp </result>
Struts允许使用其他标记语言(dispatcher,Velocity,Freemaker,XSLT和Tiles)呈现视图。
dispatcher(默认的结果类型)
用于分发到JSP页面
<result name="success">
/HelloWorld.jsp
</result>
<result name="success" type="dispatcher">
<param name="location">
/HelloWorld.jsp
</param >
</result>
FreeMaker
使用预定义的模板生成输出
<result name="success" type="freemarker">
<param name="location">hello.fm</param>
</result>
hello.fm内容:
Hello World ${name}
redirect
调用标准的response.sendRedirect()方法
<result name="success" type="redirect">
<param name="location">
NewWorld.jsp
</param >
</result>
- 值栈/OGNL
值栈
值栈是一组对象
通过为JSP,Velocity或Freemarker提供的标签进行访问
按照提供的顺序存储以下这些对象:
Temporary对象
实际中存在各种在页面执行期间创建的temporary对象。例如,JSP标签循环集合的当前迭代值。
Model对象
如果在struts应用程序中使用Model对象,则当前Model对象放在值堆栈上的action之前。
Action对象
这是指正在执行的当前action对象。
命名对象
这些对象包括#application,#session,#request,#attr和#parameters以及所引用的相应的servlet作用域。
action中获取值栈对象
ActionContext.getContext().getValueStack()
值栈对象有以下方法:
Object findValue(String expr)
通过在默认搜索顺序中对值栈评估所给定的表达式来查找值。
CompoundRoot getRoot()
获取将对象推入值栈的CompoundRoot。
Object peek()
获取值栈顶部的对象而不改变值栈。
Object pop()
获取值栈顶部的对象,并将其从值栈中删除。
void push(Object o)
将对象放在值栈的顶部。
void set(String key,Object o)
使用给定的key在值栈上设置一个对象,使其可通过findValue(key,...)检索。
void setDefaultType(Class defaultType)
设置在获取值时要转换的默认类型。
void setValue(String expr,Object value)
尝试使用由默认搜索顺序给定的表达式在值栈的bean上设置属性。
int size()
获取值栈中的对象数。
OGNL
OGNL(Object-Graph Navigation Language,对象图导航语言)
是一种强大的表达式语言,用于引用和操作值栈上的数据,还可用于数据传输和类型转换。类似于JSP表达式语言。
基于上下文中存有根对象或默认对象的理念,使用标记符号(即#号)来引用默认或根对象的属性。
Struts构建了一个ActionContext映射以供OGNL使用。 ActionContext映射包含以下内容:
应用程序 - 应用程序作用域变量
会话 - 会话作用域变量
根/值栈 - 所有的action变量都存储在这里
请求 - 请求作用域变量
参数 - 请求参数
属性 - 存储在页面,请求,会话和应用程序作用域中的属性
会话属性
<s:property value="#session.login"/>
action属性(Struts 2在执行时会将action添加到值栈的顶部)使用:
action添加属性/set/get方法
jsp使用<s:property value="name"/>访问
ActionContext中的对象使用#号引用,但是,值栈中的对象可以直接引用。
OGNL还支持处理集合 - 即Map,List和Set
<s:select name="color" list="{'red','yellow','green'}" />
例
HelloWorldAction.java
package com.sst.cx;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import java.util.*;
public class HelloWorldAction extends ActionSupport{
private String name;
public String execute() throws Exception {
//
ValueStack stack = ActionContext.getContext().getValueStack();
//
Map<String, Object> context = new HashMap<String, Object>();
context.put("key1", new String("This is key1"));
context.put("key2", new String("This is key2"));
stack.push(context);
//
System.out.println("Size of the valueStack: " + stack.size());
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
jsp中
<%@ taglib prefix="s" uri="/struts-tags" %>
<s:property value="name"/><br/>
<s:property value="key1" /><br/>
- 注释
用于替代struts.xml
有点问题,待解决!
注意:
1.导入:struts2-convention-plugin-2.5.16.jar
2.action处理类放在struts, struts2, action, actions包或者其子包中,否则会提示找不到联系。
3.Action要必须继承ActionSupport父类
@ParentPackage
对应package,一般需要继承struts-defaul
@Namespace
对应nameSpace,命名空间
@Action
对应action
value(),表示action的请求名称,也就是<action>节点中的name属性;
results(),表示action的多个result;这个属性是一个数组属性,因此可以定义多个Result;
interceptorRefs(),表示action的多个拦截器。这个属性也是一个数组属性,因此可以定义多个拦截器;
exceptionMappings(),这是异常属性,它是一个ExceptionMapping的数组属性,表示action的异常,在使用时必须引用相应的拦截器
@Result
对应result,这个注解只能应用于action类上。
name(),表示action方法的返回值,也就是<result>节点的name属性,默认情况下是【success】;
location(),表示view层文件的位置,可以是相对路径,也可以是绝对路径;
type(),是action的类型,比如redirect,不指定情况下,框架默认的是dispatcher
TestAction.java
package com.action;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.validator.annotations.IntRangeFieldValidator;
import com.opensymphony.xwork2.validator.annotations.RequiredFieldValidator;
public class TestAction extends ActionSupport {
private String name;
private int age;
@Action(
value="TestA",
results={
@Result(name="success", location="success.jsp"),
@Result(name="input", location="index.jsp")
}
)
public String execute()
{
return SUCCESS;
}
@RequiredFieldValidator( message = "The name is required" )
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@IntRangeFieldValidator(message = "Age must be in between 28 and 65",
min = "29", max = "65")
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
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>
<s:form action="/TestA" method="post">
<s:textfield name="name" label="Name" size="20" />
<s:textfield name="age" label="Age" size="20" />
<s:submit name="submit" label="Submit" align="center" />
</s:form>
</body>
</html>
- 异常处理
Struts通过exception拦截器来处理异常
单个处理
创建error.jsp
struts.xml中
<action name="testEx" class="action.HelloExAction">
<exception-mapping exception="java.lang.NullPointerException"
result="error" />
<result name="error">error.jsp</result>
<result >HelloWorld.jsp</result>
</action>
全局处理
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>
<package name="helloworld" namespace="/" extends="struts-default">
<global-allowed-methods>regex:.*</global-allowed-methods>
<global-exception-mappings>
<exception-mapping exception="java.lang.NullPointerException"
result="error" />
</global-exception-mappings>
<action name="testEx" class="action.HelloExAction">
<result >HelloWorld.jsp</result>
<result name="error">error.jsp</result>
</action>
</package>
</struts>
- 类型转换
HTTP请求上的所有内容(数字,布尔值,整数,日期,小数和其他)都按协议处理为字符串
Struts类中,可以具有任意数据类型的属性
Struts自动类型转换:
Integer,Float,Double,Decimal
Date,Datetime
Arrays,Collections
Enumerations
Boolean
BigDecimal
自定义类类型
做属性时使用<s:property value="属性(自定义类)"/>访问会默认显示包路径.类名@3c50f23c。
新建转换类extends StrutsTypeConverter
全局处理
src下新建xwork-conversion.properties
包路径.自定义类 = 包路径.EnvironmentConverter转换类
转换类
package action;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
public class EnvironmentConverter extends StrutsTypeConverter {
@Override
public Object convertFromString(Map context, String[] values, Class clazz) {
Enu env = new Enu(values[0]);
return env;
}
@Override
public String convertToString(Map context, Object value) {
Enu env = (Enu) value;
return env == null ? null : env.getName();
}
}
- 主题和模板
tag(标签)
从JSP,FreeMarker或Velocity内部执行的一小段代码。
template(模板)
一些代码,通常是写在FreeMarker上的,可以由某些标签(HTML标签)呈现。
theme(主题)
封装在一起以提供公共功能的模板集合。
主题
Struts2 具有三个内置主题
simple theme
没有“bells and whistles”的最小主题。例如,textfield标签呈现HTML<input/>标签无标记、验证、错误报告或任何其他格式或功能。
xhtml theme
默认主题,提供了simple theme具备的所有基础,并添加了几个功能,如HTML的标准两列表布局、每个HTML的标记、验证和错误报告等。
css_xhtml theme
提供了simple theme具备的所有基础,并添加了几个功能,如基于CSS的标准两列布局,对HTML Struts标签使用<div>,HTML Struts每个标签的标记,根据CSS样式表放置等。
默认主题:xhtml theme
<s:textfield name="name" label="Name" />
生成
<tr>
<td class="tdLabel">
<label for="empinfo_name" class="label">Name:</label>
</td><td>
<input type="text" name="name" value="" id="struts.xml中的action名"/>
</td>
</tr>
指定主题
各种方式如下:
特定标签上的theme属性
<s:textfield name="name" label="Name" theme="xhtml"/>
标签的周边表单标签的theme属性
名为“theme”的页面作用域属性
名为“theme”的请求作用域属性
名为“theme”的会话作用域属性
名为“theme”的应用程序作用域属性
struts.properties中的struts.ui.theme属性(默认为xhtml)
# Standard UI theme
struts.ui.theme=xhtml
# Directory where theme template resides
struts.ui.templateDir=template
# Sets the default template type. Either ftl, vm, or jsp
struts.ui.templateSuffix=ftl
创建新主题
对于给定的主题,每个struts标签都有一个关联的模板,如s:textfield -> text.ftl和s:password -> password.ftl等。这些模板文件压缩在struts2-core.xy.z.jar文件中,它们为每个标签保留预定义的HTML布局。
1.src下新建template目录 | mytheme目录
2.复制struts2-core-x.y.z.jar/template/xhtml中的内容
3.修改control.ftl文件
<table style="border:1px solid black;" class="${parameters.cssClass!'wwFormTable'?html}"<#rt/>
<#if parameters.cssStyle??> style="${parameters.cssStyle?html}"<#rt/>
</#if>
>
4.修改form.ftl中的引用control.ftl路径
<#include "/${parameters.templateDir}/mytheme/control.ftl" />
5.struts.properties指定主题
# Customized them
struts.ui.theme=mytheme
# Directory where theme template resides
struts.ui.templateDir=template
# Sets the template type to ftl.
struts.ui.templateSuffix=ftl
6.jsp使用标签
9.标签
控制标签
判断
<s:if test="name=='Mike'">
You have selected 'Mike'.
</s:if>
<s:elseif test="name=='Jason'">
You have selected 'Jason'
</s:elseif>
<s:else>
You have not selected 'Mike' or 'Jason'.
</s:else>
迭代
iterator
<s:iterator value="days">
<p>day is: <s:property/></p>
</s:iterator>
generator
<s:generator val="%{'Violet,Indigo,Blue,
Green,Yellow,Orange,Red '}" count="7"
separator=",">
<s:iterator>
<s:property /><br/>
</s:iterator>
</s:generator>
合并列表
merge
<s:merge id="allemployees">
<s:param value="employees" />
<s:param value="contractors" />
</s:merge>
<s:iterator value="allemployees">
<s:property value="name"/>,
<s:property value="department"/><br/>
</s:iterator>
append
<s:append id="allemployees">
<s:param value="employees" />
<s:param value="contractors" />
</s:append >
<s:iterator value="allemployees">
<s:property value="name"/>,
<s:property value="department"/><br/>
</s:iterator>
数据标签
action标签
显示action页面内容
<s:action name="actionTagAction" executeResult="true" />
include标签
包含其他jsp
<-- First Syntax -->
<s:include value="myJsp.jsp" />
<-- Second Syntax -->
<s:include value="myJsp.jsp">
<s:param name="param1" value="value2" />
<s:param name="param2" value="value2" />
</s:include>
<-- Third Syntax -->
<s:include value="myJsp.jsp">
<s:param name="param1">value1</s:param>
<s:param name="param2">value2</s:param>
</s:include>
bean标签
实例化一个符合JavaBeans规范的类
<s:bean name="org.apache.struts2.util.Counter" var="counter">
<s:param name="first" value="20"/>
<s:param name="last" value="25" />
</s:bean>
<ul>
<s:iterator value="#counter">
<li><s:property /></li>
</s:iterator>
</ul>
date标签
格式化日期
<s:date name="currentDate" format="MM/dd/yyyy" />
<s:date name="person.birthday" format="dd/MM/yyyy" />
<s:date name="person.birthday" format="%{getText('some.i18n.key')}" />
<s:date name="person.birthday" nice="true" />
<s:date name="person.birthday" />
param标签
参数化其他标签
name(字符串) - 参数的名称
value(对象) - 参数的值
<s:bean name="org.apache.struts2.util.Counter" var="counter">
<s:param name="first" value="20"/>
<s:param name="last" value="25" />
</s:bean>
<ul>
<s:iterator value="#counter">
<li><s:property /></li>
</s:iterator>
</ul>
property标签
用于获取一个值的属性
<s:push value="myBean">
<!-- Example 1: -->
<s:property value="myBeanProperty" />
<!-- Example 2: -->TextUtils
<s:property value="myBeanProperty" default="a default value" />
</s:push>
push标签
用于推送堆栈中的值
<s:push value="user">
<s:propery value="firstName" />
<s:propery value="lastName" />
</s:push>
set标签
为指定范围内的变量赋值
<s:set name="myenv" value="environment.name"/>
<s:property value="myenv"/>
text标签
用于呈现I18n文本消息
<!-- First Example -->
<s:i18n name="struts.action.test.i18n.Shop">
<s:text name="main.title"/>
</s:i18n>
<!-- Second Example -->
<s:text name="main.title" />
<!-- Third Examlpe -->
<s:text name="i18n.label.greetings">
<s:param >Mr Smith</s:param>
</s:text>
url标签
用于创建URL
<-- Example 1 -->
<s:url value="editGadget.action">
<s:param name="id" value="%{selected}" />
</s:url>
<-- Example 2 -->
<s:url action="editGadget">
<s:param name="id" value="%{selected}" />
</s:url>
<-- Example 3-->
<s:url includeParams="get">
<s:param name="id" value="%{'22'}" />
</s:url>
表单标签
简单UI标签
<s:head/>
<s:div>Email Form</s:div>
<s:text name="Please fill in the form below:" />
<s:form action="hello" method="post" enctype="multipart/form-data">
<s:hidden name="secret" value="abracadabra"/>
<s:textfield key="email.from" name="from" />
<s:password key="email.password" name="password" />
<s:textfield key="email.to" name="to" />
<s:textfield key="email.subject" name="subject" />
<s:textarea key="email.body" name="email.body" />
<s:label for="attachment" value="Attachment"/>
<s:file name="attachment" accept="text/html,text/plain" />
<s:token />
<s:submit key="submit" />
</s:form>
说明:
s:head生成Struts2 应用程序所需的javascript和stylesheet元素。
s:token标签生成唯一的token,用于查明表单是否已被两次提交。
群组UI标签(单选/多选)
<s:head/>
<s:form action="hello.action">
<s:radio label="Gender" name="gender" list="{'male','female'}" />
<s:checkboxlist label="Hobbies" name="hobbies"
list="{'sports','tv','shopping'}" />
</s:form>
选择UI标签(下拉选择)
<s:form action="login.action">
<s:select name="username" label="Username"
list="{'Mike','John','Smith'}" />
<s:select label="Company Office" name="mySelection"
value="%{'America'}"
list="%{#{'America':'America'}}">
<s:optgroup label="Asia"
list="%{#{'India':'India','China':'China'}}" />
<s:optgroup label="Europe"
list="%{#{'UK':'UK','Sweden':'Sweden','Italy':'Italy'}}" />
</s:select>
<s:combobox label="My Sign" name="mySign"
list="#{'aries':'aries','capricorn':'capricorn'}"
headerKey="-1"
headerValue="--- Please Select ---" emptyOption="true"
value="capricorn" />
<s:doubleselect label="Occupation" name="occupation"
list="{'Technical','Other'}" doubleName="occupations2"
doubleList="top == 'Technical' ?
{'I.T', 'Hardware'} : {'Accounting', 'H.R'}" />
</s:form>
Ajax标签
需导入struts2-dojo-plugin-2.2.3.jar
<%@ taglib prefix="s" uri="/struts-tags"%>
<%@ taglib prefix="sx" uri="/struts-dojo-tags"%>
<s:head />
<sx:head /> 初始化dojo框架
<s:form>
<sx:autocompleter label="Favourite Colour"
list="{'red','green','blue'}" />
<br />
<sx:datetimepicker name="deliverydate" label="Delivery Date"
displayFormat="dd/MM/yyyy" />
<br />
<s:url id="url" value="/hello.action" />
<sx:div href="%{#url}" delay="2000">
Initial Content
</sx:div>
<br/>
<sx:tabbedpanel id="tabContainer">
<sx:div label="Tab 1">Tab 1</sx:div>
<sx:div label="Tab 2">Tab 2</sx:div>
</sx:tabbedpanel>
</s:form>
2. 常用
2.1 文件上传
为依据“基于表单的HTML文件上传”所进行的文件处理上传提供了内置支持。当文件上传时,它通常会存储在临时目录中,然后Action类应对其进行处理或移动到固定目录中,以确保数据不会丢失。
注意:
服务器可能有适当的安全策略,禁止你写入临时目录以外的目录以及属于Web应用程序的目录。
FileUpload拦截器会自动删除上传的文件
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="upload" method="post" enctype="multipart/form-data">
<label for="myFile">Upload your file</label>
<input type="file" name="myFile" />
<input type="submit" value="Upload"/>
</form>
</body>
</html>
UploadFile.java
package com.sst.cx;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FileUtils;
import com.opensymphony.xwork2.ActionSupport;
public class UploadFile extends ActionSupport {
// 文件(xxx)
private File myFile;
// 文件类型(xxxContentType)
private String myFileContentType;
// 文件名(xxxFileName)
private String myFileFileName;
// 文件保存路径
private String destPath;
public String execute(){
/* Copy file to a safe location */
destPath = "/Users/cx/Desktop/work/";
try{
System.out.println("Src File name: " + myFile);
System.out.println("Dst File name: " + myFileFileName);
File destFile = new File(destPath, myFileFileName);
FileUtils.copyFile(myFile, destFile);
}catch(IOException e){
e.printStackTrace();
return ERROR;
}
return SUCCESS;
}
public File getMyFile() {
return myFile;
}
public void setMyFile(File myFile) {
this.myFile = myFile;
}
public String getMyFileContentType() {
return myFileContentType;
}
public void setMyFileContentType(String myFileContentType) {
this.myFileContentType = myFileContentType;
}
public String getMyFileFileName() {
return myFileFileName;
}
public void setMyFileFileName(String myFileFileName) {
this.myFileFileName = myFileFileName;
}
}
struts.xml
struts下(可选加)
<!--可接受的上传文件的最大值(以字节为单位),默认值为250M。-->
<constant name="struts.multipart.maxSize" value="1000000" />
struts.multipart.parser
用于上传多部分表单的库,默认为jakarta
struts.multipart.saveDir
存储临时文件的位置,默认是javax.servlet.context.tempdir-
几个默认的错误信息key
struts.messages.error.uploading
无法上传文件时发生的常规错误。
struts.messages.error.file.too.large
当上传的文件过大(由maximumSize指定)时发生。
struts.messages.error.content.type.not.allowed
当上传的文件与指定的预期内容类型不匹配时发生。
action:
<action name="upload" class="com.sst.cx.UploadFile">
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="fileUpload">
<param name="allowedTypes">application/pdf,text/plain,image/bmp,image/png</param>
<param name="maximumSize">5242880</param>
</interceptor-ref>
<result name="success">HelloWorld.jsp</result>
</action>
2.2 访问数据库
<%@ 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="login" method="post">
User:<br/><input type="text" name="user"/><br/>
Password:<br/><input type="password" name="password"/><br/>
<input type="submit" value="Login"/>
</form>
</body>
</html>
package com.sst.cx;
import java.sql.*;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private String user;
private String password;
private String name;
public String execute() {
String ret = ERROR;
Connection conn = null;
try {
String URL = "jdbc:mysql://localhost:3306/Test";
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(URL, "root", "密码");
String sql = "SELECT name FROM users WHERE";
sql+=" name = ? AND password = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, user);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
name = rs.getString(1);
ret = SUCCESS;
}
} catch (Exception e) {
ret = ERROR;
} finally {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
}
}
}
return ret;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<action name="login" class="com.sst.cx.LoginAction">
<result >HelloWorld.jsp</result>
</action>
2.3 发送邮件
<%@ 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>
<em>The form below uses Google's SMTP server.
So you need to enter a gmail username and password
</em>
<form action="emailT" method="post">
<label for="from">From</label><br/>
<input type="text" name="from"/><br/>
<label for="password">Password</label><br/>
<input type="password" name="password"/><br/>
<label for="to">To</label><br/>
<input type="text" name="to"/><br/>
<label for="subject">Subject</label><br/>
<input type="text" name="subject"/><br/>
<label for="body">Body</label><br/>
<input type="text" name="body"/><br/>
<input type="submit" value="Send Email"/>
</form>
</body>
</html>
package com.sst.cx;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import com.opensymphony.xwork2.ActionSupport;
public class Emailer extends ActionSupport {
private String from;
private String password;
private String to;
private String subject;
private String body;
static Properties properties = new Properties();
static
{
properties.setProperty("mail.host", "smtp.sohu.com");
properties.setProperty("mail.transport.protocol", "smtp");
properties.setProperty("mail.smtp.auth", "true");
properties.setProperty("mail.smtp.port", "25");
properties.setProperty("mail.smtp.timeout","1000");
properties.put("mail.smtp.starttls.enable", "true");
}
public String execute()
{
String ret = SUCCESS;
try
{
Session session = Session.getDefaultInstance(properties,
new javax.mail.Authenticator() {
protected PasswordAuthentication
getPasswordAuthentication() {
return new
PasswordAuthentication(from, password);
}});
Message message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(to));
message.setSubject(subject);
message.setText(body);
Transport.send(message);
}
catch(Exception e)
{
ret = ERROR;
e.printStackTrace();
}
return ret;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public static Properties getProperties() {
return properties;
}
public static void setProperties(Properties properties) {
Emailer.properties = properties;
}
}
<action name="emailT" class="com.sst.cx.Emailer">
<result >HelloWorld.jsp</result>
</action>
2.4 验证框架
package com.sst.cx;
import com.opensymphony.xwork2.ActionSupport;
public class Employee extends ActionSupport {
private String name;
private int age;
public String execute()
{
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void validate()
{
if (name == null || name.trim().equals(""))
{
addFieldError("name","The name is required");
}
if (age < 28 || age > 65)
{
addFieldError("age","Age must be in between 28 and 65");
}
}
}
<%@ 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>
<s:form action="Employee" method="post">
<s:textfield name="name" label="Name" size="20" />
<s:textfield name="age" label="Age" size="20" />
<s:submit name="submit" label="Submit" align="center" />
</s:form>
</body>
</html>
<action name="Employee" class="com.sst.cx.Employee">
<result >HelloWorld.jsp</result>
<result name="input">/index.jsp</result>
</action>
验证失败则返input,将错误信息传给表单页
XML验证
在action类旁边放置一个xml文件,命名为'[action-class]'-validation.xml
email验证、integer range验证、form验证、expression验证、regex验证、required验证、requiredstring验证、stringlength验证等
!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="name">
<field-validator type="required">
<message>
The name is required.
</message>
</field-validator>
</field>
<field name="age">
<field-validator type="int">
<param name="min">29</param>
<param name="max">64</param>
<message>
Age must be in between 28 and 65
</message>
</field-validator>
</field>
</validators>
public class Employee extends ActionSupport{
private String name;
private int age;
public String execute()
{
return SUCCESS;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2.5 本地化/国际化(i18n)
Struts2使用bundle资源束、拦截器和标签库提供本地化
用于
UI标签(固定文本)
Action类(动态文本)
信息和错误
为每种语言创建一个资源束(key/value)文件
命名方式:
bundlename_language_country.properties
bundlename
ActionClass,Interface,SuperClass,Model,Package,Global资源属性
language_country
国家区域设置,例如西班牙语(西班牙)区域设置由es_ES表示,英语(美国)区域设置由en_US表示
搜索顺序:
ActionClass.properties
Interface.properties
SuperClass.properties
model.properties
package.properties
struts.properties
global.properties
例:
global.properties:默认情况下使用英语(美国)
global_fr.properties:这将用于法语环境。
global_es.properties:这将用于西班牙语环境
使用(获取)方式
getText
<s:property value="getText('bundlename.key')" />
text(从默认资源束(即struts.properties)中检索信息)
<s:text name="bundlename.key" />
i18n(会将任意资源束推送到值栈,而i18n标签内的其他标签可以显示来自该资源束的信息)
<s:i18n name="bundlename.package.bundle">
<s:text name="bundlename.key" />
</s:i18n>
key
<s:textfield key="bundlename.key" name="textfieldName"/>
示例
global.properties(src下)
global.name = Name
global.age = Age
global.submit = Submit
global.heading = Select Locale
global.success = Successfully authenticated
global_fr.properties(src下)
global.name = Nom d'utilisateur
global.age = l'âge
global.submit = Soumettre des
global.heading = Sé lectionnez Local
global.success = Authentifi é avec succès
jsp
<s:text name="global.heading"/>
<s:param name="request_locale" >en</s:param>
<s:form action="Employee" method="post" namespace="/">
<s:textfield name="name" key="global.name" size="20" />
<s:textfield name="age" key="global.age" size="20" />
<s:submit name="submit" key="global.submit" />
</s:form>
2.6 处理404错误(路径不正确)
struts.xml中+
<package name="error" extends="struts-default">
<default-action-ref name="notFound" />
<action name="notFound">
<result>404.jsp</result>
</action>
</package>
WEB-INF 下新建404.jsp