资讯专栏INFORMATION COLUMN

Struts2【拦截器】就是这么简单

chanjarster / 2746人阅读

摘要:文件上传通过这个拦截器拦截器的设计就是基于组件设计的应用再次回顾拦截器基础在开始讲解的时候已经说明过了这个文件,它定义了的所有拦截器。由于我们配置了自定义拦截器,那么默认的拦截器栈是不会执行的。

什么是拦截器

拦截器Interceptor.....拦截器是Struts的概念,它与过滤器是类似的...可以近似于看作是过滤器

为什么我们要使用拦截器

前面在介绍Struts的时候已经讲解过了,Struts为我们实现了很多的功能,比如数据自动封装阿..文件上传功能阿....Struts为我们提供的这些功能都是通过拦截器完成的......

数据自动封装通过这个拦截器。

文件上传通过这个拦截器

拦截器的设计就是基于组件设计的应用

再次回顾拦截器基础

在开始讲解Struts的时候已经说明过了struts-default.xml这个文件,它定义了Struts的所有拦截器。因为我们在启动服务器的时候会自动装载这个文件,因此我们才可以在Action中使用到Struts为我们提供的功能【数据自动封装...文件上传】

在struts-default.xml中定义的拦截器就有32个之多,Struts2为了方便我们对拦截器的引用,提供了拦截器栈的定义。

            
                
                
                
                
                
                
                
                
                
                
                
                
                
                
                    dojo..*,^struts..*,^session..*,^request..*,^application..*,^servlet(Request|Response)..*,parameters...*
                
                
                
                    input,back,cancel,browse
                
                
                    input,back,cancel,browse
                
                
            

也就是说:当我们要引用多个拦截器的时候,只要把拦截器都放在栈里头,在外边引用拦截器即可!

值得注意的是:Struts2默认执行的是默认拦截器栈,一旦用户有指定执行哪些拦截器,那么默认的拦截器栈就不会被执行!

自定义拦截器

Struts2允许我们自定义拦截器,这就使我们能够更加灵活地操作Struts2这个框架了!

Struts2提供了Interceptor这个拦截器接口,只要我们实现这个接口,那么这就算是自定义开发拦截器了。

当然啦,大部分时候,我们定义拦截器都是继承AbstractInterceptor这个类....为了学习拦截器的内容,下面就实现Interceptor这个接口了。

编写拦截器类

当实现该接口时,有3个需要我们实现的方法:


public class MyInterceptor implements Interceptor {
    @Override
    public void destroy() {

    }

    @Override
    public void init() {

    }

    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        return null;
    }
}

init()和destory()都是和拦截器执行顺序有关的方法,我们现在先不理会....首先来讲解intercept这个方法

    /**
     * @param actionInvocation 拦截器的执行状态
     */
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {
        
        //调用invoke()方法,代表着放行执行下一个拦截器,如果没有拦截器了,那么就执行Action的业务代码
        actionInvocation.invoke();
        return null;
    }

这很容易就能让我们想起在学习过滤器中的doFilter()方法,其实是差不多的!

在struts.xml中配置

像Struts默认的拦截器一样,我们自定义的拦截器是需要我们在struts中配置的。

由于我们配置了自定义拦截器,那么struts默认的拦截器栈是不会执行的。如果我们想要使用默认拦截器栈的功能,就必须把它配置在我们自定义的栈中!

    
        
        
            
            
            
            
            
                
                
                
                
                
            
        
        
        
        
        
        
            /index.jsp

        


    
拦截器的执行顺序

我们来观察拦截器和Action类的执行顺序...只要在对应的方法上向控制台输出就行了!

拦截器

public class MyInterceptor implements Interceptor {
    @Override
    public void destroy() {

        System.out.println("我是拦截器的销毁方法");

    }

    @Override
    public void init() {

        System.out.println("我是拦截器的初始化方法");
    }


    /**
     * @param actionInvocation 拦截器的执行状态
     */
    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {

        System.out.println("我是拦截器的拦截方法");

        //调用invoke()方法,代表着放行执行下一个拦截器,如果没有拦截器了,那么就执行Action的业务代码
        //可看成是过滤器的doFilter()方法
        actionInvocation.invoke();
        return null;
    }
}

Action类

public class TestAction extends ActionSupport {

    public TestAction() {
        System.out.println("我是Action类,我被初始化了!");
    }

    @Override
    public String execute() throws Exception {

        System.out.println("我是Action类的执行方法");


        return null;

    }
}
效果

从效果图我们可以看出,他们的执行顺序是这样的:

当服务器开启的时候,会执行拦截器的init()方法

当访问Action时,Action实例被创建

创建完Action实例,会调用拦截器的interceptor()方法

最后,执行Action的execute()方法

其实很好理解,之前我们使用Struts为我们提供数据自动封装功能的时候,是这样子的:

服务器启动,加载配置文件的信息

初始化默认的拦截器栈

当用户访问Action时,创建Action的实例。拿到Action具体的信息【成员变量、setter和getter】

执行拦截器具体的内容,根据Action具体的信息,把web端的数据封装到Action上

最后在execute()就可以得到封装后的数据了!

拦截器应用案例

需求:当用户登陆成功,跳转到显示用户的JSP页面中。当用户登陆失败,重新返回登陆界面。如果用户直接访问显示用户的JSP页面,那么返回到登陆界面

分析

实现这个需求,我们可以使用过滤器的。只要获取用户的请求URL,再判断URL是不是为list.jsp,如果是,我们返回到登陆的界面就好了。

现在,为了对拦截器的理解,我们使用拦截器去完成这个功能!

搭建配置环境

导入我们c3p0.xml文件

导入c3p0开发包

导入mysql开发包

写数据库连接池工具类

dbUtils开发包

8个struts2需要用到的开发包

创建数据库表,导入数据

编写entity
package zhongfucheng.entity;

/**
 * Created by ozc on 2017/5/3.
 */
public class User {
    
    
    private String id ;
    private String username;
    private String cellphone;
    private String email;
    private String password;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getCellphone() {
        return cellphone;
    }

    public void setCellphone(String cellphone) {
        this.cellphone = cellphone;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
编写DAO
package zhongfucheng.dao;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import zhongfucheng.entity.User;
import zhongfucheng.utils.Utils2DB;

import java.sql.SQLException;
import java.util.List;

/**
 * Created by ozc on 2017/5/3.
 */
public class UserDao {

    public User login(User user) {

        try {
            String sql = "SELECT * FROM user WHERE username = ? AND password = ?";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
            return (User) queryRunner.query(sql, new BeanHandler(User.class), new Object[]{user.getUsername(), user.getPassword()});
        } catch (SQLException e) {
            new RuntimeException("登陆失败了!");
        }

        return null;
    }

    public List getAll() {

        try {
            String sql = "SELECT * FROM user";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
            return (List) queryRunner.query(sql, new BeanListHandler(User.class));
        } catch (SQLException e) {
            new RuntimeException("登陆失败了!");
        }

        return null;
    }

}
编写Service
public class Service {

    UserDao userDao = new UserDao();

    public User login(User user) {
        return userDao.login(user);

    }

    public List getAll() {
        return userDao.getAll();
    }
}
编写登陆的JSP页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    登陆页面






编写处理请求的Action
package zhongfucheng.action;

import com.opensymphony.xwork2.ActionContext;
import zhongfucheng.entity.User;
import zhongfucheng.service.Service;

import java.util.List;
import java.util.Map;

/**
 * Created by ozc on 2017/5/3.
 */
public class UserAction {


    /****************1.封装数据********************/
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    /***************2.调用Service*******************/
    Service service = new Service();


    //登陆
    public String login() {

        User user = service.login(this.user);

        if (user == null) {
            return "input";
        } else {
            //将user的信息存到Session域对象中
            Map session = ActionContext.getContext().getSession();
            session.put("user", user);


            //登陆成功
            return "login";
        }
    }

    //查看user信息
    public String list() {

        //拿到所有用户的信息
        List users = service.getAll();

        //存到request域对象中
        Map request = ActionContext.getContext().getContextMap();

        request.put("users", users);

        return "list";
    }

}
struts.xml配置文件
    
        

            
            user_list

            
            /WEB-INF/list.jsp
        

    

到目前为止,我们登陆或者不登陆都可以得到用户的具体信息....这是不合理的

我们想要的效果是:只有用户正在调用login方法,或者该用户已经登陆了,才可以查看具体的用户信息

因此,我们们要拦截它们,只有用户调用的是login方法时或者已经登陆的情况下,才能跳转到对应的显示页面

拦截器
package zhongfucheng;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ActionProxy;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

/**
 * Created by ozc on 2017/5/3.
 */
public class Interceptor  extends AbstractInterceptor{


    @Override
    public String intercept(ActionInvocation actionInvocation) throws Exception {

        //得到正在执行的代理对象
        ActionProxy proxy = actionInvocation.getProxy();

        //通过代理对象得到正在执行的方法
        String method = proxy.getMethod();


        //如果方法的名字不是login,那么就让他们返回到login页面上
        if (!method.equals("login")) {

            //查看用户是否登陆了
            Object user = ActionContext.getContext().getSession().get("user");

            //如果没有登陆,回到login页面
            if (user == null) {

                return "input";
            } else {

                //登陆了,那么就让它访问具体的用户信息页面
                return actionInvocation.invoke();
            }
        } else {

            //如果是访问login方法,那么就让它执行
            return actionInvocation.invoke();
        }

    }
}
Struts.xml




    

        
            
            

            
            
                
                
            

        


        

        
        


        

        
        

        

            
            user_list

            
            /WEB-INF/list.jsp


            
            /login.jsp

        


    

效果:

只有当用户登陆了才能查看用户具体信息,直接访问Action会跳转回

Struts2其他拦截器 计时拦截器

Struts2自带了计时拦截器,也就是用来统计每个Action执行的时间

执行等待拦截器

如果页面执行得太慢了,Struts2还提供了执行等待拦截器,也就是说,当页面加载得太久了,就跳转到对应的提示页面...当服务器执行完毕了,也跳转到相对应的页面

Struts2防止表单重复提交拦截器 回顾防止表单重复提交

当我们学习Session的时候已经通过Session来编写了一个防止表单重复提交的小程序了,我们来回顾一下我们当时是怎么做的:

在Servlet上生成独一无二的token,保存在Session域中,并交给JSP页面

JSP页面在提交表单数据的时候,把token放在隐藏域中...一起带过去给Servlet

Servlet判断用户有没有带token值过来,判断token的值是否和Session的相匹配

如果用户是第一次提交的话,那么就允许用户的请求,接着就把保存在Session中的token值去除

等用户想要再次提交的时候,Servlet发现Session中并没有token了,所以不搭理用户的请求

我们以前写表达重复提交就花了这么几个步骤...如果有兴趣的同学可以看一下以前的实现思路:http://blog.csdn.net/hon_3y/article/details/54799494#t11

Struts2防止表单重复提交

Struts2是简化我们的开发的,表单重复提交也是一件非常常用的功能...Struts2也为我们实现了...当然啦,也是通过拦截器来实现

   

它的实现原理和我们以前写的思路几乎一致...它不需要另外写一个组件来生成token值,struts2标签就有这么一个功能...因此是十分方便的

为了熟悉一下Struts2,我们也使用Struts2来编写一下上图的程序...

编写DAO
package zhongfucheng.dao;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import zhongfucheng.entity.User;
import zhongfucheng.utils.Utils2DB;

import java.sql.SQLException;
import java.util.List;

/**
 * Created by ozc on 2017/5/3.
 */
public class UserDao {

    public void add(User user) {
        try {

            String sql = "INSERT INTO user(id,username,cellphone,password,address) VALUES (?,?,?,?,?)";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

            queryRunner.update(sql, new Object[]{user.getId(), user.getUsername(), user.getCellphone(), user.getPassword(),user.getAddress()});

        } catch (SQLException e) {
            new RuntimeException("登陆失败了!");
        }
    }

    public User findUser(String id) {
        try {
            String sql = "SELECT * FROM user WHERE id=?";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

            return (User) queryRunner.query(sql, new BeanHandler(User.class), new Object[]{id});
            
        } catch (SQLException e) {
            new RuntimeException("登陆失败了!");
        }
        return null;
    }

    public List getAll() {

        try {
            String sql = "SELECT * FROM user";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
            return (List) queryRunner.query(sql, new BeanListHandler(User.class));
        } catch (SQLException e) {
            new RuntimeException("登陆失败了!");
        }
        return null;
    }
    public void  updateUser(User user) {

        try {
            String sql = "UPDATE user SET username=?,password=?,cellphone=? WHERE id=?";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

            queryRunner.update(sql, new Object[]{user.getUsername(), user.getPassword(), user.getCellphone(), user.getId()});
        } catch (SQLException e) {
            new RuntimeException("登陆失败了!");
        }
    }

}
编写service
package zhongfucheng.service;

import zhongfucheng.dao.UserDao;
import zhongfucheng.entity.User;
import zhongfucheng.utils.WebUtils;

import java.util.List;

/**
 * Created by ozc on 2017/5/3.
 */
public class Service {

    UserDao userDao = new UserDao();

    public void add(User user) {


        //手动设置id,因为在数据库表我没使用自动增长id
        user.setId(WebUtils.makeId());

        //这是以前的表,规定要address,只能手动设置了
        user.setAddress("广州");
        userDao.add(user);

    }

    public User findUser(String id) {

        return userDao.findUser(id);

    }

    public List getAll() {

        return userDao.getAll();

    }
    public void  updateUser(User user) {


        userDao.updateUser(user);

    }
}
开发步骤

编写添加用户JSP

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="s" uri="/struts-tags" %>





用户名:
密码:
电话:

使用了模型驱动封装数据,添加用户


    //这里一定要实例化
    User user = new User();

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public User getModel() {
        return user;
    }


    /*******调用service********/
    Service service = new Service();

    public String register() throws Exception {

        service.add(user);


        //注册成功,就跳转到list()方法,list方法就跳转到查看所有用户页面了!
        return list();
    }

列出全部的用户数据,提供修改功能,需要把id传递过去,明确修改的是哪一个用户

<%--
  Created by IntelliJ IDEA.
  User: ozc
  Date: 2017/5/2
  Time: 18:24
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="s" uri="/struts-tags" %>


    列出下载页面



        
            
用户id 用户姓名 用户密码 用户电话 操作
${user.id} ${user.username} ${user.password} ${user.cellphone} 修改

Action得到web带过来的id,找到对象,添加到值栈中(数据回显)

    public String updatePage() throws Exception {

        //得到用户带过来的id,根据id查找对象
       User user222 = service.findUser(user.getId());

        ActionContext.getContext().getValueStack().push(user222);

        return "updatePage";
    }

修改用户的JSP页面,使用Struts2提供的回显技术,并把id通过隐藏域带过去给Action..最终是通过id来修改用户的数据

用户名
密码
电话
效果

防止表单重复提交

上面我们已经完成了大部分的功能了,但当我们如果提交之后,再刷新页面,那么表单的数据就会重复提交...我们使用Struts2我们提供的防止表单重复提交的功能把!

在需要提交的表单上使用token标签
用户名:
密码:
电话:
在struts配置文件中配置拦截器

token拦截器默认是不会启动的,也就是说:需要我们手动配置...

当我们配置拦截器的时候,Struts2默认的拦截器是不会执行的,所以要把Struts2默认的拦截器也写上





    
    



        

            

            
                
                register
            

            
             /list.jsp

            
            /update.jsp

            
            /login.jsp

            /user_list
        
    

    


当我们重复提交的时候,它会报错,因此,如果它报错了,我们就跳转到register页面把

测试

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68742.html

相关文章

  • Java3y文章目录导航

    摘要:前言由于写的文章已经是有点多了,为了自己和大家的检索方便,于是我就做了这么一个博客导航。 前言 由于写的文章已经是有点多了,为了自己和大家的检索方便,于是我就做了这么一个博客导航。 由于更新比较频繁,因此隔一段时间才会更新目录导航哦~想要获取最新原创的技术文章欢迎关注我的公众号:Java3y Java3y文章目录导航 Java基础 泛型就这么简单 注解就这么简单 Druid数据库连接池...

    KevinYan 评论0 收藏0
  • SpringMVC入门就这么简单

    摘要:也就是说映射器就是用于处理什么样的请求提交给处理。这和是一样的提交参数的用户名编号提交配置处理请求注册映射器包框架接收参数设置无参构造器,里边调用方法,传入要封装的对象这里的对象就表示已经封装好的了对象了。 什么是SpringMVC? SpringMVC是Spring家族的一员,Spring是将现在开发中流行的组件进行组合而成的一个框架!它用在基于MVC的表现层开发,类似于struts...

    SKYZACK 评论0 收藏0
  • 纳税服务系统【总结】

    摘要:要是使用到日历的话,我们想到使用这个日历类上面仅仅是我个人总结的要点,如果有错误的地方还请大家给我指正。 纳税服务系统总结 纳税服务系统是我第一个做得比较大的项目(不同于javaWeb小项目),该项目系统来源于传智Java32期,十天的视频课程(想要视频的同学关注我的公众号就可以直接获取了) 我跟着练习一步一步完成需求,才发觉原来Java是这样用来做网站的,Java有那么多的类库,页面...

    ispring 评论0 收藏0
  • SpringMVC【开发Controller】详解

    摘要:是使用拦截器来自动帮我们完成中文乱码的问题的。这是我的首页当然了,基于注解和基于来开发,都是通过映射器适配器和视图解析器的。能够控制请求路径和请求方式一个控制器写多个业务方法到目前为止,我们都是一个控制器写一个业务方法,这肯定是不合理的。 前言 本文主要是讲解在Controller中的开发,主要的知识点有如下: 编码过滤器 使用注解开发 注解@RequestMapping详解 业务方...

    Pines_Cheng 评论0 收藏0
  • Struts2截器

    摘要:自定义的拦截器可以和框架内置的拦截器进行混合使用,一般情况拦截器都被默认配置成为执行的基础。若类型转换失败,或者数据验证失败,拦截器就会阻止的执行。 1.拦截器简介 默认的拦截器在设计的时候就能满足大部分的应用,所以很多时候就不需要添加自定义的拦截器或者修改拦截器栈。很多action有各种各样的需求,比如输入验证、文件上传、防止多次提交等等。于是struts框架就提供了一个解决方案,I...

    dendoink 评论0 收藏0

发表评论

0条评论

chanjarster

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<