大家好,又见面了,我是你们的朋友全栈君。
勿以恶小而为之,勿以善小而不为————————–刘备
劝诸君,多行善事积福报,莫作恶
上一章简单介绍了Struts2的%,#,$的区别,UI标签及其表单radio,checkbox,select回显数据(七),如果没有看过,请观看上一章
Struts2的拦截器,功能非常强大,很多强有力的功能都是通过拦截器实现的。我们输入一个网址,为什么只配置了过滤器和struts.xml文件中的action,就会去执行Action呢? 就是因为拦截器的存在。
Struts2框架已经默认为我们的每一个自定义的action都实现了一个拦截器default-stack。 其中拦截器的相关配置在struts-core核心包下的struts-default.xml文件中。
拦截器是在Action执行方法前被调用,在方法执行后被销毁。
一. Struts2提供的关于拦截器的接口和类
一.一 Struts2官方提供的拦截器Interceptor接口
package com.opensymphony.xwork2.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import java.io.Serializable;
public abstract interface Interceptor
extends Serializable
{
public abstract void destroy();
public abstract void init();
public abstract String intercept(ActionInvocation paramActionInvocation)
throws Exception;
}
destroy()方法是销毁,init()是初始化, intercept() 方法才是我们真正要关注的方法。
我们编写拦截器,一般不使用实现这个接口,而是继承它的实现类AbstractInterceptor
一.二 抽象类AbstractInterceptor
package com.opensymphony.xwork2.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
public abstract class AbstractInterceptor
implements Interceptor
{
public void init() {}
public void destroy() {}
public abstract String intercept(ActionInvocation paramActionInvocation)
throws Exception;
}
这个抽象类AbstractInterceptor实现了Interceptor接口,并且重写了init()方法和destroy()方法,用户只需要实现interceptor()方法即可。
我们用这个抽象类做一个简单的拦截器,实际开发中也并不用这一个抽象类AbstractInterceptor。
二. 简单自定义一个拦截器
二.一 新建拦截器类MyInterceptor ,继承AbstractInterceptor类
前堤已经有了一个基本的Struts2的运行环境,延用上一章的struts2的配置和Action
在com.yjl.web.interceptor包下新建一个MyInterceptor类,让其继承AbstractInterceptor类
package com.yjl.web.interceptor;
import org.apache.log4j.Logger;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
/**
* @author 两个蝴蝶飞
* @version 创建时间:Aug 25, 2018 4:03:21 PM
* 类说明
*/
public class MyInterceptor extends AbstractInterceptor{
private static final long serialVersionUID = -6424208964705287809L;
private Logger logger=Logger.getLogger(MyInterceptor.class);
@Override
public String intercept(ActionInvocation actionInvocation)
throws Exception {
logger.info("******开始执行拦截器*******");
String result=actionInvocation.invoke();
logger.info("执行后的结果为:"+result);
logger.info("********结束执行拦截器**********");
return result;
}
}
二.二 创建Action控制器,MyInterceptorAction
在MyInterceptorAction中,返回SUCCESS字符串
public class MyInterceptorAction extends ActionSupport{
private static final long serialVersionUID = 8278845997106407817L;
public String getForm(){
return SUCCESS;
}
}
二.三 在struts.xml中package标签下实例化拦截器
自定义的拦截器,刚开始定义好后,并不知道属于哪一个action,所以实例化拦截器放在 包下,用一个标签包起来,里面放置标签,这个标签有name和class两个属性,通过反射可以自己实例化自定义的拦截器。
<package name="interceptor" extends="struts-default" namespace="/">
<interceptors>
<!-- 定义单个拦截器 -->
<interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor">
</interceptor>
</interceptors>
<!-- 配置跳转页面 -->
<action name="*">
<result>/WEB-INF/content/{1}.jsp</result>
</action>
</package>
二. 四 在struts.xml中action标签下引用具体的拦截器
<package name="interceptor" extends="struts-default" namespace="/">
<interceptors>
<!-- 定义单个拦截器 -->
<interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor">
</interceptor>
</interceptors>
<action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
<!-- 引入自定义拦截器 -->
<interceptor-ref name="myInterceptor"></interceptor-ref>
<!-- 配置跳转页面 -->
<result name="success">/WEB-INF/content/form.jsp</result>
</action>
<!-- 配置跳转页面 -->
<action name="*">
<result>/WEB-INF/content/{1}.jsp</result>
</action>
</package>
二.五 编写 /content/form.jsp 页面
<body>
拦截器跳转后页面
</body>
二.六 测试验证拦截器
重启服务器,输入网址:http://localhost:8080/Struts_Interceptor/Interceptor_getForm
查看控制台日志打印:
可以发现拦截器配置完成.
提示: (在操作时,不要忘记配置web.xml中struts的过滤器)
三. 拦截器配置过程中的扩展
上面例子只是一个简单的拦截器,在实际项目中可能会配置多个拦截器,每个拦截器有不同的功能。复杂的拦截器该如何配置呢?
三.一 默认拦截器 defaultStack
可以查看struts-core.jar包下的struts-default.xml中的配置,注意查看示例. 这里简单一下里面的配置
<!--注意名称: 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="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">^action:.*,^method:.*</param>
</interceptor-ref>
<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"/>
<!--每一个继承ActionSupport类的Action都具有基本拦截器的功能-->
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
三.二 自定义配置多个拦截器
<interceptors>
<!-- 定义单个拦截器 -->
<interceptor name="myInterceptor1" class="com.yjl.web.interceptor.MyInterceptor1">
</interceptor>
<interceptor name="myInterceptor2" class="com.yjl.web.interceptor.MyInterceptor2">
</interceptor>
<interceptor name="myInterceptor3" class="com.yjl.web.interceptor.MyInterceptor3">
</interceptor>
</interceptors>
那么在Action中引用中,用到了哪一个拦截器,就用哪一个拦截器.
假如 MyInterceptorAction中用了第二个和第三个。
<action name="Form_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
<!-- 引入自定义拦截器 -->
<interceptor-ref name="myInterceptor2"></interceptor-ref>
<interceptor-ref name="myInterceptor3"></interceptor-ref>
<result name="success">/WEB-INF/content/form.jsp/result>
</action>
用到哪一个就配置哪一个。
三.三 拦截器栈 <interceptor-stack> </interceptor-stack>
我们的package包下开发中有多个Action(当然前堤也是interceptor拦截器多的情况下如1~30),
现在情况是 Form1Action引入了111拦截器,Form2Action引入了212拦截器,
Form3Action引入了3~13拦截器,
要是按照上面的样式配置的话,4~11会被配置成3遍,很显然不太好。
这个时候,可以将4~11配置成一个拦截器栈, 这样在引用了就比较容易引用了。
拦截器栈放在package标签下,用的是 <interceptor-stack > </interceptor-stack>
<interceptors>
<!-- 定义单个拦截器 -->
<interceptor name="myInterceptor1" class="com.yjl.web.interceptor.MyInterceptor1">
</interceptor>
<interceptor name="myInterceptor2" class="com.yjl.web.interceptor.MyInterceptor2">
</interceptor>
<interceptor name="myInterceptor3" class="com.yjl.web.interceptor.MyInterceptor3">
</interceptor>
<!-- 配置拦截器栈,里面有三个拦截器 -->
<interceptor-stack name="myInterceptor">
<interceptor-ref name="myInterceptor1"></interceptor-ref>
<interceptor-ref name="myInterceptor2"></interceptor-ref>
<interceptor-ref name="myInterceptor3"></interceptor-ref>
</interceptor-stack>
</interceptors>
可以根据不同的action,配置不同的interceptor-stack, 可以配置多个。
这样在配置MyInterceptorAction时,只需要简单一句
<action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
<!-- 引入自定义拦截器栈 -->
<interceptor-ref name="myInterceptor"></interceptor-ref>
<result name="success">/WEB-INF/content/form.jsp</result>
</action>
便具有1,2,3三个拦截器的功能了。
配置FormAction 时,也同样引用:
<action name="Form_*" class="com.yjl.web.action.FormAction" method="{1}">
<!-- 引入自定义拦截器栈 -->
<interceptor-ref name="myInterceptor"></interceptor-ref>
<result name="success">/WEB-INF/content/form2.jsp</result>
</action>
也就具有了1,2,3三个拦截器的功能了。
三.四 默认拦截器栈 default-stack
如同Java中默认构造函数一样,Struts2提供了一个默认的拦截器栈default-stack,
如果用户自己引用了一个拦截器,无论是框架提供的,还是自定义的,
原有的拦截器栈将不在起作用了,将失效了。
默认的拦截器 default-stack中有很多的功能,如异常,别名,国际化,参数,文件上传等。 所以这些功能很重要,所以,默认的拦截器不能丢掉。
我们在引入自定义拦截器后,还需要引入默认的拦截器
<action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
<!-- 引入自定义拦截器 -->
<interceptor-ref name="myInterceptor"></interceptor-ref>
<!-- 放置原有的默认的拦截器 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="success">/WEB-INF/content/form.jsp</result>
</action>
这样, MyInterceptorAction 将具有原先拦截器的功能,也具有自定义拦截器的功能。
三.五 将新的拦截器配置成默认的拦截器
可以利用 将原有的默认的defaultStack给其改变。
<interceptors>
<!-- 定义单个拦截器 -->
<interceptor name="myInterceptor1" class="com.yjl.web.interceptor.MyInterceptor1">
</interceptor>
<interceptor name="myInterceptor2" class="com.yjl.web.interceptor.MyInterceptor2">
</interceptor>
<interceptor name="myInterceptor3" class="com.yjl.web.interceptor.MyInterceptor3">
</interceptor>
<!-- 注意看拦截器的配置 -->
<interceptor-stack name="myInterceptor">
<interceptor-ref name="myInterceptor1"></interceptor-ref>
<interceptor-ref name="myInterceptor2"></interceptor-ref>
<interceptor-ref name="myInterceptor3"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 写在Action外面 -->
<default-interceptor-ref name="myInterceptor"></default-interceptor-ref>
这样,就改变了默认的拦截器的值。
在Action中就不用在配置拦截器了
<action name="Interceptor_*" class="com.yjl.web.action.MyInterceptorAction" method="{1}">
<result name="success">/WEB-INF/content/form.jsp</result>
</action>
注意,这个新定义的默认拦截器的作用范围是 package.
Struts2以 package 包 作为划分区域。
三.六 拦截器配置参数
用<param> </param> 进行引用。
<interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor">
<!--添加参数-->
<param name="charset">UTF-8</param>
</interceptor>
在MyInterceptor拦截器中,添加这个charset属性,实现setter和getter方法即可。
public class MyInterceptor extends AbstractInterceptor{
private static final long serialVersionUID = -6424208964705287809L;
private Logger logger=Logger.getLogger(MyInterceptor.class);
private String charset;
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
//后面还有很多代码,没有复制
这样,在 struts.xml 中定义传入参数值,在过滤器中就可以引用这个参数了。
这个参数可以在拦截器定义时注入,也可以在拦截器被Action引入时注入。
**拦截器定义时引入: **
<interceptor-ref name="myInterceptor">
<param name="charset">UTF-8</param>
</interceptor-ref>
拦截器被Action 引入时注入:
<interceptor name="myInterceptor" class="com.yjl.web.interceptor.MyInterceptor">
<!--添加参数-->
<param name="charset">UTF-8</param>
</interceptor>
三.七 公共功能拦截器配置
在项目中,常常有登录拦截器,权限验证拦截器,日志拦截器等,对于这些公共的拦截器配置,
推荐将新的拦截器栈名变成 defaultStack, 与原先的保持一致。
<interceptors>
<interceptor name="loginInterceptor" class="com.yjl.web.interceptor.LoginInterceptor">
</interceptor>
<interceptor-stack name="defaultStack">
<interceptor-ref name="loginInterceptor">
<interceptor-ref name="logInterceptor">
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
四 MethodFilterInterceptor类 源码分析
在实际开发中,配置拦截器,常常使用的是 MethodFilterInterceptor,
从方法名称中,也可以看出,拦截的是Action中的某些方法。
尝试着分析一下源码.(老蝴蝶偷偷不要脸一次)
package com.opensymphony.xwork2.interceptor;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.omg.CORBA.PRIVATE_MEMBER;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptorUtil;
import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
//继承了AbstractInterceptor类,实现的方法由以前的interceptor()方法改成了doIntercept()方法
public abstract class MethodFilterInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 1L;
protected transient Logger log = LoggerFactory.getLogger(getClass());
/**
* MethodFilterInterceptor 类的两个参数 ,均用Set集合
* 学到一招,在类中实例时时,不要在private Set<User> userSet=new HashSet<User>();了
* 试试Collections.emptySet()实例化. List时用Collections.emptyList();方法
* @param excludeMethods 不拦截器的方法. 如注册,找回密码等方法
* @param includeMethods 要拦截的方法, 如登录,查看用户列表等方法
*/
protected Set<String> excludeMethods = Collections.emptySet();
protected Set<String> includeMethods = Collections.emptySet();
//实现两个参数的setter和getter方法
public void setExcludeMethods(String excludeMethods) {
//这个方法如下
this.excludeMethods = TextParseUtil.commaDelimitedStringToSet(excludeMethods);
/*
* 这个方法很明显,就是将字符串按照,进行分隔,然后分别放置到set集合中。
*public static Set<String> commaDelimitedStringToSet(String s)
{
Set<String> set = new HashSet();
String[] split = s.split(",");
for (String aSplit : split) {
//你看看人处理的,先将两边的空格去掉.
String trimmed = aSplit.trim();
//又判断一下长度
if (trimmed.length() > 0)
set.add(trimmed);
}
return set;
}
*/
}
public Set<String> getExcludeMethodsSet() {
return excludeMethods;
}
public void setIncludeMethods(String includeMethods) {
this.includeMethods = TextParseUtil.commaDelimitedStringToSet(includeMethods);
}
public Set<String> getIncludeMethodsSet() {
return includeMethods;
}
//实现了intercept()方法.
public String intercept(ActionInvocation invocation) throws Exception {
if (applyInterceptor(invocation)) {
//如果包括的方法,执行这一个
return doIntercept(invocation);
}
//不是包括的方法,执行这一个。
return invocation.invoke();
}
protected boolean applyInterceptor(ActionInvocation invocation) {
//利用代理模式的方式得到方法
String method = invocation.getProxy().getMethod();
/*
* 进入看了看这个方法,如果是排除的方法,就返回false.
* 如果是包括的方法,就返回true。
*/
boolean applyMethod = MethodFilterInterceptorUtil.applyMethod(excludeMethods, includeMethods, method);
if ((log.isDebugEnabled()) && (!applyMethod)) {
log.debug("Skipping Interceptor... Method [" + method + "] found in exclude list.", new String[0]);
}
return applyMethod;
}
//需要实现的核心方法
protected abstract String doIntercept(ActionInvocation paramActionInvocation) throws Exception;
}
五. MethodFilterInterceptor类 的具体使用
用一个具体的登录实例验证一下吧。
其中实例是按照第四章的两个小例子进行相应的仿写的。
五.一 编写控制器类UserAction
在UserAction中常用的方法如下:
public class UserAction extends BaseAction<User>{
private static final long serialVersionUID = 1L;
private Logger logger=Logger.getLogger(UserAction.class);
private UserService userSerive=new UserService();
/**
* 转到登录的页面
*/
public String toLogin(){
logger.info("跳转到登录的界面");
return "toLogin";
}
/**
* 具体的登录方法
*/
public String login(){
logger.info("执行具体的登录操作");
User user=userSerive.login(getModel());
if(user!=null) {
//说明存在这个用户
//登录成功后,将登录的用户放置到session中.
ActionContext.getContext().getSession().put("currentUser",user);
return LOGIN;
}else {
HttpServletRequest request=ServletActionContext.getRequest();
request.setAttribute("message","用户名或者密码错误");
return "toLogin";
}
}
/**
* 跳转到注册的页面
*/
public String toRegisterUI(){
logger.info("跳转到注册的界面");
return "toRegisterUI";
}
/**
* 进行用户的注册,注册成功之后跳转到登录的界面
* 注册成功之后,不把数据带到登录页面进行填充.
*/
public String register(){
logger.info("执行具体的注册功能");
return "toLogin";
}
/**
* 用户点击忘记密码后跳转到忘记密码的界面
*/
public String forgetPasswordUI(){
logger.info("跳转到忘记密码的界面");
return "forgetPasswordUI";
}
/**
* 用户在忘记密码界面添加新的密码后执行修改密码
* 修改密码成功后跳转到登录界面
*/
public String forgetPassword(){
logger.info("添加新的密码后修改密码");
return "toLogin";
}
/**
* 显示列表
*/
public String list(){
logger.info("显示用户列表");
List<User> userList=userSerive.findAll();
ActionContext.getContext().put("userList",userList);
return "list";
}
/**
*跳转到添加的界面
*/
public String addUI(){
logger.info("跳转到添加的界面");
return "addUI";
}
/**
*执行具体的添加操作后,返回到list列表显示。
*/
public String add(){
logger.info("执行具体的添加操作");
return "toList";
}
/**
* 跳转到修改的界面
*/
public String editUI(){
logger.info("跳转到修改的界面");
return "editUI";
}
/**
* 执行具体的修改操作,修改完成后返回到列表的界面
*/
public String edit(){
logger.info("执行具体的修改操作");
return "toList";
}
/**
* 执行具体的删除操作,删除成功后返回到列表的界面
*/
public String delete(){
logger.info("执行具体的删除操作");
return "toList";
}
/**
* 点击名字,显示具体的详情
*/
public String detailUI(){
logger.info("显示具体的详情操作");
return "detailUI";
}
}
其中
toLogin(); login(); toRegisterUI(); register();forgetPasswordUI();forgetPassword();是不需要进行登陆拦截的,
list()及其以下方法,是需要登录拦截的。
如果toRegisterUI()方法也被拦截的话,那么是无法进行注册功能的。
五.二 根据Action中的返回值配置相应的struts.xml文件
<?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>
<!--修改国际化编码 -->
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<!--修改是否为开发者模式 -->
<constant name="struts.devMode" value="true"></constant>
<!--修改ui样式表 -->
<constant name="struts.ui.theme" value="simple"></constant>
<package name="methodInterceptor" extends="struts-default" namespace="/">
<!-- 配置全局错误页面 -->
<global-results>
<result name="error">/WEB-INF/content/error.jsp</result>
</global-results>
<action name="User_*" class="com.yjl.web.action.UserAction" method="{1}">
<!-- 转到登录页面的配置 -->
<result name="toLogin">/WEB-INF/content/login.jsp</result>
<!-- 登录的配置 -->
<result name="login" type="redirectAction">User_list.action</result>
<result name="toRegisterUI">/WEB-INF/content/register.jsp</result>
<result name="forgetPasswordUI">/WEB-INF/content/forgetPassword.jsp</result>
<result name="list">/WEB-INF/content/list.jsp</result>
<result name="addUI">/WEB-INF/content/add.jsp</result>
<result name="toList" type="redirectAction">User_list.action</result>
<result name="editUI">/WEB-INF/content/edit.jsp</result>
<result name="detailUI">/WEB-INF/content/detail.jsp</result>
<result name="success">/WEB-INF/content/form.jsp</result>
</action>
</package>
</struts>
五.三 根据struts.xml中的配置视图编写相应的jsp页面
每一个jsp 页面 都引入了 struts2 标签库
<%@ taglib uri="/struts-tags" prefix="s"%>
五.三.一 编写登录页面 /content/login.jsp
<body>
${message}
<s:form action="User_login.action" namespace="/" method="post">
用户名: <s:textfield name="name"/> <br/>
密码: <s:password name="password"/><br/>
<s:a action="User_forgetPasswordUI" namespace="/">忘记密码</s:a><br/>
<s:a action="User_toRegisterUI" namespace="/">注册新用户</s:a><br/>
<s:submit value="提交"/>
<s:reset value="重置"/>
</s:form>
</body>
五.三.二 编写注册页面 /content/register.jsp
<body>
这是注册的界面
<s:form action="User_register" namespace="/" method="post">
<s:submit value="注册"></s:submit>
</s:form>
</body>
五.三.三 编写忘记密码页面 /content/forgetPassword.jsp
<body>
这是忘记密码的界面
<s:form action="User_forgetPassword" namespace="/" method="post">
<s:submit value="确认找回密码"></s:submit>
</s:form>
</body>
五.三.四 编写查看页面 /content/list.jsp
<body>
<div class="container">
<div class="row">
<table class="table table-bordered table-hover">
<caption>查看学生信息</caption>
<thead>
<tr>
<th class="col-xs-2">姓名</th>
<th class="col-xs-2">性别</th>
<th class="col-xs-2">年龄</th>
<th class="col-xs-2">关系</th>
<th class="col-xs-4" colspan="3">相关操作
<span style="padding-left:40px">
<s:a action="User_addUI" namespace="/">添加</s:a>
</span>
</th>
</tr>
</thead>
<tbody>
<s:iterator var="user" value="%{userList}">
<tr>
<td><s:a action="User_detailUI?id=%{id}" namespace="/">${user.name}</s:a></td>
<td>${user.sex}</td>
<td>${user.age}</td>
<td>${user.relation}</td>
<td>
<s:a action="User_editUI?id=%{id}" namespace="/">修改</s:a>
<s:a action="User_delete?id=%{id}" namespace="/">删除</s:a>
</tr>
</s:iterator>
</tbody>
</table>
</div>
</div>
</body>
五.三.五 编写添加页面 /content/add.jsp
<body>
这是添加的界面
<s:form action="User_add" namespace="/" method="post">
<s:submit value="添加"></s:submit>
</s:form>
</body>
五.三.六 编写修改页面 /content/edit.jsp
<body>
这是修改的界面
<s:form action="User_edit" namespace="/" method="post">
<s:submit value="修改"></s:submit>
</s:form>
</body>
五.三.七 编写查看详情页面 /content/detail.jsp
<body>
查看详情的页面
<s:a action="User_list" namespace="/">返回</s:a>
</body>
五.四 重启服务器,看各个链接是否正常跳转
输入网址: http://localhost:8080/Struts_Interceptor/User_toLogin
点击各个链接,发现各个功能正常跳转,
链接跳转显示页面正确,日志打印输出正确。
五.五 编写登录拦截器 LoginInterceptor
package com.yjl.web.interceptor;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import com.yjl.pojo.User;
/**
* @author 两个蝴蝶飞
* @version 创建时间:Aug 27, 2018 8:49:26 AM
* 类说明 登录拦截器
*/
public class LoginInterceptor extends MethodFilterInterceptor{
private static final long serialVersionUID = 1L;
private static Logger logger=Logger.getLogger(LoginInterceptor.class);
@Override
protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
HttpSession session=ServletActionContext.getRequest().getSession();
User currentUser=(User) session.getAttribute("currentUser");
//判断currentUser的值
if(currentUser==null){
//获取请求的方法
String method=actionInvocation.getProxy().getMethod();
//为空,表示没有登录
logger.info(method+"方法需要被拦截,必须登录后使用");
//没有登录,就跳转到登录的页面
return "toLogin";
}else{
//登录,就放行 实际操作中,还有一个权限的判断
String result=actionInvocation.invoke();
logger.info("我操作:"+result);
return result;
}
}
}
五.六 在struts.xml 配置登录拦截器,注意拦截和不需拦截方法的配置
<package name="methodInterceptor" extends="struts-default" namespace="/">
<!-- 配置拦截器 注意顺序,放在global-results前面-->
<interceptors>
<interceptor name="loginInterceptor" class="com.yjl.web.interceptor.LoginInterceptor">
</interceptor>
</interceptors>
<!-- 配置全局错误页面 -->
<global-results>
<result name="error">/WEB-INF/content/error.jsp</result>
<!-- 转到登录页面的配置 -->
<result name="toLogin">/WEB-INF/content/login.jsp</result>
</global-results>
<action name="User_*" class="com.yjl.web.action.UserAction" method="{1}">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="loginInterceptor">
<param name="excludeMethods">toLogin,login,toRegisterUI,register,forgetPasswordUI,forgetPassword</param>
<param name="includeMethods">list,toList,addUI,add,editUI,edit,delete,detail</param>
</interceptor-ref>
<!-- 转到登录页面的配置 -->
<result name="toLogin">/WEB-INF/content/login.jsp</result>
<!-- 登录的配置 -->
<result name="login" type="redirectAction">User_list.action</result>
<result name="toRegisterUI">/WEB-INF/content/register.jsp</result>
<result name="forgetPasswordUI">/WEB-INF/content/forgetPassword.jsp</result>
<result name="list">/WEB-INF/content/list.jsp</result>
<result name="addUI">/WEB-INF/content/add.jsp</result>
<result name="toList" type="redirectAction">User_list.action</result>
<result name="editUI">/WEB-INF/content/edit.jsp</result>
<result name="detailUI">/WEB-INF/content/detail.jsp</result>
<result name="success">/WEB-INF/content/form.jsp</result>
</action>
</package>
开发中,不需要拦截的方法少, 一般只需要注入参数excludeMethods即可。
excludeMethods为不需要拦截的方法,
includeMethods为需要拦截的方法。
如果拦截的和不拦截的都有,那么以拦截为主。
五.七 重启服务器,验证拦截器是否起作用
重启服务器,
未登录成功时:
输入 http://localhost:8080/Struts_Interceptor/User_addUI 等网址,会跳转到登录页面,
输入 http://localhost:8080/Struts_Interceptor/User_forgetPasswordUI 等网址,会跳转到指定的 jsp页面。
登录成功后:
输入 http://localhost:8080/Struts_Interceptor/User_addUI 等网址,会正常跳转到指定的 jsp页面。
六. 拦截器与过滤器的区别
摘录于 https://www.cnblogs.com/joyang/p/4973435.html
过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,
然后再传入servlet或者struts的 action进行业务逻辑,
比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),
或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符
拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,
或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),
也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。
拦截器是基于java的反射机制的,而过滤器是基于函数回调。
拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次
这一章是关于拦截器的介绍,非常重要。
本章节的代码链接为:
链接:https://pan.baidu.com/s/18lQmPQzMVfpLF7lyfPKKHQ
提取码:enw4
下一章简单介绍了 Struts2实现国际化操作及中英文切换(九)
谢谢您的观看!!!
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/146729.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...