Spring MVC 三层架构和MVC SpringMVC的入门案例 请求参数的绑定 常用的注解 响应数据和结果视图 SpringMVC实现文件上传 SpringMVC的异常处理 SpringMVC框架中的拦截器

三层架构

  1. 咱们开发服务器端程序,一般都基于两种形式,一种C/S架构程序,一种B/S架构程序

  2. 使用Java语言基本上都是开发B/S架构的程序,B/S架构又分成了三层架构

  3. 三层架构

    1. 表现层:WEB层,用来和客户端进行数据交互的。表现层一般会采用MVC的设计模型

  4. 业务层:处理公司具体的业务逻辑的

    1. 持久层:用来操作数据库的

  5. MVC模型

    1. MVC全名是Model View Controller 模型视图控制器,每个部分各司其职。

    2. Model:数据模型,JavaBean的类,用来进行数据封装。

    3. View:指JSP、HTML用来展示数据给用户

    4. Controller:用来接收用户的请求,整个流程的控制器。用来进行数据校验等。

SpringMVC的入门案例

  1. 是一种基于Java实现的MVC设计模型的请求驱动类型的轻量级WEB框架。

  2. Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。

  3. 使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的SpringMVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts2等。

  4. SpringMVC在三层架构中的位置是表现层框架。

SpringMVC的入门程序

  1. 创建WEB工程,引入开发的jar包

  2. 在web.xml配置文件中核心控制器DispatcherServlet

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     3          xmlns="http://java.sun.com/xml/ns/javaee"
     4          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
     5             http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
     6          id="WebApp_ID" version="2.5">
     7     <!-- 配置 spring mvc 的核心控制器 -->
     8     <servlet>
     9         <servlet-name>SpringMVCDispatcherServlet</servlet-name>
    10         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    11         <!-- 配置初始化参数,用于读取 SpringMVC 的配置文件 -->
    12         <init-param>
    13             <param-name>contextConfigLocation</param-name>
    14             <param-value>classpath:SpringMVC.xml</param-value>
    15         </init-param>
    16         <!-- 配置 servlet 的对象的创建时间点:应用加载时创建。
    17         取值只能是非 0 正整数,表示启动顺序 -->
    18         <load-on-startup>1</load-on-startup>
    19     </servlet>
    20     <servlet-mapping>
    21         <servlet-name>SpringMVCDispatcherServlet</servlet-name>
    22         <url-pattern>/</url-pattern>
    23     </servlet-mapping>
    24 </web-app>
  3. 编写springmvc.xml的配置文件

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3        xmlns:mvc="http://www.springframework.org/schema/mvc"
     4        xmlns:context="http://www.springframework.org/schema/context"
     5        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     6        xsi:schemaLocation="http://www.springframework.org/schema/beans
     7             http://www.springframework.org/schema/beans/spring-beans.xsd
     8              http://www.springframework.org/schema/mvc
     9              http://www.springframework.org/schema/mvc/spring-mvc.xsd
    10              http://www.springframework.org/schema/context
    11             http://www.springframework.org/schema/context/spring-context.xsd">
    12     <!-- 配置创建 spring 容器要扫描的包 -->
    13     <context:component-scan base-package="com.itheima"></context:component-scan>
    14 15     <!-- 配置视图解析器 -->
    16     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    17           <!-- 配置前缀和后缀 以后写转发路径的时候直接写文件名就可以了 -->
    18         <property name="prefix" value="/WEB-INF/pages/"></property>
    19         <property name="suffix" value=".jsp"></property>
    20     </bean>
    21 </beans>
  4. 编写index.jsp和HelloController控制器类

    1. index.jsp

    2. HelloController

  5. 在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面

  6. 启动Tomcat服务器,进行测试

入门案例的执行过程分析

  1. 入门案例的执行流程

    1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件

    2. 开启了注解扫描,那么@Controller注解的对象就会被创建

    3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 找到执行的具体方法

    4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件

    5. Tomcat服务器渲染页面,做出响应

  2. 入门案例中的组件

    1. 前端控制器(DispatcherServlet)

  3. 处理器映射器(HandlerMapping)

    1. 处理器(Handler)

  4. 处理器适配器(HandlAdapter)

    1. 视图解析器(View Resolver)

  5. 视图(View)

  6. <mvc:annotation-driven>说明

    在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。

    使 用 mvc:annotation-driven 自动加载 RequestMappingHandlerMapping (处理映射器) 和 RequestMappingHandlerAdapter ( 处 理 适 配 器 ) , 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用mvc:annotation-driven替代注解处理器和适配器的配置。

  7. RequestMapping注解

    1. RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系

    2. RequestMapping注解可以作用在方法和类上

      1. 作用在类上:第一级的访问目录

      2. 作用在方法上:第二级的访问目录

      3. 细节:路径可以不编写 / 表示应用的根目录开始

      4. 细节:${ pageContext.request.contextPath }也可以省略不写,但是路径上不能写 /

    3. RequestMapping的属性

      1. path 指定请求路径的url

      2. value value属性和path属性是一样的

      3. mthod 指定该方法的请求方式

      4. params 指定限制请求参数的条件

        • 例如

          params = {"accountName"},表示请求参数必须有 accountName

          params = {"moeny!100"},表示请求参数中 money 不能是 100。

      5. headers 发送的请求中必须包含的请求头

请求参数的绑定

  1. 请求参数的绑定说明

    1. 绑定机制

      1. 表单提交的数据都是k=v格式的 username=haha&password=123

      2. SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的

      3. 要求:提交表单的name和参数的名称是相同的

    2. 支持的数据类型

      1. 基本数据类型和字符串类型

      • 提交表单的name和参数的名称是相同的、严格区分大小写

      1. 实体类型(JavaBean)

      • 提交表单的name和JavaBean中的属性名称需要一致。

        • 如果一个JavaBean类中包含其他的引用类型

          • 那么表单的name属性需要编写成:对象.属性

            • 例如:address.name

      1. 集合数据类型(List、map集合等)

        • JSP页面List集合编写方式:name="accounts[0].name"

        • JSP页面Map集合编写方式:name="accountMap['one'].name"

请求参数中文乱码的解决

  1. 在web.xml中配置Spring提供的过滤器类

  2.  1 <filter>
     2     <filter-name>CharacterEncodingFilter</filter-name>
     3     <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
     4     <!-- 设置过滤器中的属性值 -->
     5     <init-param>
     6         <param-name>encoding</param-name>
     7         <param-value>UTF-8</param-value>
     8     </init-param>
     9     <!-- 启动过滤器 -->
    10     <init-param>
    11         <param-name>forceEncoding</param-name>
    12         <param-value>true</param-value>
    13     </init-param>
    14 </filter>
    15 16 <!-- 过滤所有请求 -->
    17 <filter-mapping>
    18     <filter-name>CharacterEncodingFilter</filter-name>
    19     <url-pattern>/*</url-pattern>
    20 </filter-mapping>
    21 22 <!--在 springmvc 的配置文件中可以配置,静态资源不过滤:-->
    23 <!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 -->
    24 <mvc:resources location="/css/" mapping="/css/**"/>
    25 <mvc:resources location="/images/" mapping="/images/**"/>
    26 <mvc:resources location="/scripts/" mapping="/javascript/**"/>
    27 <!--    get 请求方式:-->
    28 <!--    tomacat 对 GET 和 POST 请求处理方式是不同的,GET 请求的编码问题,要改 tomcat 的 server.xml-->
    29 <!--    配置文件,如下:-->
    30 <Connector connectionTimeout="20000" port="8080"
    31            protocol="HTTP/1.1" redirectPort="8443"/>
    32         改为:
    33 <Connector connectionTimeout="20000" port="8080"
    34            protocol="HTTP/1.1" redirectPort="8443"
    35            useBodyEncodingForURI="true"/>
    36 <!--    如果遇到 ajax 请求仍然乱码,请把:-->
    37 <!--    useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"-->
    38 <!--    即可。-->

自定义类型转换器

表单提交的任何数据类型全部都是字符串类型,但是后台定义Integer类型,数据也可以封装上,说明Spring框架内部会默认进行数据类型转换。

  1. 如果想自定义数据类型转换,可以实现Converter的接口

    1. 自定义类型转换器

      1. 定义一个类,实现 Converter 接口

        import java.text.DateFormat;
        import java.text.SimpleDateFormat;
        import java.util.Date;
        ​
        public class StringToDateConverter implements Converter<String, Date> {
            /**
             * 用于把 String 类型转成日期类型
             */
            @Override
            public Date convert(String source) {
                DateFormat format = null;
                try {
                    if (StringUtils.isEmpty(source)) {
                        throw new NullPointerException("请输入要转换的日期");
                    }
                    format = new SimpleDateFormat("yyyy-MM-dd");
                    Date date = format.parse(source);
                    return date;
                } catch (Exception e) {
                    throw new RuntimeException("输入日期有误");
                }
            }
        }
        

          

    2. 注册自定义类型转换器,在springmvc.xml配置文件中编写配置

       1 <!-- 配置类型转换器工厂 -->
       2 <bean id="converterService"
       3       class="org.springframework.context.support.ConversionServiceFactoryBean">
       4     <!-- 给工厂注入一个新的类型转换器 -->
       5     <property name="converters">
       6         <array>
       7             <!-- 配置自定义类型转换器 -->
       8             <bean class="com.itheima.web.converter.StringToDateConverter"></bean>
       9         </array>
      10     </property>
      11 </bean>
    3. 在 annotation-driven 标签中引用配置的类型转换服务

      1 <mvc:annotation-driven conversion-service="converterService"></mvc:annotation-driven>
  2. 使用注解转换

    1. 在pojo声明的属性上添加注解@DateTimeFormat(pattern = "yyyy-MM-dd")

    2. 该注解也可以添加在参数前

在控制器中使用原生的ServletAPI对象

  • 只需要在控制器的方法参数定义HttpServletRequest和HttpServletResponse对象

常用的注解

  1. RequestParam注解

    • 作用:把请求中的指定名称的参数传递给控制器中的形参赋值

    • 属性

      1. value:请求参数中的名称

      2. required:请求参数中是否必须提供此参数,默认值是true,必须提供

      3. 代码如下

        public String useRequestParam(@RequestParam("name")String username,@RequestParam(value = "age", required = false)Integer age)
        

          

  2. RequestBody注解

    1. 作用:用于获取请求体的内容(注意:get方法不可以)

    2. 属性

      • required:是否必须有请求体,默认值是true

    3. 代码如下

      public String useRequestBody(@RequestBody(required=false) String body)
      

        

  3. PathVariable注解

    1. 作用:拥有绑定url中的占位符的。例如:url中有/delete/{id},{id}就是占位符,url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。

    2. 属性

      1. value:指定url中的占位符名称

    3. Restful风格的URL

      1. 请求路径一样,可以根据不同的请求方式去执行后台的不同方法

      2. restful风格的URL优点

        1. 结构清晰

        2. 符合标准

        3. 易于理解

        4. 扩展方便

      3. 伪代码优点展示

        /account/1 HTTP GET : 得到 id = 1 的 account 
        /account/1 HTTP DELETE: 删除 id = 1 的 account
        /account/1 HTTP PUT: 更新 id = 1 的 account
        /account HTTP POST: 新增 account
      4. 开启使游览器支持其他请求方式

        1. 在 web.xml 中配置该过滤器。

        2. 请求方式必须使用 post 请求。

        3. 按照要求提供_method 请求参数,该参数的取值就是我们需要的请求方式。

      5. 使用方式

        <!--jsp代码-->
        <!--更新-->
        <form action="springmvc/testRestPUT/1" method="post">
          用户名称:
          <input type="text" name="username">
          <br/>
          <input type="hidden" name="_method" value="PUT">
          <input type="submit" value="更新">
        </form>

        <!--java代码-->
        @RequestMapping(value = "/testRestPUT/{id}", method = RequestMethod.PUT)
        public String testRestfulURLPUT(@PathVariable("id")Integer id,User user){
              System.out.println("rest put "+id+","+user);
              return"success";
        }
    4. 代码如下

      <a href="springmvc/usePathVariable/100">pathVariable 注解</a>

      @RequestMapping("/usePathVariable/{id}")
      public String usePathVariable(@PathVariable("id") Integer id){}
  4. RequestHeader注解

    1. 作用:获取指定请求头的值

    2. 属性:value:请求头的名称

  5. CookieValue注解

    1. 作用:用于获取指定cookie的名称的值

    2. 属性:value:cookie的名称

  6. ModelAttribute注解

    1. 作用

      1. 出现在方法上:表示当前方法会在控制器方法执行前线执行。

      2. 出现在参数上:获取指定的数据给参数赋值。

    2. 应用场景

      1. 当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。

    3. 具体的代码

      1. 修饰的方法有返回值

      2. 修饰的方法没有返回值

  7. SessionAttributes注解

    1. 作用:用于多次执行控制器方法间的参数共享

    2. 属性.

      1. value:指定存入属性的名称

      2. type:用于指定存入的数据类型。

    3. 代码如下

      @Controller("sessionAttributeController")
      @RequestMapping("/springmvc")
      @SessionAttributes(value = {"username", "password"}, types = {Integer.class})
      public class SessionAttributeController {
          /**
           * 把数据存入 SessionAttribute
           *
           * @param model
           * @return Model 是 spring 提供的一个接口,该接口有一个实现类 ExtendedModelMap
           * 该类继承了 ModelMap,而 ModelMap 就是 LinkedHashMap 子类
           */
          @RequestMapping("/testPut")
          public String testPut(Model model) {
              model.addAttribute("username", "泰斯特");
              model.addAttribute("password", "123456");
              model.addAttribute("age", 31);
              //跳转之前将数据保存到 username、password 和 age 中,因为注解@SessionAttribute 中有
              这几个参数
              return "success";
          }
      ​
          @RequestMapping("/testGet")
          public String testGet(ModelMap model) {
      ​
              System.out.println(model.get("username") + ";" + model.get("password") + ";" + model.get("a
                      ge")); 
              return "success";
          }
      ​
          @RequestMapping("/testClean")
          public String complete(SessionStatus sessionStatus) {
              sessionStatus.setComplete();
              return "success";
          }
      }
      

        

响应数据和结果视图

返回值分类

  1. 返回字符串:

    1. Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。

    2. springMVC方式的转发和重定向

      转发:return "forward:/WEB-INF/pages/success.jsp";
      重定向:return "redirect:testReturnModelAndView"
  2. 返回值是void

    1. 如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。

    2. 可以把Servlet 原始 API 可以作为控制器中方法的参数

      public void testReturnVoid(HttpServletRequest request,HttpServletResponse response) 
      throws Exception {}
      1. 然后通过原始的重定向或者内部转发的方式跳转页面

  3. 返回值是ModelAndView对象

    1. ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图

    2. 具体的代码如下

      //实例代码
      public ModelAndView testReturnModelAndView(){
      ModelAndView mv = new ModelAndView();
        mv.addObject("username", "张三");
        mv.setViewName("success");
        return mv;
      }
      //响应的jsp代码
      ${requestScope.username}    
         

ResponseBody响应json数据

需求:使用@ResponseBody 注解实现将 controller 方法返回对象转换为 json 响应给客户端

 1 jsp 中的代码:
 2  3 <script type="text/javascript"      src="${pageContext.request.contextPath}/js/jquery.min.js"></script>
 4 <script type="text/javascript">
 5     $(function () {
 6         $("#testJson").click(function () {
 7             $.ajax({
 8                 type: "post",
 9                 url: "${pageContext.request.contextPath}/testResponseJson",
10                 contentType: "application/json;charset=utf-8",
11                 data: '{"id":1,"name":"test","money":999.0}',
12                 dataType: "json",
13                 success: function (data) {
14                     alert(data);
15                 }
16             });
17         });
18     })
19 </script>
20 <!-- 测试异步请求 --> 
21 <input type="button" value="测试 ajax 请求 json 和响应 json" id="testJson"/>
Controller层java代码:
​
@Controller("jsonController")
public class JsonController {
    /**
     * 测试响应 json 数据
     */
    @RequestMapping("/testResponseJson")
    public @ResponseBody
    Account testResponseJson(@RequestBody Account account) {
        System.out.println("异步请求:" + account);
        return account;
    }
}

  

SpringMVC实现文件上传

文件上传的必要前提

  1. form 表单的 enctype 取值必须是:multipart/form-data

  2. method 属性取值必须是 Post

文件上传的原理分析

当 form 表单的 enctype 取值不是默认值后,request.getParameter()将失效。 enctype=”application/x-www-form-urlencoded”时,form 表单的正文内容是:
key=value&key=value&key=value
当 form 表单的 enctype 取值为 Mutilpart/form-data 时,请求正文内容就变成:
每一部分都是 MIME 类型描述的正文
-----------------------------7de1a433602ac 分界符
Content-Disposition: form-data; name="userName" 协议头
aaa 协议的正文
-----------------------------7de1a433602ac
Content-Disposition: form-data; name="file";
filename="C:UserszhyDesktopfileupload_demofile.txt"
Content-Type: text/
plain 协议的类型(MIME 类型)
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-----------------------------7de1a433602ac--

借助第三方组件实现文件上传

使用 Commons-fileupload 组件实现文件上传,需要导入该组件相应的支撑 jar 包:Commons-fileupload 和commons-io。

实现步骤

  1. 导入文件上传所需jar包

  2. 编写 jsp 页面,表单form标签enctype属性设置为multipart/form-data

  3. 编写控制器

    @Controller("fileUploadController")
    public class FileUploadController {
        /**
         * 文件上传
         */
        @RequestMapping("/fileUpload")
        public String testResponseJson(String picname, MultipartFile
                uploadFile, HttpServletRequest request) throws Exception {
            //定义文件名
            String fileName = "";
            //1.获取原始文件名
            String uploadFileName = uploadFile.getOriginalFilename();
            //2.截取文件扩展名
            String extendName =uploadFileName.substring(uploadFileName.lastIndexOf(".") + 1,uploadFileName.length());
            //3.把文件加上随机数,防止文件重复
            String uuid = UUID.randomUUID().toString().replace("-", "").toUpperCase();
            //4.判断是否输入了文件名
            if (!StringUtils.isEmpty(picname)) {
                fileName = uuid + "_" + picname + "." + extendName;
            } else {
                fileName = uuid + "_" + uploadFileName;
            }
            System.out.println(fileName);
            //2.获取文件路径
            ServletContext context = request.getServletContext();
            String basePath = context.getRealPath("/uploads");
            //3.解决同一文件夹中文件过多问题
            String datePath = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            //4.判断路径是否存在
            File file = new File(basePath + "/" + datePath);
            if (!file.exists()) {
                file.mkdirs();
            }
            //5.使用 MulitpartFile 接口中方法,把上传的文件写到指定位置
            uploadFile.transferTo(new File(file, fileName));
            return "success";
        }
    }
    

      

  4. 配置文件解析器

    1 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    2     <!-- id 的值是固定的-->
    3     <!-- 设置上传文件的最大尺寸为 5MB -->
    4     <property name="maxUploadSize">
    5         <value>5242880</value>
    6     </property>
    7 </bean>

SpringMVC的异常处理

异常处理思路

  1. Controller调用service,service调用dao,异常都是向上抛出的,最终有DispatcherServlet找异常处理器进行异常的处理。

SpringMVC的异常处理

  1. 自定义异常处理器

    public class GlobalExceptionHandle implements HandlerExceptionResolver {
        @Override
        public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
            ModelAndView mav = new ModelAndView();
            mav.addObject("except", e);
            mav.addObject("obj", o);
            //        指定视图
            mav.setViewName("error");
    ​
            return mav;
    ​
        }
    }
    

      

  2. 配置异常处理器

    <!-- 配置自定义异常处理器 --> 
    <bean />

SpringMVC框架中的拦截器

拦截器的概述

  1. SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。

  2. 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链 中的拦截器会按着定义的顺序执行。

  3. 拦截器和过滤器的功能比较类似,有区别

    1. 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。

    2. 拦截器是SpringMVC框架独有的。

    3. 过滤器配置了/*,可以拦截任何资源。

    4. 拦截器只会对控制器中的方法进行拦截。

  4. 拦截器也是AOP思想的一种实现方式

  5. 想要自定义拦截器,需要实现HandlerInterceptor接口。

自定义拦截器步骤

  1. 创建类,实现HandlerInterceptor接口,重写需要的方法

  2. 在springmvc.xml中配置拦截器类

    1 <!-- 配置拦截器 -->
    2 <mvc:interceptors>
    3     <mvc:interceptor>
    4         <mvc:mapping path="/**"/>
    5         <bean id="handlerInterceptorDemo1" class="com.itheima.web.interceptor.HandlerInterceptorDemo1"></bean>
    6     </mvc:interceptor>
    7 </mvc:interceptors>

HandlerInterceptor接口中的方法

  1. preHandle方法是controller方法执行前拦截的方法

    1. 可以使用request或者response跳转到指定的页面

    2. return true放行,执行下一个拦截器,如果没有拦截器,执行controller中的方法。

    3. return false不放行,不会执行controller中的方法。

  2. postHandle是controller方法执行后执行的方法,在JSP视图执行前。

    1. 可以使用request或者response跳转到指定的页面

    2. 如果指定了跳转的页面,那么controller方法跳转的页面将不会显示。

    3. postHandle方法是在JSP执行后执行

      1. request或者response不能再跳转页面了

拦截器的简单案例(验证用户是否登录)

controller层代码:
​
@RequestMapping("/login")
public String login(Model model) throws Exception {
    return "login";
}
​
//登陆提交
//userid:用户账号,pwd:密码
@RequestMapping("/loginsubmit")
public String loginsubmit(HttpSession session, String userid, String pwd) throws
        Exception {
    //向 session 记录用户身份信息
    session.setAttribute("activeUser", userid);
    return "redirect:/main.jsp";
}
​
//退出
@RequestMapping("/logout")
public String logout(HttpSession session) throws Exception {
    //session 过期
    session.invalidate();
    return "redirect:index.jsp";
}
//拦截器代码
​
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //如果是登录页面则放行
        if (request.getRequestURI().indexOf("login.action") >= 0) {
            return true;
        }
        HttpSession session = request.getSession();
        //如果用户已登录也放行
        if (session.getAttribute("user") != null) {
            return true;
        }
        //用户没有登录就跳转到登录页面
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        return false;
    }
}