2017.2.2-2017.2.6
Struts2介绍
- Struts2框架是基于MVC模式的开源Java EE框架,使用可以对使用Java EE技术的web项目开发进行代码的分层,优点是有利于维护。
- 它是WebWork框架和Struts1框架的基础上综合开发出来的产物,但Struts2的核心代码主要来自WebWork框架。
- Struts2的优点主要体现在解耦上,其他的附属技术也比Struts1有所加强,使用上更加快捷方便,比如简化了配置文件的代码。
- 在网站http://struts.apache.org/上可以找到其全部相关资料。
下载最新版的zip文件struts-2.5.8-all
其中apps是Struts2的demo示例项目,docs是开发文档及使用手册,lib是jar,src则是Struts2框架的源代码。
必要的jar文件
第一个项目
版本2.3.24,参考Struts/apps文件夹下的项目
- 引入jar包,在apps文件夹下找
创建action
package action; /* * (1)每次访问servlet的时候,都会执行service方法 * -写类继承HttpServlet,重写类里面的方法 * -在web.xml中配置servlet访问路径 * * (2)访问action,每次访问action的时候,默认执行execute方法 * -配置action方法 */ public class hello { public String execute(){ return "ok"; } }
配置action类访问路径
(1)创建Struts2核心配置文件<br> -核心配置文件名称(struts.xml)和位置(src/)是固定的<br> -引入dtd约束 <package name="default" namespace="/" extends="struts-default"> <!-- name:访问名城 --> <action name="hello" class="action.hello"> <!-- 配置方法的返回页面 --> <result name="ok">/ok.jsp</result> </action> </package>
配置struts2过滤器
<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>
访问路径
http:localhost/struts(项目名)/hello(action名)
struts执行过程
过滤器是在服务区启动时创建,创建过滤器时执行init方法。
init方法主要加载配置文件(自带的和手工创建的web.xml和struts.xml)
struts.xml里的package标签
<package name="default" namespace="/" extends="struts-default">
<!-- name:访问名城 -->
<action name="hello" class="action.hello">
<!-- 配置方法的返回页面 -->
<result name="ok">/ok.jsp</result>
</action>
</package>
为了区分不同的action,要配置action,必须首先写package标签,在package里面才能配置action。
(1)name属性
在一个配置文件中可以写多个package标签,name属性值不能相同
(2)extends属性
属性值是固定的,”struts-default”,写了这个属性之后,在package里面配置的类才具有action功能
(3)namespace属性
namespace属性值和action标签里面的name属性值构成访问路径,默认为”/”
action标签
action配置action访问路径
(1)name属性
namespace属性值和action标签里的name属性值构成访问路径,在package里面可以配置多个action标签,但是action的name属性值不能相同。
(2)class属性
action全路径
(3)method属性
让action里面多个方法执行,使用method进行配置。
result标签
根据action的方法返回值,配置到不同的路径里面
(1)name属性
和action方法的返回值一样
(2)type属性
配置如何到路径中(转发或者重定向),默认为转发(地址栏不改变)。
修改Struts2默认常量值
在struts.xml中进行配置
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
还有两种方式(了解)
- 在src下面创建struts.properties,进行修改
- 在web.xml进行配置
最常用常量
struts.i18n.encoding=UTF-8
表单提交数据有中文乱码问题
-post提交直接设置编码
-get提交做编码转换
如果在action获取表单通过post方式提交中文,中文乱码问题系统会自动解决
分模块开发
单独写配置文件,把配置文件引入到核心配置文件中
<include file="cn/zcw/action/hello.xml"></include>
Action编写方式(3种)
- 创建普通类,这个不继承任何类,不实现任何接口
- 创建类,实现接口Action
- 创建类,继承类ActionSupport
*访问action的方法(3种)
- 使用action标签的method属性,在这个属性里面写执行action的方法
使用通配符方式实现
<action name="a*" class="......" method="{1}"></action>
- 动态访问实现(不用)
在action里面的方法有返回值,如果返回值的类型必须是String,
如果action里面的方法可以没有返回值,这时候result标签不需要配置。
(1)把返回类型设置为void。(2)返回“none”
全局结果页面
应用场景:当有多个action方法的返回值相同且到达的页面也是相同。
<package name="default" namespace="/" extends="struts-default">
<global-results>
<result name="ok">/ok.jsp</result>
</global-results>
<!-- name:访问名称 -->
<action name="hello" class="action.hello">
<!-- 配置方法的返回页面 -->
<!-- <result name="ok">/ok.jsp</result> -->
</action>
</package>
局部结果页面
<action name="hello" class="action.hello">
<!-- 配置方法的返回页面 -->
<!-- <result name="ok">/ok.jsp</result> -->
</action>
优先级:全局结果页面 < 局部结果页面
result标签的type属性
- dispatcher,转发(默认),地址栏不变
- redirect,重定向,地址栏改变
chain,转发到action,存在缓存问题,一般不使用
<--! list为action的name值 --> <result name="success" type="chain">list</result>
redirectAction,重定向到action
<result name="success" type="redirectAction">list</result>
action获取表单提交数据
使用ActionContext类(官方推荐)
首先提交form表单,action值为访问action的路径。 action类核心代码: //1.获得ActionContext对象 ActionContext context=ActionContext.getContext(); //2.调用方法得到表单数据,value是输入的值 Map<String, Object> params = context.getParameters(); Set<String> keys=params.keySet(); for (String key : keys) { //根据key得到value //返回数组形式,因为输入项中可能有复选框的情况 Object[] obj=(Object[]) params.get(key); System.out.println(Arrays.toString(obj)); }
使用ServletActionContext类
核心代码: //通过ServletActionContext类得到request对象 HttpServletRequest request=ServletActionContext.getRequest(); String username=request.getParameter("username"); String password=request.getParameter("password"); System.out.println(username+":"+password);
- 使用接口注入方式(了解即可)
action中操作域对象(3个)
//1.request域
HttpServletRequest request=ServletActionContext.getRequest();
//2.session域
HttpSession session=request.getSession();
//3.ServletContext域
ServletContext context=request.getServletContext();
Struts2封装获取表单数据方式
属性封装
在action中声明与表单name一样的成员变量并且实现其的set方法。但不能把数据直接封装到实体类对象里面
模型驱动封装(重点)
使用模型驱动可以直接将表单数据封装到实体类对象里 1.action实现接口ModelDriven 2.在action中创建实体类对象 3.实现接口里面的getModel方法,返回创建的对象
表达式封装(会用)
1、声明实体类 public User user; 2、生成实体类变量的get、set方法 3、将表单的name写成对象属性形式,如: <input type="text" name="user.username"/>
不能同时用属性封装和模型驱动封装获取同意表单数据,如果同时使用则默认执行模型驱动封装。
比较表达式封装和模型驱动封装
相同点:两个都可以讲数据封装到实体类对象里面
不同点:模型驱动只能把数据封装到一个实体类对象里面,表达式封装可以把数据封装到不同的实体类对象里面
封装数据到List
1、声明List变量
private List<User> list;
2、生成List的get、set方法
3、在表单输入项里面写表达式
<input type="text" name="list[0].username"/>
封装数据到Map
1、声明Map集合
private Map<String,User> map;
2、生成get、set方法
3、在页面里写表达式
<input type="text" name="map['one'].username"/>
......
<input type="text" name="map['abc'].username"/>
ognl配合struts2使用
实例:输出字符串长度
1.引入ognl的jar包
2.引入标签 <%@ taglib uri="/struts-tags" prefix="s"%>
3.配合Struts标签使用<s:property value="'abc'.length()"/>
什么是值栈
值栈是struts2里面提供的一种存储机制,类似于域对象,可以存值和取值。在action里面把数据放到值栈里,在页面中获取值栈数据。
Servlet和action的区别
Servlet:默认第一次访问时创建,只创建一次,单实例对象
action:访问时创建,每次访问时都会创建action对象,多实例对象
值栈存储位置
每个action对象里面都有一个值栈对象(只有一个)
获取值栈对象
常用方式:
//1、获取ActionContext类的对象
ActionContext context=ActionContext.getContext();
//2、调用方法得到值栈对象
ValueStack stack=context.getValueStack();
值栈内部结构
- 第一部分root,结构为list集合。一般都是操作root里面数据
- 第二部分context,结构为map集合
向值栈中放入数据
- 获取值栈对象,调用其的set方法
- 获取值栈对象,调用其的push方法
- 在action中设置变量属性,实现其get方法
获取值栈的字符串
应用设置action对象属性(如username)的方法向值栈中添加数据,在页面中使用struts2和ongl表达式显示结果:
<s:property value="username"/>
从值栈中获取对象
<S:property vlaue="user.username"/>
从值栈中获取list(3种)
1.<s:property value="list[0].username"/>
2.
<s:iterator value="list">
<s:property value="username"/>
</S:iterator>
3.
<s:iterator value="list" var="user">
<s:property value="#user.username"/>
</S:iterator>
获取set方式的值
在action中使用:stack.set("name","zcw");
在页面中获取:<s:property value="name"/>
获取push设置的值
<s:property value="[0].top"/>
为什么EL表达式可以获取值栈中的数据
EL表达式用于获取域对象的值,首先从request域获取值,如果获取到直接返回;
如果获取不到,则从值栈中把值获取出来,把值放到域对象里面。
ognl中#、%
使用ognl获取request域中的值,首先加上#,再写context的key名称,最后写域对象名称。
action类:
request.setAttribute("req","hello");
页面:
<s:property value="#request.req"/>
在struts2标签里面使用ognl表达式,如果直接在struts2表单标签里面使用ognl表达式不识别,只用%之后才会识别。
<s:textfield name="name" value="%{#request.req}"></s:textfield>
struts2拦截器介绍
1.struts2是框架,封装了很多的功能,struts2里面封装的功能都是在拦截器里面
2.struts2里面封装了很多的功能,有很多拦截器,不是每次这些拦截器都执行,每次只执行默认的拦截器。
3.执行时间:在action对象创建之后,在action的方法执行之前。
拦截器底层思想
aop思想
AOP切面模式编程,不修改源代码即可增加功能。
责任链模式
要执行多个操作,有添加、修改、删除三个操作。 首先执行添加操作,添加操作执行后,做类似于放行操作,执行修改操作,修改操作执行之后做类似放行操作,执行删除操作。 过滤链:一个请求有多个过滤器进行过滤,每个过滤器只有做放行才能到下一个过滤器。
过滤器和拦截器的区别
(1)过滤器:过滤器理论上可以过滤任意内容,比如html、jsp、servlet、图片路径
(2)拦截器:拦截器只可以拦截action
拦截器实现过程
- 第一步 创建类,继承MethodFilterInterceptor类,实现重写其doInterceptor方法
第二步 重写MethodFilterInterceptor类里面的方法写拦截器逻辑
package intercept; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; public class demo extends MethodFilterInterceptor{ protected String doIntercept(ActionInvocation invocation) throws Exception { HttpServletRequest request=ServletActionContext.getRequest(); Object username=request.getSession().getAttribute("username"); if(username!=null){ //类似于放行操作,执行action方法 return invocation.invoke(); } else{ //达到login的访问路径 return "login"; } } }
第三步 配置action和拦截器关系(注册拦截器)
在要拦截的action标签所在的package标签里面声明拦截器
<!-- 声明拦截器 --> <interceptors> <interceptor name="logininterceptor" class="cn.zcw.interceptor.Login"> </interceptor>
在具体的action标签里面使用声明的拦截器
struts2里面执行很多的默认拦截器。但是如果在action里面配置自定义拦截器,默认的拦截器就不会执行了。解决办法:把默认拦截器手动使用一次
配置拦截器,对action里面所有的方法都进行拦截
要使某个方法不被拦截器拦截,需要配置
<interceptor-ref name="logininterceptor">
<--! 不被拦截的方法用逗号隔开 -->
<param name="excludeMethods">login</param>
</interceptor-ref>
struts2标签库
struts2标签只能在JSP页面中使用
- s:property:和ognl表达式在JSP页面中获取值栈数据
- s:iterator:获取值栈list集合数据,表示list集合
- s:debug:查看值栈结构和数据
struts2表单标签(会用)
<s:form>
<!-- 普通输入项 -->
<s:textfield name="username" label="name"></s:textfield>
<!-- 密码输入项 -->
<s:password name="password" label="password"></s:password>
<!-- 单选输入项 -->
<!-- value属性值和显示的一样 -->
<s:radio list="{'女','男'}" name="sex" lable="性别"></s:radio>
<!-- value属性值和显示的不一样 -->
<s:radio list="#{'nv':'女','nan':'男' }" name="sex1" label="性别"></s:radio>
<!-- 复选输入框 -->
<s:checkboxlist list="{'乒乓球','打代码'}" name="hobby" label="爱好"></s:checkboxlist>
<!-- 下拉输入框 -->
<s:select list="{'中学','高中','大学'}" name="level" label="受教育水平"></s:select>
<!-- 文件上传 -->
<s:file name="file" label="文件上传"></s:file>
<!-- 文本域 -->
<s:textarea rows="10" cols="6" name="resume" label="简历"></s:textarea>
<!-- 提交按钮 -->
<s:submit value="提交"></s:submit>
<!-- 重置 -->
<s:reset value="重置"></s:reset>
</s:form>