struts2介绍
概括
struts2是J2EE的比较流行的框架,对JSP/servlet进行了封装,应用于面向WEB开发的项目。
struts是MVC设计模式的一种解决方案
Struts2是基于MVC的Web应用框架
Struts2=Struts1的知名度和市场+WebWork的技术
实现MVC模式,结构清晰
丰富的标签(tag)
通过配置文件页面导航,便于后期维护
与Servlet API松耦合,便于测试
下载
http://struts.apache.org
Projects -- > struts
http://archive.apache.org/dist/struts/binaries/
功能介绍
数据输入校验。
Struts标签用于页面开发。
可扩展性编程。
采用拦截器实现AOP功能。
国际化和本地化。
文件上传下载。
表单重复提交校验
struts2和struts1的区别
1)Action实现:struts1继承抽象的父类,struts2不需要。
2)Action实例化:struts1中Action是单例模式,Struts2为每一个请求创建一个Action实例。
3)与jsp/Servlet耦合:struts1在调用传统的jsp/servletAPI,但struts2可以调用jsp/servlet的API(不推荐),但重新封装了其他的API(与jsp/servlet无关),实现解耦。
4)测试方面:因为Struts1仍然调用servlet的API,因此测试必须依赖于web服务器,但Struts2克通过实例化,方法调用的方式测试。
5)表达式语言:struts1整合了JSTL,struts2则整合了 更为强大的OGNL表达式。
6)struts2与struts1除了命名之外,其实没有多大关系。
目录结构
apps:基于Struts2的示例应用
docs:Struts2开发的各类帮助文档
lib:核心类库及第三方插件类库
requied-lib:Struts 2开发常用的jar文件
src:Struts2框架的源代码
使用
1.导入jar包
struts2-core-2.3.4.1.jar Struts2的核心包
xwork-core-2.3.4.1.jar xwork的核心包
commons-io-2.0.1.jar 支持IO读写操作
commons-fileupload-1.2.2.jar 支持文件的上传和下载
ognl-3.0.5.jar 支持OGNL表达式
freemarker-2.3.19.jar 基于模板生成文本输出的通用工具/标签库模板包
javassist-3.11.0.GA.jar 支持JAVA字节码操作
commons-lang3-3.1.jar 对java.lang包扩展
2.配置struts2的核心过滤器
在web.xml中配置
<filter>
<filter-name>struts2</filter-name>
<!-- 核心控制器,负责拦截用户的请求,根据请求的不同,分发给相应的Action处理 -->
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<!-- 将全部请求定位到指定的Struts 2过滤器中 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
3.truts2的配置文件
在src目录下
默认struts.xml
4.编写Action
5.在struts配置文件中配置action
Action
作用
处理请求
实现业务逻辑
返回result决定结果视图
实现方式
1.普通的Java类
2.实现Action接口
3.继承ActionSupport类
普通的Java类
public class OneAction{
public String execute() throws Exception {
System.out.println("访问到了");
//返回的字符串 对应 result的name属性
return "success";
}
}
实现Action接口
public class OneAction implements Action{
@Override
public String execute() throws Exception {
System.out.println("访问到了");
//返回的字符串 对应 result的name属性
return "success";
}
}
继承ActionSupport类
public class OneAction extends ActionSupport{
private static final long serialVersionUID = 2245233853322624873L;
//action中默认调用的方法就是execute方法
@Override
public String execute() throws Exception {
System.out.println("访问到了");
//返回的字符串 对应 result的name属性
return "success";
}
}
配置
<action name="one" class="com.shuai.test.OneAction" method="execute">
<result name="success">/info.jsp</result>
</action>
Struts配置文件
基础配置
这个配置文件需要到struts的源码中去搜索,随便一个就可以。
<?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>
</struts>
内容
<package name="shuai" extends="struts-default" namespace="/shuai">
<action name="" class="" method="">
<result name=""></result>
</action>
</package>
说明
package
说明
包,管理action的路径
name
包名
作用:给其它包去继承
注意:包名必须要唯一,否则启动会报错
namespace
命名空间
可以对路径进行管理
是url的一部分
默认是/
如果是 /test 访问路径 = /test/actionName
extends
继承
自定义的包,必须要继承 struts-default
struts-default.xml
文件目录 struts2-core-xxx.jar/struts-default.xml
result-types : 返回值类型
interceptors : 拦截器
abstract
默认是false,如果是true表示是一个抽象包,即里面不能有action的定义。
action
说明
是一个控制器
作用:配置访问路径与处理action的映射关系
name
访问路径
控制器的名称,是url的一部分
class
控制器实际路径
访问路径对应action类的全名 可以不写 默认是ActionSupport
默认的class写法用来做页面跳转
WebContent目录下是 /hello.jsp
WEB-INF目录下是 /WEB-INF/hello.jsp
默认的class在 struts-default.xml中配置了 <default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
修改默认执行的Action类 一般不会做修改
<default-class-ref class="com.shuai.struts2.action.six.MyDefaultAction"></default-class-ref>
method
执行的方法,默认是execute
可以省略不写
result
说明
是结果集
配置action中处理请求的方法,返回的结果视图标记对应的跳转资源
name
是结果的名称,通过action动作的返回值来指定。
action处理方法的返回值
文本值
是结果视图
type
设置结果视图的类型和跳转方式
转发 : dispatcher 默认
重定向 : redirect
这两个值都在struts-default.xml 中result-types中有定义
struts2访问过程
http://localhost:8080/struts2/test/six1
1.先找struts.xml配置文件
2.在配置文件中找命名空间/test 注意:这个地方会按照层级去找
/a/b/c/six 查找机制
首先在/a/b/c/中找six
然后在/a/b/中找six
然后再/a/中找six
然后再/中找six
如果没有就报错
3.在命名空间中找action的six1
4.执行action中的方法
5.在配置文件中找result返回值
6.找到页面进行返回
Action细节
struts2的加载顺序
default.properties --> struts-default.xml --> struts.xml ---> *.xml
其它注意
每次访问action的内存地址都是会改变的
action是多例的
servlet,filter,listener是单例的
struts1中的action是单例的
请求参数封装
<form action="one" method="post">
<!-- 普通属性方式 -->
<input type="text" name="name"/>
<!-- 对象属性方式 -->
<input type="text" name="student.username">
<!-- ModelDriven方式 -->
<input type="text" name="username">
<input type="submit" />
</form>
属性方式
public class OneAction{
//普通属性方式
private String name;
//对象属性方式
private Student student;
public String execute() throws Exception {
return "success";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
对象方式
public class UserAction{
private Student student;
public String execute() throws Exception {
System.out.println("user-action");
System.out.println(student);
return "success";
}
public void setStudent(Student student){
this.student = student;
}
public Student getStudent(){
return this.student;
}
}
ModelDriven方式
public class UserAction implements ModelDriven<Student>{
private Student student = new Student();
public String execute() throws Exception {
System.out.println("user-action");
System.out.println(student);
return "success";
}
@Override
public Student getModel() {
return student;
}
}
通配符
与后边的{1}是对应关系
eight_* 中 {1}代表这个*
eight_*_* 中{2}代表第二个*
<action name="eight_*" class="com.shuai.struts2.action.EightAction" method="{1}">
<!-- 指代跟方法名相同的jsp页面 -->
<result>/{1}.jsp</result>
</action>
按模块拆分struts.xml
struts-article.xml
<package name="article" namespace="/article" extends="struts-default">
<action name="one" class="com.shuai.test.ArticleAction" method="execute">
<result name="success">/article.jsp</result>
</action>
</package>
struts-user.xml
<package name="user" namespace="/user" extends="struts-default">
<action name="one" class="com.shuai.test.UserAction" method="execute">
<result name="success">/user.jsp</result>
</action>
</package>
struts.xml
<struts>
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<include file="struts-user.xml"></include>
<include file="struts-article.xml"></include>
</struts>
访问Servlet API(Request/Session/Application)的方式
第一种方式
ActionContext context = ActionContext.getContext();
//保存到request域
Map<String,Object> request = (Map<String,Object>)context.get("request");
request.put("request_data", "request_data_message");
//保存到session域
Map<String,Object> session = (Map<String,Object>)context.get("session");
session.put("session_data", "session_data_message");
//保存到application域
Map<String,Object> application = (Map<String,Object>)context.get("application");
application.put("application_data", "application_data_message");
第二种方式-有耦合
//保存到request域
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("request_data", "request_data_message");
//保存到session域
HttpSession session = request.getSession();
session.setAttribute("session_data", "session_data_message");
//保存到application域
ServletContext context = ServletActionContext.getServletContext();
context.setAttribute("application_data", "application_data_message");
第三种方式
public class ElevenAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
private Map<String, Object> application;
private Map<String, Object> session;
private Map<String, Object> request;
@Override
public void setRequest(Map<String, Object> request) {
this.request = request;
}
@Override
public void setSession(Map<String, Object> session) {
this.session = session;
}
@Override
public void setApplication(Map<String, Object> application) {
this.application = application;
}
}
乱码问题
POST方式GBK编码
项目统一编码GBK
<constant name="struts.i18n.encoding" value="GBK"></constant>
POST方式UTF-8编码
项目统一编码UTF-8
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
POST方式其它
项目统一编码GBK
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
GET方法UTF-8编码
项目统一编码UTF-8
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
tomcat/conf/server.xml配置<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
常量修改
概述
在struts2-core 里面 的 org.apache.struts2包下来 default.properties 这里面有常量配置
修改
<constant name="struts.action.extension" value="action,do,go,,"></constant>
名称
struts.i18n.encoding=UTF-8
请求数据的中文处理 请求数据的编码 POST请求
struts.action.extension=action,,
访问后缀
struts.enable.DynamicMethodInvocation = true
是否开启动态方法调用,就是是否可以通过*号的方式来指代占位
http://localhost:8080/struts2/twelve1!insert 这种访问方式是否可以
struts.multipart.maxSize=2097152
文件上传大小的限制
默认是2M
struts.devMode = false
开发者模式,会显示更多的日志信息
struts.i18n.reload=false
就是改了配置文件是否需要重启服务
struts.ui.theme=xhtml
修改struts主题 ,一般都改为simple,就是jsp页面使用struts标签的时候,
页面展示的时候,生成是html页面是否有额外的东西。
result结果集的type类型11个类型
转发
<result name="success" type="dispatcher">/user.jsp</result>
重定向 - 外部资源
<result name="success" type="redirect">/one.jsp</result>
<result name="success" type="redirect">/user/one</result>
配置错误页面
某个Action下的错误页面
<action name="one" class="com.shuai.test.OneAction">
<result name="error">/error.jsp</result>
</action>
全局错误页面
<global-results>
<result name="error">error.jsp</result>
</global-results>
全局未抓取的异常配置
<global-exception-mappings>
<exception-mapping result="error" exception="java.lang.Exception"/>
</global-exception-mappings>
struts-tags 标签
需要导入taglib指令:
<%@taglib uri="/struts-tags" prefix="s"%>
标签分类
通用标签
数据标签
控制标签(默认前缀s)
UI标签
Ajax标签(默认前缀sx)
数据标签
提供对各种数据访的相关功能
<s:property>
输出值栈及Stack Context 中所有能访问的值
访问对象的属性
//value 是Action中的userName属性
<s:property value="userName"/>
//value 是Action中的user属性对象中的userName属性
<s:property value="user.userName"/>
Action的成员变量存储在值栈中
<s:property value="user.id"/>
访问List集合的一个元素
<s:property value="streetsList[0]"/>
访问List集合的第一个元素的属性
<s:property value="streetsList[0].streetName"/>
获取List集合的大小
<s:property value="streetsList.size()"/>
获取List集合是否为空
<s:property value="streetsList.isEmpty()"/>
<s:debug>
在页面上生成一个链接,单击这个链接可以
查看值栈及Stack Context 中所有能访问的值
<s:date>
格式化输出一个日期
<s:set>
对设置的表达式求值,并将结果赋给特定作用域的某个变量
<s:url>
生成一个URL 地址
<s:a>
生成HTML 的<a>标签
<s:param>
为其他标签添加参数化设置
<s:include>
把其他页面包含到当前的页面上
控制标签
用来完成流程控制,如分支流程、循环流程等
<s: if>/<s: elseif>/<s: else>
实现分支流程控制,它们的语意和Java中的if、else if、else相似
<s:iterator>
主要用于对集合实现循环访问功能
UI标签
用来生成UI界面及元素
<s:form>
对应HTML 中的<form>,用于向服务器端提交数据
<s:textfield>
对应HTML 中的<input type="text">,即单行文本框
<s:textarea>
对应HTML 中的<textarea>,即多行文本域
<s:submit>
对应HTML 中的<input type="submit">,即提交表单按钮
<s:select>
生成一个下拉框
<s:doubleselect >
生成两个联动的下拉框
<s:datetimepicker>
生成一个日历控件
interceptor拦截器(提供32个,默认执行18个)
概述
struts2是通过拦截器来完成功能的。
在struts-default.xml中定义了struts的所有拦截器 interceptors
使用拦截器 有一个拦截器栈 interceptor-stack
默认的栈是 <interceptor-stack name="defaultStack">
struts执行哪个拦截器栈
<default-interceptor-ref name="defaultStack"/>
拦截器与过滤器区别
过滤器
Filter 是servlet的概念
拦截所有的请求,jsp/servlet/html/css/js/image....
拦截器
interceptor 是struts2的概念
只拦截action请求
如果访问的是jsp就不会拦截。
自定义拦截器
步骤
1.创建类OneInterceptor implements Interceptor
2.实现 init/intercept/destroy方法
3.在package中配置
代码
public class OneInterceptor implements Interceptor {
private static final long serialVersionUID = 353192690805863911L;
@Override
public void destroy() {
System.out.println("拦截器销毁 destroy");
}
@Override
public void init() {
System.out.println("拦截器初始化");
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
System.out.println("拦截开始");
//放行,去到下一个拦截器,如果没有下一个拦截器 就执行action的方法
//一旦执行了invoke方法,就说明已经发生了资源跳转,再更改方法的返回值无效
String result = invocation.invoke();
System.out.println("拦截结束--invoke="+result);
return result;
}
}
配置
<package name="thirteen" extends="struts-default" >
<interceptors>
<!-- 自定义的拦截器 -->
<interceptor name="OneInterceptor" class="com.shuai.struts2.OneInterceptor"></interceptor>
<!-- 自定义拦截器栈 -->
<interceptor-stack name="mystatck">
<!-- 引入默认的拦截器栈 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 加入自己的拦截器 -->
<interceptor-ref name="OneInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 使用自己的拦截器栈 -->
<default-interceptor-ref name="mystatck"></default-interceptor-ref>
</package>
文件上传
单文件上传
public class OneAction extends ActionSupport {
private static final long serialVersionUID = -5407112650267208013L;
//单文件上传
private File file;
private String fileFileName;
private String fileContentType;
@Override
public String execute() throws Exception {
//自己打开输入流输出流把file写出到某个位置即可。
System.out.println("file="+file);
System.out.println("fileFileName="+fileFileName);
System.out.println("fileContentType="+fileContentType);
return SUCCESS;
}
}
多文件上传
public class OneAction extends ActionSupport {
private static final long serialVersionUID = -5407112650267208013L;
private File[] file;
private String[] fileFileName;
private String[] fileContentType;
@Override
public String execute() throws Exception {
for (int i = 0; i < file.length; i++) {
System.out.println("file[]=" + file[i]);
}
for (int i = 0; i < fileFileName.length; i++) {
System.out.println("fileFileName[]=" + fileFileName[i]);
}
for (int i = 0; i < fileContentType.length; i++) {
System.out.println("fileContentType[]=" + fileContentType[i]);
}
return SUCCESS;
}
}
配置文件
<action name="one" class="com.shuai.struts2.action.OneAction">
<interceptor-ref name="defaultStack">
<param name="fileUpload.allowedExtensions">txt,png,docx</param>
</interceptor-ref>
<result>/hello.jsp</result>
</action>
说明
限制允许上传的文件类型 只能上传这些中类型
<param name="fileUpload.allowedTypes">text/plain,image/png</param>
限制允许上传的文件扩展名(注意:如果与上面一起用取交集!)
<param name="fileUpload.allowedExtensions">txt,png,docx</param>
界面
<form action="one" method="post" enctype="multipart/form-data">
file:<input type="file" name="file"/><br/>
<input type="submit"/><br/>
</form>
文件下载
代码
public class OneAction extends ActionSupport {
private static final long serialVersionUID = -5407112650267208013L;
//2.需要下载的文件名
private String fileName;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
try {
fileName = new String(fileName.getBytes("ISO8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
this.fileName = fileName;
}
//1.下载方法
public String down() {
return "down"; // 注意:因为做下载功能,返回的结果类型是“stream”
}
// 4.返回流
public InputStream getFileStream(){
File file = new File("D:\\download",this.fileName);
FileInputStream inputStream=null;
try {
inputStream = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println("inputStream="+inputStream);
return inputStream;
}
// 5.浏览器显示的文件名
public String getDownFile(){
try {
return URLEncoder.encode(fileName, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
配置文件
<action name="one_*" class="com.shuai.struts2.action.OneAction" method="{1}">
<result>/hello.jsp</result>
<!-- 3.下载操作 -->
<result name="down" type="stream">
<!-- 文件的类型,指定为任意二进制类型,可以标识任何文件 任何类型的文件 -->
<param name="contentType">application/octet-stream</param>
<!-- 对应的是Action类中返回流的属性! 注意:这个fileStream是action中的getFileStream方法 -->
<param name="inputName">fileStream</param>
<!-- 指定浏览器显示的文件名,对应action类中的返回文件名的属性! 需要url编码 注意:这个downFile是action中的getDownFile方法-->
<param name="contentDisposition">attachment;filename=${downFile}</param>
<!-- 读取缓冲区大小 -->
<param name="bufferSize">1024</param>
</result>
</action>
OGNL表达式
概述
Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。
Struts2框架使用OGNL作为默认的表达式语言。
作用
页面取值!必须配置struts2标签!
页面取值方式:
1.jsp的EL表达式
2.Struts2的Ognl表达式
使用
引入struts的jar包,必须引入ognl.jar
OGNL优势
1、支持对象方法调用,如xxx.doSomeSpecial();
2、支持类静态的方法调用和值访问,表达式的格式:
@[类全名(包括包路径)]@[方法名|值名],例如:
@java.lang.String@format('foo %s', 'bar')
或@tutorial.MyConstant@APP_NAME;
3、支持赋值操作和表达式串联,如price=100, discount=0.8,
calculatePrice(),这个表达式会返回80;
4、访问OGNL上下文(OGNL context)和ActionContext;
5、操作集合对象。
其它
OGNL 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了 java.utils.Map 的接口。
Ognl的核心是OgnlContext对象
代码
OgnlContext是一个Map
//创建对象
OgnlContext context = new OgnlContext();
//赋值
context.put("china", "中国");
//取值
System.out.println(context.get("china"));
往根元素设置值
User user = new User(100);
//创建对象
OgnlContext context = new OgnlContext();
//赋值
context.setRoot(user);
//解析
Object ognl = Ognl.parseExpression("id");
Object value = Ognl.getValue(ognl, context,context.getRoot());
System.out.println(value);
往非根元素设置值, ognl表达式取值时候,需要带#符号
User user = new User(200);
//创建对象
OgnlContext context = new OgnlContext();
//赋值
context.put("user",user);
//解析
Object ognl = Ognl.parseExpression("#user.id");
Object value = Ognl.getValue(ognl, context,context.getRoot());
System.out.println(value);
总结
根元素取值
<s:property value = "id">
非根元素取值
<s:property value = "#user.name">
ognl表达式取值,如果是根元素取值不用带#符号, 非根元素取值要带#号!
ValueStack
概述
ValueStack实际是一个接口
在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类
这个类是Struts2利用OGNL的基础。
特点
ValueStack贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个ValueStack 对象).
相当于一个数据的中转站. 在其中保存当前Action 对象和其他相关对象.
Struts2框架把 ValueStack 对象保存在名为 “struts.valueStack” 的request请求属性中。
ValueStack vs1 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
存储集合
ValueStack存储对象
ObjectStack: Struts 把动作和相关对象压入 ObjectStack 中--List
ContextMap:
Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中
Struts 会把下面这些映射压入 ContextMap 中
parameters: 该 Map 中包含当前请求的请求参数
request: 该 Map 中包含当前 request 对象中的所有属性
session: 该 Map 中包含当前 session 对象中的所有属性
application:该 Map 中包含当前 application 对象中的所有属性
attr: 该 Map 按如下顺序来检索某个属性: request, session, application
值栈数据存储原理
Struts每次访问action的时候
1. 创建一个ActionContext对象
2. 创建值栈对象
把域中存放的数据、以及Action对象,放到值栈中!
这时候,值栈就有了struts运行时期的数据!
3. 把值栈的数据,拷贝一份给ActionContext!
4. 最后,把值栈放到request的请求中!
验证
其它
1.请求数据自动封装
2.数据处理
3.拦截器、自定义拦截器
4.文件上传下载
5.Ognl表达式与struts标签
6.数据校验
7.类型转换
8.国际化
9.模型驱动