Struts四
一,拦截器
1.概述
1.1什么是拦截器
在struts2中,拦截器(Interceptor)是用来动态拦截Action执行的对象。
拦截器有点类似以前Servlet阶段的Filter(过滤器) , 能够在请求到达Action之前进行拦截操作, 可以在里面进行判断校验。 典型的例子: 登录拦截.
注:过滤器可以过滤servlet,jsp,html Action, 但拦截器只能拦截Action
拦截器说白了就是struts2里面定义的一个类, 在到达Action之前执行. 目的: 在到达Action之前扩展功能( eg: 模型驱动, 属性驱动…方便开发)
1.2 struts2执行流程
客户端请求Action,执行前端控制器,在前端控制器内部创建了Action的代理类,调用代理类的execute方法,在execute方法内部执行ActionInvocation的invoke方法。在invoke方法内部递归调用拦截器的拦截的方法。如果没有下一个拦截器执行目标Action,Action执行结束后根据Result进行页面跳转,执行拦截器的后面相应的代码,最后由response对象生成响应。
-
流程图
-
时序图
2.自定义拦截器
2.1方式一:实现Interceptor接口
最原始的方式,也是最基本的方式. 要实现三个方法,其中init 和 destroy ,平常我们都不太用。
-
创建一个类实现Interceptor接口
public class Interceptor01 implements Interceptor { @Override public String intercept(ActionInvocation invocation) throws Exception { System.out.println("Interceptor01 执行了..."); //放行 invocation.invoke(); return null; } @Override public void destroy() { } @Override public void init() { } }
-
在struts.xml里面声明拦截器
<package name="test" extends="struts-default" namespace="/"> <!-- 声明拦截器 --> <interceptors> <interceptor name="interceptor01" class="com.itheima.web.interceptor.Interceptor01"> </interceptor> </interceptors> </package>
-
在action里面使用拦截器
<action name="demo_*" class="com.itheima.web.action.ActionDemo" method="{1}"> <interceptor-ref name="interceptor01"></interceptor-ref> </action>
2.2方式二:继承AbstractInterceptor
是Interceptor的一个子类, 只需要重写intercept()方法.
-
创建一个类继承AbstractInterceptor
public class Interceptor02 extends AbstractInterceptor { @Override public String intercept(ActionInvocation invocation) throws Exception { System.out.println("Interceptor01 执行了..."); //放行 invocation.invoke(); return null; } }
-
在struts.xml里面声明拦截器
<package name="test" extends="struts-default" namespace="/"> <!-- 声明拦截器 --> <interceptors> <interceptor name="interceptor02" class="com.itheima.web.interceptor.Interceptor02"> </interceptor> </interceptors> </package>
-
在action里面使用拦截器
<action name="demo_*" class="com.itheima.web.action.ActionDemo" method="{1}"> <interceptor-ref name="interceptor02"></interceptor-ref> </action>
2.3方式三:继承MethodFilterInterceptor【重点】
是AbstractInterceptor的一个子类.可以精确的控制拦截或者不拦截哪一个方法
-
创建一个类继承MethodFilterInterceptor
public class Interceptor03 extends MethodFilterInterceptor { @Override protected String doIntercept(ActionInvocation invocation) throws Exception { System.out.println("Interceptor03 执行了..."); //放行 invocation.invoke(); return null; } }
-
在struts.xml里面声明拦截器
<package name="test" extends="struts-default" namespace="/"> <!-- 声明拦截器 --> <interceptors> <interceptor name="interceptor03" class="com.itheima.web.interceptor.Interceptor03"> </interceptor> </interceptors> </package>
-
在action里面使用拦截器
<action name="demo_*" class="com.itheima.web.action.ActionDemo" method="{1}"> <interceptor-ref name="interceptor03"> <!--不拦截fun02()方法 --> <param name="excludeMethods">fun02</param> </interceptor-ref> </action>
注: 拦截器的执行顺序,取决于action标签中interceptor-ref的顺序.
3.自定义拦截器相关的操作
3.1拦截器不放行
拦截器的处理结果,莫过于两种:
放行: 如果后面还有拦截器就执行下一个拦截器,如果后面没有了拦截器,就执行action
拦截: 但是注意,拦截后也需要返回到一个具体的结果(页面,Action...)。 所以需要配置result标签
- 放行, 调用invoke()方法即可
- 拦截,跳转其它页面, 不调用invoke()方法
3.2自定义拦截器的问题【重视】
一旦使用了自己定义的拦截器,那么struts默认的哪一套 拦截器就不会走。 有点像有参构造和无参构造的关系。
-
struts默认的拦截器都有哪些呢?在struts-default.xml里面有一个package 名字也叫作 struts-default 在这个包中定义了一个拦截器栈,名字叫做 defaultStack.
<interceptor-stack name="defaultStack"> <interceptor-ref name="exception"/> <interceptor-ref name="alias"/> <interceptor-ref name="servletConfig"/> <interceptor-ref name="i18n"/> <interceptor-ref name="prepare"/> <interceptor-ref name="chain"/> <interceptor-ref name="scopedModelDriven"/> <interceptor-ref name="modelDriven"/> <interceptor-ref name="fileUpload"/> <interceptor-ref name="checkbox"/> <interceptor-ref name="datetime"/> <interceptor-ref name="multiselect"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"/> <interceptor-ref name="conversionError"/> <interceptor-ref name="validation"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="workflow"> <param name="excludeMethods">input,back,cancel,browse</param> </interceptor-ref> <interceptor-ref name="debugging"/> <interceptor-ref name="deprecation"/> </interceptor-stack> .... <default-interceptor-ref name="defaultStack"/>
-
如果我们给自己的action使用了自己定义的拦截器,那么上面默认的这些拦截器都不会生效了,失去了这些功能,如果还想使用默认的这些拦截器。那么可以在action里面再引用它即可。
<action name="actionDemo_*" class="com.itheima.action.ActionDemo" method="{1}"> <!-- 执行这个action,就必然要走名字叫做myInterceptor02的拦截器 --> <!-- 使用默认的拦截器 --> <interceptor-ref name="defaultStack"></interceptor-ref> <!-- 使用自定义的拦截器 --> <interceptor-ref name="myInterceptor"></interceptor-ref> <result name="login">/index.jsp</result> </action>
4.案例: 使用拦截器完成用户登录过滤
4.1 案例需求
在项目的欢迎页面(index), 点击进入网站首页.
如果用户没有登录过,跳转到登录页面(login);
如果用户登录过, 跳转到网站首页(home), 并显示欢迎xx用户
4.2案例思路
-
修改进入网站首页的超链接
<a href="${pageContext.request.contextPath }/user_index">进入网站首页</a>
-
创建UserAction继承ActionSupport,创建index()方法
-
在index()方法里面, 返回 “index”.
-
在struts.xml里面配置Action和结果
-
创建LoginInterceptor,在doIntercept()方法里面
判断用户是登录(就是从session里面获得user,判断user 是否为空)
如果登录, 放行
如果没有登录,拦截,跳转到登录页面 -
在登录页面, 点击登录按钮,把数据提交到Action
二,标签库
1.概述
1.1 Struts2标签库介绍
Struts2标签库是一个比较完善,且功能强大的标签库,它将所有标签都统一到一个标签库中,从而简化了标签的使用,它还提供主题和模板的支持,极大地简化了视图页面代码的编写。
1.2Struts2标签库分类
这些标签都在 docs/docs/tag-reference.html 里面可以找到
1.3使用步骤
- 如果使用Struts2的标签库,必须导入库到页面
<%@ taglib uri="/struts-tags" prefix=“s” %> - 根据语法书写标签库…
2.流程控制标签库【重点】
-
if标签,elseif标签…类似JSP里面的c:if
取值:<s:property value="#request.a"/><br/> <s:if test="#request.a > 10"> a 大于10 </s:if> <s:else> a 小于或者等于10 </s:else>
-
iterator标签类似JSP里面的c:foreach
<s:iterator value="list" var="u"> <s:property value="username"/> <s:property value="password"/> </s:iterator>
3.UI标签
3.1表单标签
-
和HTML标签对比
<h1>一,HTML的表单标签</h1> <form action="${pageContext.request.contextPath }/demo03_fun03" method="post"> 用户名:<input type="text" name="username"/><br/> 密码: <input type="password" name="password"/><br/> 性别:<input type="radio" name="sex" value="1"/>男<input type="radio" name="sex" value="0"/>女<br/> 爱好: <input type="checkbox" name="hobby" value="lq"/>篮球 <input type="checkbox" name="hobby" value="zq"/>足球 <input type="checkbox" name="hobby" value="ppq"/>乒乓球 <input type="checkbox" name="hobby" value="qdm"/>敲代码<br/> 籍贯:<select name="address"> <option value="-1">-请选择-</option> <option value="0">北京</option> <option value="1">上海</option> <option value="2">深圳</option> </select><br/> 自我介绍:<textarea rows="2" cols="8" name="introduce">哈哈哈</textarea><br/> <input type="submit" /> </form> <h1>二,Struts2的表单标签</h1> <!--默认请求方式就是post,action不用写项目路径--> <s:form action="/demo03_fun03"> <s:textfield name="username" label="用户名" /> <s:password name="password" label="密码"/> <%-- <s:radio list="{'男','女'}" name="sex" label="性别"/> --%> <s:radio list="#{'1':'男','0':'女' }" name="sex" label="性别" value="1"></s:radio> <s:checkboxlist list="{'篮球','足球','乒乓球','敲代码'}" label="爱好" name="hobby"/> <s:select list="#{'0':'北京','1':'上海','2':'深圳' }" label="籍贯" name="address" headerKey="-1" headerValue="请选择" value="1"></s:select> <s:textarea cols="8" rows="2" name="introduce" label="籍贯" value="哈哈"></s:textarea> <s:submit value="注册" align="left"/> </s:form>
Struct2标签特点:
自动加了样式, 标签都套了一层表格.对齐了
有自动回显数据的功能.
3.2Struts2模版和主题
主题就是一种风格化标签,能够让所有UI标签能够产生同样的视觉效果而归集到一起的一组模板,即风格相近的模板被打包为一个主题. struts2提供了四种主题simple、xhtml、css_xhtml、ajax。
simple:把UI标签翻译成最简单的HTML对应元素,而且会忽视行标属性
xhtml:默认的主题。这个主题的模板通过使用一个布局表格提供了一种自动化的排版机制(默认)
css_xhtml:这个主题里的模板与xhtml主题里的模板很相似,但他们将使用css来进行布局和排版
ajax:这个主题里的模板以xhtml主题里的模板为基础,但增加了一些ajax功能。
-
通过配置struts.xml文件中的常量属性struts.ui.theme修改主题风格. 全局的
<constant name="struts.ui.theme" value="simple"></constant>
-
也可以通过UI标签的theme属性进行修改
<s:form action="..." theme="simple">
1.国际化案例
1.1需求步骤
-
创建国际化资源. 在src下新建两个properties文件 , login_zh_CN.properties login_en_US.properties. 命名规则是 名字_语言_国家地区.properties 注意:名字必须一致,只是后面的语言 & 国家可以不同而已。
如: login_zh_CN.properties内容: login.username=用户名 login.password=密码 login.submit=登录 login_en_US.properties的内容: login.username=username login.password=password login.submit=submit
-
告诉struts框架,使用这个国际化文件 ,配置手法,在struts.xml里面配置常量
-
修改页面内容
-
<a href="${pageContext.request.contextPath }/demo_fun01?request_locale=zh_CN">中文</a> <a href="${pageContext.request.contextPath }/demo_fun01?request_locale=en_US">English</a> <!--这两个超链接是用来跳转到一个action,让struts 根据提交过去的request_locale 参数值来获取对应的properties文件内容,那个action里面没有什么实质性内容,只要返回success,然后还跳转到这个页面来即可。--> <s:form id="loginform" action="login" method="post"> <s:textfield name="username" key="login.username"></s:textfield> <s:textfield name="password" key="login.password" ></s:textfield> <s:submit key="login.submit"></s:submit> </s:form>