Struts2入门
1 Struts2简介
Struts2就是基于MVC模式的开发框架,对servlet技术的封装!!!!
1)核心原理:编写核心控制器类ActionServlet。对不同的请求加以区分,进行不同的处理。
2) struts2的具体功能:请求数据封装、简化国际化、简化文件上传、后台数据校验......
3) struts2框架的作用
strurs2是基于MVC开发模型的web层框架。
struts1也是MVC开发模式的框架。struts2并不是struts1的升级版。
struts2是基于webwork的升级版。struts2=webwork+sturts1
2 Struts2的使用
2.1 使用步骤
1)导入strust2的支持jar包
commons-beautils [beanutils工具包]
commons-filupload.ajr [文件上传]
commons-io.jar
commons-lang [struts2对java.lang.*类的支持]
freemarker.jar [视图显示技术]
javassit [struts2对字节码运算的支持]
ognl.jar [struts2对ognl表达式的支持]
struts2-core.jar [ struts2的核心包 ]
xwork-core.jar [webwork框架的支持,struts2的前身就是webwork(对webwork的封装)]
2)配置启动的全局的过滤器(Filter) - 和ActionServlet类似!!!
在web.xml中配置
<!-- 配置启动strut2的全局过滤器 --> <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> |
3)编写不同的业务Action类,编写不同业务方法。默认execute方法。
public class LoginAction implements Action{ //默认方法 public String execute() throws Exception { System.out.println("执行了LoginAction的execute方法"); return "success"; } } |
4)在src目录下(类路径的根目录下),新建一个struts.xml,配置Action对象
<struts> <package name="xxx" extends="struts-default"> <!-- 配置Action http://localhost:8080/day28_struts/login.action--> <action name="login" class="gz.itcast.action.LoginAction"> <result name="success" type="redirect">/index.jsp</result> </action> </package> </struts> |
5)访问Action的业务方法
http://localhost:8080/day28_struts/login.action
2.2 Struts2的执行过程
项目启动:
1)创建核心过滤器StrutsPrepareAndExecuteFilter对象
2)执行核心过滤器的init方法
读取了依次以下的配置:
struts-default.xml [struts2框架的默认配置文件(不需要自定修改)]
struts-plugin.xml [struts2的插件配置文件]
struts.xml [我们写的业务配置文件(包含配置的Action)]
访问资源:
3) 在内存中查询对应的Action配置,得到class内容,创建Action对象。
4)读取Action配置的method内容,执行Action对象对应的方法。
2.3 struts-default.xml文件的详解
1)声明struts2框架运行过程中使用到的一些对象
<bean class="com.opensymphony.xwork2.ObjectFactory" name="xwork" /> |
2)默认包,包名叫struts-default(注意:我们自己写的package必须继承这个默认包,只有继承了这个默认包才可以使用该默认包下的功能)
<package name="struts-default" abstract="true"> |
2.1)跳转类型:
常用的跳转类型
redirect: 重定向到页面
dispatcher: 转发到页面
redirectAction: 重定向到Action
chain: 转发到Action
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/> |
2.2 ) 声明拦截器(Interceptor)
struts2默认的拦截器(32个): 完成strutrs2的核心功能。(请求封装,文件上传,国际化..)
拦截器(Intercptor) vs 过滤器(Filter)
过滤器: 可以过滤任何类型的请求(html、servlet、jsp)和响应。加入通用的代码逻辑。
拦截器: 是sturts2的特有功能。只能过滤Action!!在执行Action的时候加入通用的代码。
2.3) 声明拦截器栈 (<interceptor-stack name="basicStack">)
默认拦截器:
<interceptor-stack name="defaultStack"> (18个拦截器) |
2.4 ) 默认包当前使用的拦截器:
<default-interceptor-ref name="defaultStack"/> |
注意:
我们写的包(package)就是继承struts-default默认包的,那么就继承了默认的18个拦截器
2.5) 当前默认包下的默认Action
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" /> |
2.4 struts.xml文件详解
该文件是开发者自行配置的业务配置文件。(关键是Action的配置)
1)包(package),用于管理Action,一般可以按模块划分包!!
package: 代表一个包。管理action配置。在用一个包下面不能有同名的action name: 包名.在一个项目中不能出现同名的包。 extends: 继承。类似于类的继承。如果一个包继承另一个包,那么就会把父包的功能继承下来。 我们开发的包就必须继承struts-default包。 namespace: 名称空间。区分不同的包的访问路径。默认值 “/” 用户访问Action的路径搜索规则: http://localhsot:8080/day28/namespace/action的name namespace="/user" http://localhost:8080/day28_struts/user/a/login2.action ok http://localhost:8080/day28_struts/user/login2.action ok http://localhost:8080/day28_struts/a/user/login2.action 不行!!
用户访问: http://localhost:8080/day28_struts/user/a/b/login2.action 先搜索: http://localhost:8080/day28_struts/user/a/b/login2.action 没有, 有就返回 接着搜索: http://localhost:8080/day28_struts/user/a/login2.action 没有, 有就返回 再搜索 : http://localhost:8080/day28_struts/user/login2.action 有, 有就返回(为止)
abstract: 表示当前包是否抽象。如果当前包是抽象包,那么不能含有action. 抽象包中一般用来定义拦截器,公共视图,不做具体的业务。 |
2)Action和result的配置
action配置: name: action的名称。用于访问该Action的路径 class: Action业务对象的类名。一定是全名(包名+类名),这里struts2是用反射构造Action对象的 method: 执行的业务方法。默认:execute result配置: name: 视图的标记。在一个Action中名称不要重复!默认: success type: 跳转的类型。 redirect: 重定向 dispatcher: 转发(默认值) redirectAction: 重定向到Action chain: 转发到Action。可以在不同Action中通过request共享数据 stream: 用在下载文件的时候。 文本内容: 跳转到的页面或者Action |
3)可以通过划分不同的xml文件来管理package
<!-- 包含读取其他xml文件 注意: 声明的顺序就是读取的顺序!!!!--> <include file="config/struts-book.xml"></include> <include file="config/struts-user.xml"></include> |
3 struts2的Action三种使用方式
1)第一种方式,不实现Action接口
// 第一种方式:不需要实现或继承任何接口或类 public class UserAction2 { public String login()throws Exception{ System.out.println("UserAction2.login()"); return "success"; } } |
2)第二种方式,实现Action接口
/** 第二种方式:实现Action接口 * 1)定义了默认的execute方法的标准 * 2)提供了项目中常用的视图标记 */ public class UserAction implements Action { public String login() throws Exception { System.out.println("执行了UserAction的login方法"); return SUCCESS; } public String execute() throws Exception { return null; } } |
3)第三种方式,继承ActionSupport类(推荐)
/** 第三种方式: 继承ActionSupport类(推荐使用) * 好处: * 1)提供了常用的视图标记 * 2)提供了数据校验功能 */ public class UserAction3 extends ActionSupport{ public String login()throws Exception{ System.out.println("UserAction3.login()"); return SUCCESS; } } |
4 路径通配符
<!-- 一个模块(Action对象)使用一个action配置 --> <!-- * (星号) :表示路径的通配符。 使用通配符的内容:{1}(表示获取第一个通配符的实际内容) 好处: 大大地减少action的配置 --> <!-- <action name="user_*" class="gz.itcast.b_path.UserAction" method="{1}"> <result name="{1}">/{1}.jsp</result> </action> -->
<!-- 多个模块使用一个action配置 约定前提: 第一个*代表模块(Action),第二个代表方法 ser_login --> <action name="*_*" class="gz.itcast.b_path.{1}Action" method="{2}"> <result name="{2}">/{1}/{2}.jsp</result> </action> |
5 strus2的常量配置
struts2的常量就是用于在strut2的程序运行过程中使用的一些常量参数。
注意:
通过struts.xml文件声明<constant name="struts.action.extension" value="action,do,,"></constant>修改常量配置。
指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的输出 <constant name="struts.i18n.encoding" value="UTF-8"/> 自定义后缀修改常量 <constant name="struts.action.extension" value="action,do,,"/> 设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭 <constant name="struts.serve.static.browserCache" value="false"/> 当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开 <constant name="struts.configuration.xml.reload" value="true"/> 开发模式下使用,这样可以打印出更详细的错误信息 <constant name="struts.devMode" value="true" /> 默认的视图主题 <constant name="struts.ui.theme" value="simple" /> 与spring集成时,指定由spring负责action对象的创建 <constant name="struts.objectFactory" value="spring" /> 该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为false 注意: 如果打开动态方法调用,那么该Action对象下的所有方法都会对外暴露。存在一定安全隐患,所以通常把它关闭调用 <constant name="struts.enable.DynamicMethodInvocation" value="false"/> 上传文件的大小限制 <constant name="struts.multipart.maxSize" value=“10701096"/> 修改临时文件存放的目录 <constant name="struts.multipart.saveDir" value="e:/temps/"></constant> |
6 struts2的全局视图配置和默认配置
1)全局视图作用: 当该包下的所有action都使用到的一些视图就是可以放到全局视图配置中
注意:
当action中也有相同名称的视图,那么action的局部视图会覆盖全局视图。
<!-- 全局视图配置: 把该包下的所有action共用的视图都机集中在这里写 --> <global-results> <result name="success">/login.jsp</result> </global-results> |
2)action的默认配置
<!-- 默认配置 name: 必填项 class: 可选项 。默认配置: ActionSupport类 该类继承自struts-default (<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />) method: 可选。默认配置 result: name: 可选。默认配置: success type: 可选。默认配置: dispatcher --> <!-- 全部使用默认配置的action的作用 :专门用于转发到WEB-INF下的页面 --> <action name="book"> <result>/WEB-INF/jsp/login.jsp</result> </action> |
7 Action的属性注入
作用: 如果Action对象中需要把一些经常改变的参数提取到配置文件中,那么就可以使用属性注入的方法。(相当于读取配置文件)
Action属性注入的步骤
1)在Action类中声明一个成员变量,用于接收xml配置文件传入内容
2)在Action类提供一个该变量的setter方法,该方法接收了xml配置的内容
//1)在action中提供一个属性 private String savePath; //2)提供属性的setter方法,用于外部的action的参数进行注入 public void setSavePath(String savePath) { this.savePath = savePath; } |
3)在对应的struts.xml文件中,找到对应的action对象的配置,然后在action中使用
<param name=""></param> 这个标签来向Action对象的属性注入内容
<action name="upload" class="gz.itcast.d_ioc.UploadAction" method="upload"> <!-- 3)使用该配置可以往Action对象的属性注入内容(只要有setter都可以使用param进行注入) param:name: setter方法名。(setSavePath -> savePath) --> <param name="savePath">e:/images/</param> <result>/login.jsp</result> </action> |
(8以后都是Struts2中Action的使用)
8 sruts2的数据共享的三种方式
在web项目中都是使用域对象来共享数据。
struts2提供给开发者使用域对象来共享数据的方法一共有三种。
8.1 第一种方式
ServletActionContext类(静态方法)
getRequest() : 获取request对象
getRequest().getSession() : 获取session对象
getServletContext() : 获取ServletContext对象
注意:
1)该方式依赖servlet的api,耦合比较高
2)如果要通过域对象来获取域对象的相关信息必须使用该方式
8.2 第二种方式
ActionContext类
ActionContext.getContext().getContextMap() : 获取操作request域对象数据的map集合
ActionContext.getContext().getSession() : 获取操作session域对象数据的map集合
ActionContext.getContext().getApplication() 获取操作context域对象数据的map集合
注意:
1)不依赖servlet的api,耦合性低
2)只能用在Action对象的一个方法中。不能在所有方法中都是用同一个ActionContext
3) 当Action对象的方法比较少的时候使用,一般测试用
8.3 第三种方式
使用 RequestAware , SessionAware ApplicationAware 接口
注入操作对应域对象数据的Map集合
注意:
1)不依赖servlet的api
2)可以在Action对象的所有方法中共享Map集合
3) 当Action对象的方法比较多的时候使用
9请求参数数据的封装
9.1 直接赋值给简单数据类型
public class UserAction extends ActionSupport{ //参数赋值(注入方式) private String name; private String password; private String gender; private String[] hobit; //参数通过这个set方法注入到Action中 public void setName(String name) { this.name = name; } public void setPassword(String password) { this.password = password; } public void setGender(String gender) { this.gender = gender; } public void setHobit(String[] hobit) { this.hobit = hobit; } |
9.2 赋值给一个javabean对象
<form action="${pageContext.request.contextPath }/data/user_register.action" method="post"> 用户名: <input type="text" name="user.name"/><br/> 密码: <input type="password" name="user.password"/><br/> 性别: <input type="radio" name="user.gender" value="男"/>男 <input type="radio" name="user.gender" value="女"/>女<br/> 爱好: <input type="checkbox" name="user.hobit" value="篮球"/>篮球 <input type="checkbox" name="user.hobit" value="足球"/>足球 <input type="checkbox" name="user.hobit" value="羽毛球"/>羽毛球<br/> <input type="submit" value="注册"/> </form> |
public class UserAction2 extends ActionSupport{ //使用一个javabean对象接收 private User user; public User getUser() {return user;} public void setUser(User user) {this.user = user;} |
注意:请求参数的封装通过struts2的ParametersInterceptor拦截器进行赋值
10 自定义类型转换
作用: 默认情况下,页面的日期类型只能接收 yyyy-MM-dd类型,如果要转换yyyy/MM/dd这种类型,则需要使用自定义类型转换器进行转换。
strut2提供了自定义类型转换器的基类: StrutsTypeConverter类
// 自定义日期类型转换器 public class MyDateConverter extends StrutsTypeConverter{ SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy/MM/dd"); /** * 从页面的数据到服务器的类型转换 * 参数一: context: 值栈上下文对象 * 参数二: values: 从页面传递过来的参数值 * 参数三: toClass: 转换到的类型。String->java.util.Date */ @Override public Object convertFromString(Map context, String[] values, Class toClass) { System.out.println("进入了转换器"); try { //1)判断values是否为空 if(values==null || values.length==0){return null;} if(values.length>1){ //多个值的情况 Date[] dates = new Date[values.length]; //2)取出数据进行转换 for(int i=0;i<dates.length;i++){ Date date = sdf1.parse(values[i]); dates[i] = date; } return dates; }else{ //一个值的情况 Date date = sdf1.parse(values[0]); return date; } } catch (ParseException e) { e.printStackTrace(); } return null; } //从服务器到页面的类型转换(上面相反,用于从服JavaBean转换成String向页面输出) @Override public String convertToString(Map context, Object o) { return null; } } |
绑定自定义转换器的方式:
方式一: 局部绑定(只能绑定一个Action)
1)建立一个 Action的文件名-conversion.properties
2)一定和绑定的Action放在同一个目录下。
注意:转换器绑定到具体的属性。
user.birth=gz.itcast.g_convert.MyDateConverter |
方式二: 全局绑定(绑定整个项目多个Action)(推荐使用)
1)建立一个xwork-conversion.properties
2)该文件一定放在src目录下。
注意:该方法,只要转换目标是ava.util.Date,都会使用该转换器(覆盖原来的转换器)
java.util.Date=gz.itcast.g_convert.MyDateConverter |
11文件上传和下载
11.1 文件上传
1)三个条件:
表单有file
post提交
enctype="multipart/form-data"
2)在Action中接收文件内容
File attach; (attach是file表单的name属性)
String attachContentType; 文件类型
String attachFileName; 文件名称
细节:
1)修改上传大小
修改默认文件上传大小 <constant name="struts.multipart.maxSize" value="100000000"></constant> 修改临时文件存放的目录 <constant name="struts.multipart.saveDir" value="e:/temps/"></constant> |
2)修改允许上传的文件类型和文件后缀
<action name="upload" class="gz.itcast.h_upload_down.UploadAction" > <!-- 往FileUploadInterceptor拦截器的属性注入值(调用setter方法) --> <interceptor-ref name="defaultStack"> <!-- 改变当前文件上传拦截器的允许文件类型 --> <param name="fileUpload.allowedTypes">image/jpeg,image/jpg</param> <!-- 允许的文件后缀 --> <param name="fileUpload.allowedExtensions">jpg,jpeg,gif</param> <!-- 如果以上配置都写了,那么取他们的交集 --> </interceptor-ref> </action> |
11.2 文件下载
视图类型一定是stream类型
<action name="down_*" class="gz.itcast.h_upload_down.DownAction" method="{1}"> <!-- 文件下载的关键: 视图类型一定是stream --> <result name="down" type="stream"> <!-- 往StreamResult类中的属性注入内容 --> <!-- 返回给浏览器的文件类型。返回通用的二进制 --> <param name="contentType">application/octet-stream</param> <!-- 返回给浏览器的输入流 --> <param name="inputName">inputStream</param> <!-- 告诉浏览器的方式下载资源。${name}: 获取Action中的getName()方法的数据--> <param name="contentDisposition">attachment;filename=${name}</param> <!-- 缓存大小 --> <param name="bufferSize">1024</param> </result> </action> |
在Action对象中提供一个对应的获取输入流的方法
//需要提供给struts写出数据的输入流 public InputStream getInputStream(){ FileInputStream fis = new FileInputStream(new File(serverPath+name)); return fis; } |