SpringMVC | Spring MVC中的“拦截器”

目录:

    • 一、拦截器 :
      • 1. 拦截器的 “概述”
      • 2. 拦截器的 “定义” (创建“拦截器”对象)
      • 3. 拦截器的 “配置” (让“拦截器”对象生效)
      • 4. 拦截器的 “执行流程”
        • “单个拦截器”的执行流程
        • “多个拦截器”的执行流程
    • 二、应用案例一实现用户登录权限验证

在这里插入图片描述

作者简介 :一只大皮卡丘,计算机专业学生,正在努力学习、努力敲代码中! 让我们一起继续努力学习!

该文章参考学习教材为:
《Java EE企业级应用开发教程 (Spring + Spring MVC +MyBatis)》 黑马程序员 / 编著
文章以课本知识点 + 代码为主线,结合自己看书学习过程中的理解和感悟 ,最终成就了该文章

文章用于本人学习使用 , 同时希望能帮助大家。
欢迎大家点赞👍 收藏⭐ 关注💖哦!!!

(侵权可联系我,进行删除,如果雷同,纯属巧合)


实际项目中,拦截器使用是非常普遍 的,例如在购物网站中通过 拦截器 可以 拦截未登录的用户禁止其购买商品,或者 使用拦截器验证已登录用户是否有相应操作权限 等。在Struts2框架中,拦截器是其重要的组成部分,而 Spring MVC也提供了拦截器功能,通过配置即可对请求进行拦截处理

一、拦截器 :

1. 拦截器的 “概述”

SpringMVC 中的 拦截器( Interceptor ) 类似于 Servlet中的过滤器( Filter),它主要用于拦截用户请求并做相应的处理。例如通过拦截器可以进行 权限验证记录请求信息日志判断用户是否登录 等。

2. 拦截器的 “定义” (创建“拦截器”对象)

  • 要使用 SpringMVC中的拦截器,就需要对拦截器类进行定义配置。通常拦截器类可以通过 两种方式来定义

    • 一种是通过 实现 HandlerInterceptor接口,或 继承 HandlerInterceptor接口实现类HandlerInterceptorAdapter 来定义;
    • 另一种是通过 实现 WebRequestInterceptor接口,或 继承 WebRequestInterceptor接口实现类 来定义。
  • 例子如 :(实现HandlerInterceptor接口的方式来实现SpringMVC拦截器) :

    //通过实现HandlerInterceptor接口的方式来实现SPringMVC拦截器
    public class CustomerInterceptor implements HandlerInterceptor { //该方法在“控制器方法”之前执行,其返回值表示“是否中断后续操作”@Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o) throws Exception {return false;}//该方法在“控制器方法”之后执行,且“解析视图”之前执行(可通过该方法对“模型和视图”进一步修改)@Overridepublic void postHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {}//该方法在“整个请求”完成之后执行,即“视图渲染结束”之后执行(通过该方法可进行“资源清理、记录日志信息等”)@Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {}
    }
    

    上述代码可以看出,自定义拦截器类实现了HandlerInterceptor接口,并实现了 接口中的三个方法 。 关于这 三个方法具体描述 如下 :

    方法描述
    preHandler()方法该方法会在 控制器方法 之前执行,其 返回值 表示 是否中断后续操作
    当其返回值true 时,表示 继续向下执行
    当其返回值false 时,会 中断后续的所有操作 (包括调用下一个拦截器控制器类中的方法执行等)。
    postHandle()方法方法会在 控制器方法 之后执行,且 解析视图 之前执行。可以通过此方法请求域中的 模型视图 做出 进一步的修改
    afterCompletion()方法方法整个请求完成之后执行,即 视图渲染结束 之后执行。可以通过此方法实现一些资源清理记录日志信息等。

    要想让刚创建好的 拦截器”生效,就要在 springmvc-config.xml中进行配置让“拦截器”生效

3. 拦截器的 “配置” (让“拦截器”对象生效)

  • 使自定义拦截器生效,还需要在SpringMVC配置文件 : springmvc-config.xml 中进行配置

  • SpringMVC拦截器配置元素图 如下所示

    在这里插入图片描述

  • SpringMVC拦截器“在==springmvc-config.xml”== 中==配置代码== 如下所示

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置拦截器 --><mvc:interceptors><!-- 配置“全局拦截器”,拦截所有请求 --><bean class="com.myh.interceptor.CustomerInterceptor"/><!-- 配置“普通拦截器1”,拦截“指定路径”/“指定请求” --><mvc:interceptor><!-- 需要拦截的路径 --><mvc:mapping path="/**"/><bean class="com.myh.interceptor.CustomerInterceptor1"/></mvc:interceptor><!-- 配置“普通拦截器2” --><mvc:interceptor><!-- 需要拦截的路径 --><!-- 拦截所有以 /hello 结尾的路径 --><mvc:mapping path="/hello"/><bean class="com.myh.interceptor.CustomerInterceptor2"/></mvc:interceptor>.....</mvc:interceptors>
    </beans>
    

    上述配置代码中,<mvc:interceptors>元素用于配置一组拦截器,其子元素<bean>中定义的
    全局拦截器
    ,它会拦截所有的请求;而 <mvc:interceptor>元素 中定义的是指定路径拦截器
    它会对指定路径下的请求生效<mvc:interceptor> 元素子元素<mvc:mapping>用于配置拦截
    器作用路径,该路径在其属性path中定义。如上述代码中path属性值“/”** 表示拦截所有路径,“hello"表示拦截所有以"hello" 结尾的路径。如果在请求路径中包含不需要拦截的内容,还可以通过 <mvc:exclude- mapping>元素进行配置

    注意点 :
    需要注意的是,<mvc:interceptor>中的子元素必须按照上述代码配置顺序进行编写,即 <mvc:mapping> —> <mvc:exclude-mapping> —> <bean>顺序否则文件会报错

4. 拦截器的 “执行流程”

“单个拦截器”的执行流程
  • 运行程序 时,拦截器的执行一定顺序 的,该 顺序配置文件中所定义拦截器的顺序 相关。如果在项目只定义了一个拦截器,那么该拦截器程序中执行流程如图 如下图所示 :
    在这里插入图片描述

    上图 可以看出程序首先执行拦截器类 中的 preHandle( )方法,如果该方法的 返回值true ,则程序继续向下执行 处理器类中的方法否则不会向下执行 ,后执行 控制器类中方法
    执行完“控制器类中方法”后,会执行“拦截器类”中的 postHandle( )方法,然后会通过DispatcherServlet各户端返回响应;在DispatcherServlet处理完请求后,才会执行
    afterCompletion( )方法

  • 单个拦截器”的执行流程 例子如 :

    第一步创建项目,导入依赖
    Spring MVC所需JAR (百度网盘)

    第二步 :配置 SpringMVC拦截器相关文件 :

    web.xml :

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!-- 配置"前端过滤器"--><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--  配置springmvc-config.xml配置文件的位置 (上下文配置位置) --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-config.xml</param-value></init-param><!--  配置启动服务器时加载此配置文件,加载此servlet --><load-on-startup>1</load-on-startup></servlet><!--  配置Servlet的Mapper映射  --><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>
    

    springmvc-config.xml :

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置组件扫描,进行根包扫描,让注解生效 --><context:component-scan base-package="com.myh.controller"/><!-- 配置视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/WEB-INF/jsp/"/><!-- 后缀 --><property name="suffix" value=".jsp"/></bean><!-- 配置SpringMVC 拦截器 --><mvc:interceptors><!-- 全局拦截器,会拦截所有请求 --><bean class="com.myh.interceptor.CustomerInterceptor"/></mvc:interceptors></beans>
    

    HelloController.java (控制器类) :

    package com.myh.controller;import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;@Controller //标记该类为控制器类
    public class HelloController {/*** 页面跳转*/@RequestMapping("/hello")public String Hello() {System.out.println("HelloController...Hello()");return "success"; //响应一个页面给前端}
    }
    

    CustomerInterceptor.java (拦截器对象) :

    package com.myh.interceptor;import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;public class CustomerInterceptor implements HandlerInterceptor { //通过实现HandlerInterceptor接口的方式来实现SPringMVC拦截器//该方法在“控制器方法”之前执行,其返回值表示“是否中断后续操作”@Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object handler) throws Exception {//对拦截的请求放行return true;}//该方法在“控制器方法”之后执行,且“解析视图”之前执行(可通过该方法对“模型和视图”进一步修改)@Overridepublic void postHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("CustomerInterceptor...postHandle()");}//该方法在“整个请求”完成之后执行,即“视图渲染结束”之后执行(通过该方法可进行“资源清理、记录日志信息等”)@Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object handler, Exception e) throws Exception {System.out.println("CustomerInterceptor...afterCompletion()");}
    }
    

    success.jsp :

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>success.jsp页面</title>
    </head>
    <body>
    ok
    </body>
    </html>
    

    启动服务器前端访问 /hello控制台打印内容为
    在这里插入图片描述

    上图可以看出,程序先执行了拦截器类中的 preHandle( )方法,然后执行了控制器中Hello( )方法,最后分别执行了拦截器类中的 postHandle( )方法afterCompletion( )方法。这 上文所描述单个拦截器的执行顺序一致的

“多个拦截器”的执行流程
  • 大型的企业级项目 中,通常 不会只有一个拦截器开发人员可能会定义 多个拦截器实现不同的功能
    多个拦截器执行顺序 如下图
    在这里插入图片描述

    上图可以看出,当有 "多个拦截器"同时工作 时,它们的 preHandle( )方法 会按照配置文件中 拦截器"配置顺序"执行,而它们的 postHandle( )方法afterCompletion( )方法 则会按照 配置顺序反序执行

  • 多个拦截器执行流程 例子如 :

    第一步创建项目,导入依赖
    Spring MVC所需JAR (百度网盘)

    第二步 :配置 SpringMVC拦截器相关文件 :

    web.xml :

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!-- 配置"前端过滤器"--><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--  配置springmvc-config.xml配置文件的位置 (上下文配置位置) --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-config.xml</param-value></init-param><!--  配置启动服务器时加载此配置文件,加载此servlet --><load-on-startup>1</load-on-startup></servlet><!--  配置Servlet的Mapper映射  --><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>
    

    springmvc-config.xml :

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置组件扫描,进行根包扫描,让注解生效 --><context:component-scan base-package="com.myh.controller"/><!-- 配置视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/WEB-INF/jsp/"/><!-- 后缀 --><property name="suffix" value=".jsp"/></bean><!--  定义两个拦截器  --><mvc:interceptors><!--  拦截器1  --><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.myh.interceptor.Interceptor1"/></mvc:interceptor><!--  拦截器2 --><mvc:interceptor><mvc:mapping path="/hello"/><bean class="com.myh.interceptor.Interceptor2"/></mvc:interceptor></mvc:interceptors></beans>
    

    上述拦截器配置代码中,第一个拦截器会作用于所有路径下请求,而 第二个拦截器 会作用于以 “hello" 结尾请求

    HelloController.java (控制器类) :

    package com.myh.controller;import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;@Controller //标记该类为控制器类
    public class HelloController {/*** 页面跳转*/@RequestMapping("/hello")public String Hello() {System.out.println("HelloController...Hello()");return "success"; //响应一个页面给前端}
    }
    

    Interceptor1.java (拦截器对象1) :

    package com.myh.interceptor;import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    /*** 如果有多个拦截器,preHandle()方法按照拦截器的“顺序执行”,* postHandle()方法 和 afterCompletion()方法按照拦截器的“逆序执行”*/
    public class Interceptor1 implements HandlerInterceptor {//以实现HandlerInterceptor接口的方式定义拦截器@Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o) throws Exception {System.out.println("Interceptor1...preHandle()");return true;   //对拦截的请求放行}@Overridepublic void postHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {System.out.println("Interceptor1...postHandle()");}@Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {System.out.println("Interceptor1...afterCompletion()");}
    }
    

    Interceptor2.java (拦截器对象2) :

    package com.myh.interceptor;import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;/*** 如果有多个拦截器,preHandle()方法按照拦截器的“顺序执行”,* postHandle()方法 和 afterCompletion()方法按照拦截器的“逆序执行”*/
    public class Interceptor2 implements HandlerInterceptor {//以实现HandlerInterceptor接口的方式定义拦截器@Overridepublic boolean preHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o) throws Exception {System.out.println("Interceptor2...preHandle()");return true;   //对拦截的请求放行}@Overridepublic void postHandle(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {System.out.println("Interceptor2...postHandle()");}@Overridepublic void afterCompletion(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {System.out.println("Interceptor2...afterCompletion()");}
    }
    

    success.jsp :

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>success.jsp页面</title>
    </head>
    <body>
    ok
    </body>
    </html>
    

    启动服务器前端访问 /hello控制台打印内容为
    在这里插入图片描述

    控制体输出信息可以看出,程序 先执行前两个拦截器类 中的 preHandle( )方法,这 两个方法执行顺序配置文件中定义顺序相同;然后执行了控制器类中的 Hello( )方法; 最后执行了两个拦截器类中的 postHandle( )方法afterCompletion( )方法 ,且这两个方法的 执行顺序 与配置文件中所 定义 的拦截器 顺序相反

二、应用案例一实现用户登录权限验证

  • 下面将通过 拦截器 来完成一个 用户登录权限验证案例本案例中,只有登录后用户才能访问系统中的主页面,如果 没有登录系统直接访问主页面,则 拦截器会将请求拦截并转发到登录页面,同时在登录页面中给出提示信息。如果 用户名或密码错误,也会在登录页面给出 相应的提示信息。当 已登录的用户 在系统主页中单击 “退出” 链接时,系统同样会 回到登录页面

  • 案例整个执行流程 如下图所示 : ( 用户权限验证的执行流程图 ) :
    在这里插入图片描述

  • 案例具体代码第一步创建项目,导入依赖
    Spring MVC所需JAR (百度网盘)

    第二步应用案例实现用户登录权限验证相关代码文件 :

    User.java

    package com.myh.po;
    public class User {
    private Integer id;private String username;private String password;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
    }
    

    UserController.java : (控制器类

    package com.myh.controller;import com.myh.po.User;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;import javax.servlet.http.HttpSession;@Controller
    public class UserController {/*** 向用户登录页面跳转*/@RequestMapping(value = "/toLogin",method = RequestMethod.GET)public String toLogin() {return "login";}/*** 用户登录*/@RequestMapping(value = "/login",method = RequestMethod.POST)public String login(User user, Model model, HttpSession session) { //Model用于传递属性值//获取用户名和密码String username = user.getUsername();String password = user.getPassword();//此处模拟从数据库中获取用户名和密码后进行判断if (username != null && username.equals("tom") && password != null && password.equals("123")) {//将对象添加到Session中session.setAttribute("USER_SESSION",user); //存session// redirect:/main : 表示用户应被“重定向”到 "/main"的URL(或视图),此处为重定向到/main这个URLreturn "redirect:main"; //重定向到“主页面”的"跳转方法"}model.addAttribute("msg", "用户名或密码错误,请重新登录!");return "login"; //因为没登录成功,所以重新回到login.jsp页面}/*** 向主页面跳转*/@RequestMapping(value = "/main")public String toMain() {return "main";}/*** 退出登陆*/@RequestMapping(value = "/logout")public String logout(HttpSession session) {//清除sessionsession.invalidate();//重定向到“登录页面”的“跳转方法”return "redirect:/toLogin";}
    }
    

    LoginInterceptor.java : (拦截器类

    package com.myh.interceptor;
    import com.myh.po.User;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;/*** 登录拦截器*/
    public class LoginInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//获取请求的URLString url = request.getRequestURI();//url:除了login.jsp可以公开访问的,其他的url都要进行拦截控制if ((url.indexOf("/toLogin") >= 0) |(url.indexOf("/login") >= 0) ) { //整体意思: 判断url中是否包含/login(包含则证明是关于“登录的请求”,给予放行)return true; //只有/login请求才能被放行,其他都要进行拦截 (如果是/login则返回值true,下面的代码就不用执行了)}/*** 没有被前面的if语句拦截,说明url请求不是/login,就判断是否已经登录过了(判断session中是否有登录对象数据)*///获取SessionHttpSession session = request.getSession();User user = (User)session.getAttribute("USER_SESSION");//判断Session中是否有用户数据,如果有返回true,继续向下执行if (user != null) {return true;}//没被上面的if语句拦截,说明没有进行登录,Session中查不到登录信息,最后转发到登录页面request.setAttribute("msg","您还没有登录,请先登录!");/*调用getRequestDispatcher对象的 .forward(request,response)来进行请求转发,将当前的请求对象和响应对象转发到"指定的资源" : /WEB-INF/jsp/login.jsp*/request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);return false; //拦截请求}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception {}
    }
    

    文件preHandle( )方法中,先获取了请求的URL,然后通过indexOf( )方法判断URL是否 有 “/login” 字符串“/toLogin” 字符串 。如果,则返回true,即 直接放行;如果没有,则继续向下进
    行拦截处理。接下来获取了Session中的用户信息,如果Session中包含用户信息,即表示用户已登录,也直接放行;否则会转发到登录页面不再执行后续程序

    main.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>系统主页</title>
    </head>
    <body>
    <%-- 用{ }获得存在session中的数据 --%>当前用户: ${USER_SESSION.username}
    <a href="${pageContext.request.contextPath}/logout">退出</a>
    </body>
    </html>
    

    login.jsp :

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head><title>用户登录</title>
    </head>
    <body>
    <span style="color: red"> ${msg}</span><form action="${pageContext.request.contextPath}/login" method="post">用户名:<input type="text" name="username"></br>&nbsp;&nbsp;码:<input type="password" name="password"/></br><input type="submit" value="登录"></form>
    </body>
    </html>
    

    项目发布 Tomcat服务器启动,在浏览器中访问地址”http://localhost:8080/main“,其显示效果如下图所示 :
    在这里插入图片描述

    从上图可以看出,当 用户未登录直接访问主页面时,访问请求会被登录拦截器拦截,从而跳转到登录页面,并提示用户未登录信息。如果在用户名输入框中输入"jack’" ,密码框中输入“123456",当单击 “登录”按钮后,浏览器的显示结果下图所示 :
    在这里插入图片描述

    输入正确的用户名tom密码123456”,并单击“登录”按钮后,浏览器跳转到系统主页面如下图所示
    在这里插入图片描述

    单击“退出”链接后,用户即可退出当前系统,系统会从主页面重定向到登录页面

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/769988.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ssm006基于java的少儿编程网上报名系统+vue

少儿编程网上报名系统 摘 要 在国家重视教育影响下&#xff0c;教育部门的密确配合下&#xff0c;对教育进行改革、多样性、质量等等的要求&#xff0c;使教育系统的管理和运营比过去十年前更加理性化。依照这一现实为基础&#xff0c;设计一个快捷而又方便的网上少儿编程网上…

利用PSR,三步实现业务快速加载

01 什么是PSR PSR是通信业界在BSS/OSS域面向产品设计和业务开通过程中提出的一个标准化信息分层解耦和映射的框架&#xff0c;按照国际电信论坛TMF推荐的SID信息框架的标准&#xff0c;主要分为产品域、服务域和资源域等三层&#xff0c;支撑通信业务的快速加载和敏捷开通。 TM…

vscode下c++的boost库安装

Boost Downloadshttps://www.boost.org/users/download/下载最新的库文件。在shell中&#xff0c;使用命令bootstrap.bat gcc生成b2.exe文件。然后是.\b2.exe toolsetgcc生成库文件&#xff0c;在stage\lib文件夹下把stage\lib文件夹中的库文件拷贝到mingw64\x86_64-w64-mingw3…

Spring Boot + MyBatis

一、配置依赖 <!-- MyBatis --> <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.5.3</version> </dependency> <!-- junit测试依赖 --&g…

【C语言】【Leetcode】88. 合并两个有序数组

文章目录 一、题目二、思路再思考 一、题目 链接: link 二、思路 这题属于简单题&#xff0c;比较粗暴的做法就是直接比较两个数组&#xff0c;先把第二个数组加到第一个的后面&#xff0c;如何冒泡排序&#xff0c;这种方法简单粗暴但有效&#xff0c;可是不适用于这题&…

Python利用Turtle小乌龟实现推箱子游戏

文章目录&#xff1a; 一&#xff1a;运行效果 1.演示 2.思路和功能 二&#xff1a;代码 文件架构 level.py PushBox.py 必备知识&#xff1a;python图形化编程turtle小乌龟 一&#xff1a;运行效果 1.演示 效果图◕‿◕✌✌✌ Python利用Turtle小乌龟实现推箱子游戏运…

python5:基于多进程的并发编程、基于协程的并发编程的学习笔记

进程 为什么要使用多进程&#xff1f;——GIL的存在&#xff0c;多线程实际不是并发执行 将任务分为两类&#xff1a;IO密集型&#xff08;多线程&#xff09;CPU密集型&#xff08;多进程&#xff09; 多进程的基本用法 concurrent.futures.process.ProcessPoolExecutor#进…

程序员35岁会失业吗?‍

程序员35岁会失业吗&#xff1f;&#x1f468;‍&#x1f4bb;&#x1f552; 程序员35岁会失业吗&#xff1f;&#x1f468;‍&#x1f4bb;&#x1f552;摘要引言技术更新与个人适应性持续学习的重要性实用学习方法 职业发展路径多样性职业转型的机会实践案例分享 企业文化与就…

【SpringBoot】如何定义接口

定义get接口 使用GetMapping定义一个基本get接口 RestController //表示定义一个json格式返回给前端 public class test {private Map<String,Object> map new HashMap<>();GetMapping(value "/test") //定义接口路径public Object userInfo(Strin…

代码随想录训练营Day32:● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

122.买卖股票的最佳时机II 题目链接 https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/description/ 题目描述 思路 看完视频讲解之后豁然开朗啊简直了&#xff01;&#xff01;&#xff01; 统计后一天减去前一天&#xff0c;差值为正数的&#xff0c;再…

图论基础|417. 太平洋大西洋水流问题、827.最大人工岛、127. 单词接龙

目录 417. 太平洋大西洋水流问题 827.最大人工岛 127. 单词接龙 417. 太平洋大西洋水流问题 题目链接(opens new window) 有一个 m n 的矩形岛屿&#xff0c;与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界&#xff0c;而 “大西洋” 处于大陆的右边界…

css的active事件在手机端不生效的解决方法

需求&#xff1a;需求就是实现点击图中的 “抽奖” 按钮&#xff0c;实现一个按钮Q弹的放大缩小动画 上面是实现的效果&#xff0c;pc端&#xff0c;点击触发 :active 问题&#xff1a;但是这种方式在模拟器上可以&#xff0c;真机H5一调试就没生效了&#xff0c;下面是简单…

数据结构·二叉树(1)

目录 1 树的概念及结构 1.1 树的结构 1.2 树的概念 1.3树的表示 2 二叉树的概念及结构 2.1二叉树的概念 2.2 特殊的二叉树 2.3 二叉树的存储结构 1 树的概念及结构 1.1 树的结构 前面所学到的顺序表链表等&#xff0c;都是线性的数据结构&#xff0c;今天介绍的树&am…

电脑卸载软件怎么清理干净?电脑清理的5种方法

随着我们在电脑上安装和卸载各种软件&#xff0c;很多时候我们会发现&#xff0c;即使软件被卸载&#xff0c;其残留的文件和注册表项仍然存在于电脑中&#xff0c;这不仅占用了宝贵的磁盘空间&#xff0c;还可能影响电脑的性能。那么&#xff0c;如何确保在卸载软件时能够彻底…

mysql - 缓存

缓存 InnoDB存储引擎在处理客户端的请求时&#xff0c;当需要访问某个页的数据时&#xff0c;就会把完整的页的数据全部加载到内存中&#xff0c;也就是说即使我们只需要访问一个页的一条记录&#xff0c;那也需要先把整个页的数据加载到内存中。将整个页加载到内存中后就可以…

计算机三级——网络技术(综合题第五题)

第一题 填写路由器RG的路由表项①至④。 目的网络&#xff0f;掩码长度输出端口输出端口172.19.63.192&#xff0f;30S0(直接连接)172.19.63.188&#xff0f;30S1(直接连接) 路由器RG的S0的IP地址是172.19.63.193&#xff0c;路由器RE的S0的IP地址是172.19.63.194。 【解析】…

VPCFormer:一个基于transformer的多视角指静脉识别模型和一个新基准

文章目录 VPCFormer:一个基于transformer的多视角指静脉识别模型和一个新基准总结摘要介绍相关工作单视角指静脉识别多视角指静脉识别Transformer 数据库基本信息 方法总体结构静脉掩膜生成VPC编码器视角内相关性的提取视角间相关关系提取输出融合IFFN近邻感知模块(NPM) patch嵌…

【C++】虚拟继承 组合

目录 一、虚拟继承 &#x1f31f;【非虚拟内存分布】 &#x1f31f;【虚拟继承内存分布】 &#x1f31f;【虚拟继承读取】 &#x1f31f;【练习检验】 &#x1f31f;【继承的总结和反思】 二、组合 &#x1f31f;【继承和组合】 &#x1f31f;【前言回顾】 上一篇文章我们…

MATLAB和ROS联合仿真参考资料

参考文章&#xff1a; MATLAB和ROS联合仿真篇&#xff08;从MATLAB获取ROS信息&#xff09;链接

每日一题|djwcb【算法赛】|字符串快速幂

每日一题|djwcb【算法赛】 djwcb 心有猛虎&#xff0c;细嗅蔷薇。你好朋友&#xff0c;这里是锅巴的C\C学习笔记&#xff0c;常言道&#xff0c;不积跬步无以至千里&#xff0c;希望有朝一日我们积累的滴水可以击穿顽石。 djwcb 注意&#xff1a; 快速幂字符串&#xff0c;看…