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

Seafile搭建以及onlyoffice在线办公 部署seafile docker-compose.yml 如下: 参考此篇文章 version: '2.0' services: db: image: mariadb:10.1 container_name: seafile-mysql environment: - MYSQL_ROOT_PASSWORD=db_dev # mysql root的密码,同时修改 seafile的DB_ROOT_PASSWD与这个一致 - MYSQL_LOG_CONSOLE 阅读详情

什么是拦截器

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

为什么我们要使用拦截器

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

  • 数据自动封装通过<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>这个拦截器。
  • 文件上传通过<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>这个拦截器

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

再次回顾拦截器基础

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

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


            <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">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</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-stack>

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

值得注意的是: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默认的拦截器栈是不会执行的。如果我们想要使用默认拦截器栈的功能,就必须把它配置在我们自定义的栈中!


    <package name="xxx" extends="struts-default" >

        <interceptors>
            <!--配置用户自定义的拦截器-->
            <interceptor name="MyInterceptor" class="TestAction"/>

            <!--自定义拦截器栈,我们配置了自定义的拦截器,默认的拦截器栈就不会被执行,因此,想要使用默认的拦截器功能,就要配置进来-->
            <interceptor-stack name="mystack">
                <!--引用默认的拦截器栈,一定要放在第一行-->
                <interceptor-ref name="defalutStack"/>

                <!--引用自定义的拦截器-->
                <interceptor-ref name="MyInterceptor"/>
            </interceptor-stack>
        </interceptors>

        <!--上面配置了拦截器栈,但是没有被执行...下面配置执行拦截器-->
        <default-interceptor-ref name="mystack"/>

        <action name="TestAction" class="TestAction" method="execute">
            <result name="success">/index.jsp</result>

        </action>


    </package>

拦截器的执行顺序

我们来观察拦截器和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<User> getAll() {

        try {
            String sql = "SELECT * FROM user";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
            return (List<User>) 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<User> getAll() {
        return userDao.getAll();
    }
}

编写登陆的JSP页面


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登陆页面</title>
</head>
<body>

<form action="${pageContext.request.contextPath}/user_login" method="post">
    <input type="text" name="username"><br>
    <input type="password" name="password"><br>
    <input type="submit" value="登陆"><br>
</form>
</body>
</html>

编写处理请求的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<String, Object> session = ActionContext.getContext().getSession();
            session.put("user", user);


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

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

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

        //存到request域对象中
        Map<String, Object> request = ActionContext.getContext().getContextMap();

        request.put("users", users);

        return "list";
    }

}

struts.xml配置文件

    <package name="xxx" extends="struts-default" >
        <action name="user_*" class="zhongfucheng.action.UserAction" method="{1}" >

            <!--如果登陆成功,重定向到Action中,执行list业务方法-->
            <result name="login" type="redirectAction">user_list</result>

            <!--如果是list,那么跳转到list.jsp页面-->
            <result name="list" >/WEB-INF/list.jsp</result>
        </action>

    </package>

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

我们想要的效果是:只有用户正在调用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


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <package name="xxx" extends="struts-default">

        <interceptors>
            <!--配置自定义的拦截器-->
            <interceptor name="Interceptor1" class="zhongfucheng.Interceptor"/>

            <!--配置拦截器栈,把默认的拦截器栈都加载自定义的拦截器栈中-->
            <interceptor-stack name="myStack">
                <interceptor-ref name="Interceptor1"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>

        </interceptors>


        <!--让Struts执行拦截器-->

        <!--【执行拦截器:第一种写法: 当前包下所有的acntion都执行myStack栈】-->
        <default-interceptor-ref name="myStack"></default-interceptor-ref>


        <!--第二种写法: 只是在这一个Action中执行myStack栈
        <interceptor-ref name="defaultStackt"></interceptor-ref>
        <interceptor-ref name="loginCheck"></interceptor-ref>
        -->

        <!-- 第三种写法:执行用户栈(与第二种写法一样, 只在当前aciton中执行自定义栈) -->
        <!-- <interceptor-ref name="myStack"></interceptor-ref>-->

        <action name="user_*" class="zhongfucheng.action.UserAction" method="{1}">

            <!--如果登陆成功,重定向到Action中,执行list业务方法-->
            <result name="login" type="redirectAction">user_list</result>

            <!--如果是list,那么跳转到list.jsp页面-->
            <result name="list">/WEB-INF/list.jsp</result>


            <!--如果是直接访问Action或者没有用户登陆,返回login页面-->
            <result name="input">/login.jsp</result>

        </action>


    </package>
</struts>

效果:

只有当用户登陆了才能查看用户具体信息,直接访问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.youkuaiyun.com/hon_3y/article/details/54799494#t11


Struts2防止表单重复提交

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

   <interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>

它的实现原理和我们以前写的思路几乎一致…它不需要另外写一个组件来生成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<User> getAll() {

        try {
            String sql = "SELECT * FROM user";
            QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
            return (List<User>) 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<User> 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" %>
<html>
<head>
</head>
<body>

<form action="${pageContext.request.contextPath}/user_register" method="post">
    <table border="1">

        <tr>
            <td>用户名:<input type="text" name="username"></td>
        </tr>
        <tr>
            <td> 密码:<input type="password" name="password"></td>
        </tr>
        <tr>
            <td>电话:<input type="text" name="cellphone"></td>
        </tr>
        <tr>
            <td><input type="submit" value="提交"></td>
        </tr>
    </table>
</form>


</body>
</html>
  • 使用了模型驱动封装数据,添加用户


    //这里一定要实例化
    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" %>
<html>
<head>
    <title>列出下载页面</title>
</head>
<body>
<table border="1" align="center">
    <tr>
        <td>用户id</td>
        <td>用户姓名</td>
        <td>用户密码</td>
        <td>用户电话</td>
        <td>操作</td>
    </tr>

    <s:if test="#request.users!=null">
        <c:forEach items="${users}" var="user">
            <tr>
                <td>${user.id}</td>
                <td>${user.username}</td>
                <td>${user.password}</td>
                <td>${user.cellphone}</td>
                <td><a href="${pageContext.request.contextPath}/user_updatePage?id=${user.id}">修改</a></td>
            </tr>
        </c:forEach>
    </s:if>
</table>


</body>
</html>
  • 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来修改用户的数据

<form action="${pageContext.request.contextPath}/user_update">
    <table border="1">

        <tr>
            <td>用户名<s:textfield name="username"/></td>
        </tr>
        <tr>
            <td>密码 <s:textfield name="password" /></td>
        </tr>
        <tr>
            <td>电话<s:textfield name="cellphone"/></td>
        </tr>
        <s:hidden name="id"/>

        <tr>
            <td><input type="submit" value="修改"></td>
        </tr>
    </table>
</form>

效果

这里写图片描述


防止表单重复提交

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

这里写图片描述

在需要提交的表单上使用token标签


<table border="1">
        <s:token></s:token>
        <tr>
            <td>用户名:<input type="text" name="username"></td>
        </tr>
        <tr>
            <td> 密码:<input type="password" name="password"></td>
        </tr>
        <tr>
            <td>电话:<input type="text" name="cellphone"></td>
        </tr>
        <tr>
            <td><input type="submit" value="提交"></td>
        </tr>
    </table>

在struts配置文件中配置拦截器

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

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


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
        "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <constant name="struts.ui.theme" value="simple"/>
    <package name="xxx" extends="struts-default">



        <action name="user_*" class="zhongfucheng.action.UserAction" method="{1}">

            <interceptor-ref name="defaultStack"/>

            <interceptor-ref name="token">
                <!-- 要拦截的方法! -->
                <param name="includeMethods">register</param>
            </interceptor-ref>

            <!--如果是list,那么就跳转到list的JSP页面-->
            <result name="list"> /list.jsp</result>

            <!--请求跳转到修改页面-->
            <result name="updatePage">/update.jsp</result>

            <!--如果校验成功,跳转到login.jsp页面回显-->
            <result name="success">/login.jsp</result>

            <result name="redirectList" type="redirect">/user_list</result>
        </action>
    </package>

    <include file="config.xml"/>

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

这里写图片描述

测试

这里写图片描述

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

cesium 综合教程200+【目录】(已包含186篇文章) cesium示例教程100+旨在为开发者提供简单快捷的,。在每一个示例中,解释相应的API知识点,做到。目录中有链接的为已有文章,没链接的为目标文章,不断更新中… 阅读详情

相关推荐

XS5018A TX ISP芯片同轴高清模拟输出图像处理芯片用户指南

当看门狗开启且系统异常,看门狗模块得不到喂狗信号时,自动产生看门狗复位信号,复位​​​​​​​。分量上与人眼对光谱的响应通常是有偏差的,通常通过一个色彩校正矩阵校正光谱响应的交叉效。但实际上由于电路的作用,复位模块对整个芯片及各个功能模块的复位进行统一管理,负责产生各个模块的软复位信。每个区域前景色可以在 16 个色表中查找,单个区域的前景色统一,各个区域的前。较弱的坏点被放大成刺眼的白点和明显的黑点,强烈推荐开启动态坏点校正功能。四种制式,通过寄存器配置,可以很方便的实现四种制式的切换、且可以对截止。

2403_88922712的博客 1959

struts2之拦截器详解

文章目录1 拦截器1.1 拦截器是什么1.2 拦截器的优点是什么1.3 预定义拦截器1.3.1 预定义拦截器1.3.1.1 params拦截器1.3.1.2 timer拦截器1.3.1.3 logger拦截器1.3.2 拦截器配置说明1.3.3 拦截器的调用顺序1.3.4 全局拦截器的配置1.3.5 使用execAndWait拦截器1.4 自定义拦截器1.4.1 自定义基础拦截器1.4.2 自定义拦截器示例1.4.3 自定义登录检查拦截器1.4.4 自定义logger拦截器 1 拦截器 1.1 拦截器是什么

上善若泪 2826

华为擎云W515 PGUV-WBY0安装银河麒麟V10全流程解析

本文详细解析了华为擎云W515 PGUV-WBY0安装银河麒麟V10系统的全流程,包括准备工作、镜像下载与校验、启动盘制作、BIOS设置、安装过程关键选择、系统初始化及常见问题排查。特别针对ARM架构设备提供了实用技巧,帮助用户顺利完成国产化系统的部署与优化。

weixin_28725949的博客 696

Struts2之拦截器

Struts2之拦截器

qq_42640067的博客 1523

Ubuntu视频播放器怎么选?VLC、mpv、SMPlayer硬解与字幕配置指南

在Linux系统中,视频播放体验取决于播放器、解码器与显卡驱动的协同。硬件解码通过VA-API或VDPAU将解码任务交给GPU,能显著降低CPU占用,解决4K高码率视频卡顿问题。对于Ubuntu用户,合理配置解码环境与播放器,可流畅播放HEVC、多音轨及ASS特效字幕视频。无论是日常观影、番剧追更还是家庭影院场景,选择合适的播放器并正确启用硬解,都是提升体验的关键。本文围绕Ubuntu平台,详解VLC、mpv、SMPlayer等播放器的安装、硬解配置与常见问题排查,帮助你在Linux上获得流畅的本地视频播放

weixin_33801856的博客 506

USB的24脚和12脚TYPEC引脚定义

USB 是一种接口,用于将设备连接到计算机上。通过该连接,计算机可以向设备发送数据或检索来自设备的数据。USB 为开发者提供了一个标准接口,适用于多种不同类型的应用。借助于系统的设计过程,USB 设备易于连接和使用。本应用笔记会使该过程变得更加简单。以下是本应用笔记中会使用的概念:USB 历史USB 架构USB 物理接口USB 速度USB 电源USB 端点USB 通信协议USB 描述符USB 类设备USB 枚举与配置过程。

易板 1万+

5.Struts 2拦截器(Interceptor)

任何优秀的MVC框架都会提供一些通用的操作,如请求数据的封装、类型转换、数据校验、解析上传的文件、防止表单的多次提交等。 Struts 2将它的核心功能放到拦截器中实现而不是集中在核心控制器中实现,把大部分控制器需要完成的工作按功能分开定义,每个拦截器完成一个功能,而完成这些功能的拦截器可以自由选择、灵活组合,需要哪些只需要在struts.xml指定即可,从而增加了框架的灵活性,有利于系统解耦。 拦截器的方法在Action执行之前或者执行之后自动的执行,从而将通用的操作动态地插入到了可插拔式。

相互学习 共同进步 1039

Windows 11 24H2 系统下,保姆级安装华为 eNSP 模拟器(含依赖软件下载与避坑指南)

本文提供Windows 11 24H2系统下华为eNSP模拟器的完整安装指南,涵盖系统配置调整、依赖软件安装及常见问题解决方案。特别针对新版系统的兼容性问题,提供详细的避坑步骤和优化建议,帮助网络工程师顺利完成eNSP模拟器的部署与使用。

weixin_42567752的博客 428

Struts2的拦截器

关于自定义拦截器的建立

ccb1372098的博客 778

某手 v8.x 签名计算方法(二) sig和__NS_sig3

一、目标 今天的目标是 sig和__NS_sig3,咱们抓个包先 二、步骤 sig目测像是MD5 先jadx搜索 sig= ,没有找到结果。 再试试 sig ,晕倒 6k多个结果,突然灵光一闪,这些参数,必然是要加入到 Map中,那么我们搜索 "sig" 应该就是这个 CPU.getClock,Hook之 var signCls = Java.use('com.yxcorp.xxx.util.CPU'); signCls.getClock.implementation = function(a,b,c

fenfei331的博客 2428

基于YOLOv11的仓库机器人导航系统设计与实现:Amazon Robotics Challenge解决方案

本文将详细介绍一个基于YOLOv11目标检测算法的仓库机器人导航系统,该系统能够准确识别托盘(pallet)和箱子(box),为机器人提供精确的导航信息。而基于深度学习的视觉导航系统能够实时识别环境中的关键物体,如托盘和箱子,从而实现更智能的路径规划和货物搬运。YOLOv11作为YOLO系列的最新演进版本,在检测精度和速度上都有显著提升,非常适合仓储环境中的实时物体检测任务。YOLOv11在保持实时性的同时,提高了对小物体和密集物体的检测能力,这对仓储环境中的托盘和箱子检测尤为重要。

YOLO 303

Struts2拦截器配置(简单的登陆后的权限验证)

简单登陆后的权限验证 1.UserAction public String login(){ //为防止用户重复提交同一请求(当直接在地址栏输入请求时,) session=context.getSession();//首先获取session User userSession=(User)session.get("user...

diku9497的博客 147

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

struts2拦截器(简单)

1.LoginAction.java   package lee; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private String username; private String password; public String getUser...

梦醒2010 131

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Struts2拦截器简单模拟

简单模拟了下Struts2拦截器的原理。 首先定义Interceptor接口: package com.kaso.interceptor; public interface Interceptor { public String intercept(ActionInvocation invocation); } 该接口中引用了ActionInvocation类: p

KasoGG的专栏 585

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Struts2拦截器简单示例

拦截器(Interceptor)是Struts 2的核心组成部分。很多功能(Feature)都是构建在拦截器基础之上的,例如文件的上传和下载、国际化、转换器和数据校验等,Struts 2利用内建的拦截器,完成了框架内的大部分操作。 在Struts 2文档中对拦截器的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制,使开发者可以定义一个特定的功能模块,这个模...

weixin_34237596的博客 141

编写一个简单的Struts2 拦截器

xiaolong0211的专栏 508

Struts2拦截器的一个简单应用

<br />前言:大家都知道Struts2的拦截器和Servlet的过滤器类似.但是个人觉得Struts2的拦截器功能上不如Servlet过滤器的强大.<br />原因有两点: 1、拦截器只能对action进行拦截,而不能拦截JSP页面<br />                 2、拦截器只能在表单提交以后发挥作用,而对直接在地址栏上输入的url无法进行拦截.从而导致不能进行完整的身份认证.<br />在Struts2中我还没有发现能够解决以上两个问题的办法,姑且暂时先用Struts2的拦截器做了一个登陆

mistyGod的"咖啡"世界 1232

Struts2拦截器注解的简单例子

最近开发一个项目,技术架构由spring2+hibernate3+struts2+freemarker搭建。struts2的action视图转发工作,本人觉得用注解直接在代码上配置很方便,想省去了配置struts.xml操作。但就是由于自己懒惰,在开发过程中遇到了一些麻烦,因为对struts2注解的不熟悉,不知道怎样做拦截器的注解,后来经过在网上查资料和自己不断的搞测试,终于把问题搞定了。 下面...

jadewoo的专栏 183

struts2的拦截器的简单使用

struts2的拦截器使用

u010931209的专栏 637

MyEclipse struts2 拦截器处理用户请求简单实例

Struts2简介 Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架。其全新的Struts 2的体系结构与Struts

CjfBlog的博客 1897

struts2实现简单拦截器

struts2实现拦截器的方法有三种:      1:实现Interceptor接口,需要实现init(),destroy(),intercept(ActionInvocation actionInvocation)三个方法。      2:继承AbstractInterceptor,只需要重写intercept(ActionInvocation actionInvocation)方法,他帮我

shizhan1881的专栏 701

struts2简单的自定义interceptor拦截器入门

interceptor拦截器可以对请求在到达Action之前的做出一些预处理,也就是到达Action之前干一些事我们都知道很多网站都有这样的限制,如某宝,只有用户登录了才能查看自己的购物车,订单,收藏夹等,视频网站也会要求你登录以后才能下载视频或文件,就像优快云需要你登录才能下载资料.那么网站是如何知道你有没有登录,又是如何限制用户下载的呢?本文通过简单的案例来入门struts2简单的自定义in...

HHSUVV的博客 377

struts2简单拦截器

前置条件:已完成一个简单的struts2登录实例 1、在src&gt;tool包下新建拦截器实现类MyInterceptor.java package tool; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; im...

zero_130的博客 183

struts2实现简单action时间拦截器

//jsp index.jsp<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+re

大道至简,悟在天成。 608
上一篇: Spring入门这一篇就够了
下一篇: Struts2【OGNL、valueStack】就是这么简单
Java3y
Java3y 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 509原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值