SpringMVC——核心技术:拦截器(一个/多个、权限拦截器)

简介: SpringMVC——核心技术:拦截器(一个/多个、权限拦截器)

文章目录:


1.介绍

2.一个拦截器的实例 

2.1 控制器类 

2.2 拦截器类

2.3 springmvc配置文件

2.4 web.xml

2.5 index.jsp

2.6 other.jsp

2.7 执行结果

2.7.1 访问index.jsp的页面

2.7.2 index.jsp页面提交用户请求、转到other.jsp的页面 

2.7.3 IDEA中得到拦截器类的输出结果 

3.多个拦截器的实例

3.1 控制器类

3.2 两个拦截器类

3.3 springmvc配置文件

3.4web.xml文件与上面的例子相同

3.5 index.jsp

3.6 result.jsp

3.7 运行结果 

4.权限拦截器(简单的应用小实例)

4.1 控制器类

4.2 拦截器类

4.3 springmvc配置文件、web.xml文件与第一个例子是一样的

4.4 首页index.jsp

4.5 result.jsp(用于显示index.jsp页面的提交结果)

4.6 登录、登出页面(login.jsplogout.jsp

4.7 非用户无法登录页面(tips.jsp

4.8 运行结果 

5.写在结尾

1.介绍


SpringMVC中的 Interceptor 拦截器是非常重要和相当有用的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。其拦截的时间点在处理器映射器根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器执行处理器之前。当然,在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链,并返回给了中央调度器。

拦截器其实就是springmvc框架中的一种对象,需要实现HandlerInterceptor 接口,拦截用户的请求、controller的请求。

拦截用户的请求可以预先对请求做处理,根据处理结果,决定是否执行 controller;也可以把多个 controller 中公用的功能定义到拦截器

拦截器的定义:1)创建一个类实现 HandlerInterceptor 接口,实现接口中的三个方法。

                        2)在springmvc配置文件中,声明拦截对象,并指定拦截的 uri 地址。

2.一个拦截器的实例


2.1 控制器类 

package com.songzihao.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
/**
 *
 */
@Controller
public class MyController {
    @RequestMapping(value = "/some.do")
    public ModelAndView doSome(HttpSession session,String name, Integer age) {
        System.out.println("执行了MyController的doSome()方法");
        //添加一个临时数据
        session.setAttribute("attr","控制器中新增加的临时数据");
        ModelAndView mv=new ModelAndView();
        mv.addObject("myName",name);
        mv.addObject("myAge",age);
        mv.setViewName("result");
        return mv;
    }
}

2.2 拦截器类

注释写的很详细了!!! 

package com.songzihao.handler;
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;
import java.util.Date;
/**
 *
 */
public class MyInterceptor implements HandlerInterceptor {
    /**
     *  preHandle: 预先处理请求的方法
     *  参数: Object handler: 被拦截的控制器对象(MyController)
     *       返回值boolean: true 表示请求正确,控制器方法会被执行
     *                     false 表示请求不正确,控制器方法不会被执行
     *  特点: 1.预处理方法的执行时间在控制器方法之前
     *       2.可以对请求做处理,可以做登录的检查、权限的判断、统计数据等
     *       3.决定请求是否执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("===MyInterceptor拦截器的preHandle===");
        //request.getRequestDispatcher("/tips.jsp").forward(request,response);
        return true;
    }
    /**
     *  postHandle: 后处理方法
     *  参数: Object handler: 被拦截的控制器对象(MyController)
     *       ModelAndView: 控制器方法的返回值(请求的执行结果)
     *  特点: 1.在控制器方法之后执行的
     *       2.能获取控制器方法的执行结果,可以修改原来的执行结果(数据、视图)
     *       3.可以看作对请求的二次处理
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception {
        System.out.println("===MyInterceptor拦截器的postHandle===");
        //对请求做二次处理
        if(mv!=null) {
            mv.addObject("myDate",new Date());
            mv.setViewName("other");
        }
    }
    /**
     *  afterCompletion: 最后执行的方法
     *  参数: Object handler: 被拦截的控制器对象(MyController)
     *       Exception: 异常对象
     *  特点: 1.在请求处理完成后执行的(请求处理完成的标志是视图处理完成、对视图执行完forward操作后)
     *       2.可以做程序最后要做的工作(释放内存、清理临时变量)
     *       3.方法的执行条件: 1) 当前拦截器的 preHandle() 方法必须执行
     *                      2) 当前拦截器的 preHandle() 方法必须返回true
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("===MyInterceptor拦截器的afterCompletion===");
        //获取临时数据
        HttpSession session=request.getSession();
        Object attr=session.getAttribute("attr");
        System.out.println("attr===" + attr);
        //删除临时数据
        session.removeAttribute("attr");
        //判断数据是否已被删除
        attr=session.getAttribute("attr");
        System.out.println("attr===" + attr);
    }
}

2.3 springmvc配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- springmvc的配置文件 -->
    <context:component-scan base-package="com.songzihao.controller" />
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <mvc:annotation-driven />
    <!-- 声明拦截器 -->
    <mvc:interceptors>
        <!-- 声明第一个拦截器 -->
        <mvc:interceptor>
            <!--
                指定拦截器的拦截地址
                path: 拦截器的uri地址,使用 ** 通配符
            -->
            <mvc:mapping path="/**"/>
            <!-- 指定使用的拦截器 -->
            <bean class="com.songzihao.handler.MyInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>
</beans>

2.4 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">
    <!-- 声明springmvc的核心对象 -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 自定义配置文件的位置 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <!-- tomcat服务器创建对象的顺序,数值(大于等于0)越小,创建对象的时间就越早 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <!-- 意思是将 *.do 的请求交给 DispatcherServlet 处理 -->
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

2.5 index.jsp

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
<head>
    <title>$</title>
</head>
<body>
    <p>一个拦截器</p>
    <form action="some.do" method="post">
        姓名:<input type="text" name="name"><br/>
        年龄:<input type="text" name="age"><br/>
        操作:<input type="submit" value="提交">
    </form>
</body>
</html>

2.6 other.jsp

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
<head>
    <title>$</title>
</head>
<body>
    /WEB-INF/view/other.jsp,显示request作用域中的数据<br/>
    <h3>myName数据:${myName}</h3>
    <h3>myAge数据:${myAge}</h3>
    <h3>myDate数据:${myDate}</h3>
</body>
</html>

2.7 执行结果

2.7.1 访问index.jsp的页面

2.7.2 index.jsp页面提交用户请求、转到other.jsp的页面 

2.7.3 IDEA中得到拦截器类的输出结果 

IDEA中的输出结果,大家对照拦截器类中的注释,就可以看懂啦!!!

当拦截器类中的 preHandle 方法返回 true 时,请求的执行顺序:用户发起some.do → preHandle → 控制器的doSome方法 → postHandle → afterCompletion

当拦截器类中的 preHandle 方法返回 false 时,请求仅仅只会执行 preHandle 方法。

3.多个拦截器的实例


3.1 控制器类

package com.songzihao.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
/**
 *
 */
@Controller
public class MyController {
    @RequestMapping(value = "/some.do")
    public ModelAndView doSome(HttpSession session,String name, Integer age) {
        System.out.println("执行了MyController的doSome()方法");
        ModelAndView mv=new ModelAndView();
        mv.addObject("myName",name);
        mv.addObject("myAge",age);
        mv.setViewName("result");
        return mv;
    }
}

3.2 两个拦截器类

package com.songzihao.handler;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 *
 */
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("===MyInterceptor111111拦截器的preHandle===");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception {
        System.out.println("===MyInterceptor111111拦截器的postHandle===");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("===MyInterceptor111111拦截器的afterCompletion===");
    }
}
package com.songzihao.handler;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 *
 */
public class MyInterceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("===MyInterceptor222222拦截器的preHandle===");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception {
        System.out.println("===MyInterceptor222222拦截器的postHandle===");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("===MyInterceptor222222拦截器的afterCompletion===");
    }
}

3.3 springmvc配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- springmvc的配置文件 -->
    <context:component-scan base-package="com.songzihao.controller" />
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/" />
        <property name="suffix" value=".jsp" />
    </bean>
    <mvc:annotation-driven />
    <!-- 声明拦截器 -->
    <mvc:interceptors>
        <!-- 声明第一个拦截器 -->
        <mvc:interceptor>
            <!--
                指定拦截器的拦截地址
                path: 拦截器的uri地址,使用 ** 通配符
            -->
            <mvc:mapping path="/**"/>
            <!-- 指定使用的拦截器 -->
            <bean class="com.songzihao.handler.MyInterceptor" />
        </mvc:interceptor>
        <!-- 声明第二个拦截器 -->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.songzihao.handler.MyInterceptor2"/>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>

3.4web.xml文件与上面的例子相同


3.5 index.jsp

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
<head>
    <title>$</title>
</head>
<body>
    <p>多个拦截器</p>
    <form action="some.do" method="post">
        姓名:<input type="text" name="name"><br/>
        年龄:<input type="text" name="age"><br/>
        操作:<input type="submit" value="提交">
    </form>
</body>
</html>

3.6 result.jsp

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
<head>
    <title>$</title>
</head>
<body>
    /WEB-INF/view/result.jsp,显示request作用域中的数据<br/>
    <h3>myName数据:${myName}</h3>
    <h3>myAge数据:${myAge}</h3>
</body>
</html>

这两个 jsp 页面只是起到了一个辅助作用,就是发起一个请求,目的是看一下两个拦截器是如何运行输出的。

3.7 运行结果 

当两个拦截器的 preHandle 方法都返回 true 的时候,请求的执行顺序是这样的:👇👇👇

用户发起some.do → 拦截器1 preHandle 方法拦截器2 preHandle 方法控制器的doSome方法拦截器2postHandle方法拦截器1postHandle方法拦截器2 afterCompletion 方法拦截器1 afterCompletion 方法。(对应下面这张图)

当第一个拦截器的 preHandle 方法返回 true,第二个拦截器的 preHandle 方法返回 false时,请求的执行顺序是这样的:👇👇👇

用户发起some.do → 拦截器1 preHandle 方法拦截器2 preHandle 方法拦截器1 afterCompletion 方法。

最后还会执行拦截器1 afterCompletion 方法是因为:afterCompletion方法是根据 preHandle 方法的返回值决定的,如果返回值为true,则afterCompletion 方法必会执行,所以拦截器1 preHandle 方法返回 true时,执行完连个拦截器的 preHandle 方法之后,最后就会执行拦截器1 afterCompletion 方法。(就是修改一下 preHandle 方法的返回值,所以就不再举例了。。。)

当第一个拦截器的 preHandle 方法返回 false,第二个拦截器的 preHandle 方法返回值无论是 true 还是 false ,请求的执行顺序都只能是这样的:👇👇👇

用户发起some.do → 拦截器1 preHandle 方法。因为拦截器1 preHandle 方法返回 false之后,直接就切断了请求的执行,后面都不会再执行其他内容了。(就是修改一下 preHandle 方法的返回值,所以就不再举例了。。。)

4.权限拦截器(简单的应用小实例)


4.1 控制器类

package com.songzihao.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;
/**
 *
 */
@Controller
public class MyController {
    @RequestMapping(value = "/some.do")
    public ModelAndView doSome(HttpSession session,String name, Integer age) {
        System.out.println("执行了MyController的doSome()方法");
        ModelAndView mv=new ModelAndView();
        mv.addObject("myName",name);
        mv.addObject("myAge",age);
        mv.setViewName("result");
        return mv;
    }
}

4.2 拦截器类

package com.songzihao.handler;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 *
 */
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("===MyInterceptor111111拦截器的preHandle===");
        //获取登录的账号信息
        Object attr=request.getSession().getAttribute("username");
        String username="";
        if (attr!=null) {
            username=(String) attr;
        }
        //判断账号
        if (username.equals("张起灵")) {
            return true;
        }else {
            request.getRequestDispatcher("/tips.jsp").forward(request,response);
            return false;
        }
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv) throws Exception {
        System.out.println("===MyInterceptor111111拦截器的postHandle===");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("===MyInterceptor111111拦截器的afterCompletion===");
    }
}

4.3 springmvc配置文件、web.xml文件与第一个例子是一样的

4.4 首页index.jsp

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
<head>
    <title>$</title>
</head>
<body>
    <p>一个拦截器</p>
    <form action="some.do" method="post">
        姓名:<input type="text" name="name"><br/>
        年龄:<input type="text" name="age"><br/>
        操作:<input type="submit" value="提交">
    </form>
</body>
</html>

4.5 result.jsp(用于显示index.jsp页面的提交结果)

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
<head>
    <title>$</title>
</head>
<body>
    /WEB-INF/view/result.jsp,显示request作用域中的数据<br/>
    <h3>myName数据:${myName}</h3>
    <h3>myAge数据:${myAge}</h3>
</body>
</html>

4.6 登录、登出页面(login.jsplogout.jsp

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
    登录操作
    <%
        session.setAttribute("username","张起灵");
    %>
</body>
</html>
<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
<head>
    <title>退出系统</title>
</head>
<body>
    退出系统
    <%
        session.removeAttribute("username");
    %>
</body>
</html>

4.7 非用户无法登录页面(tips.jsp

<%@ page contentType="text/html;charset=utf-8" language="java" %>
<html>
<head>
    <title>$</title>
</head>
<body>
    tips.jsp  系统不允许访问!!!
</body>
</html>

这个权限拦截器实现的小功能就是:首先通过 login.jsp 页面发起请求(获取会话作用域对象,此时的用户名只能是张起灵);之后通过 index.jsp 首页,发起 some.do 请求进行登录,如果输入的用户名是张起灵,则会转到正确的页面:result.jsp;如果输入了其他用户名,则会通过请求转发,直接转到非用户无法登录的页面:tips.jsp。最后可以通过登出页面(logout.jsp),将自己的用户名信息进行删除。

在执行控制器类中的doSome方法之前,会转到拦截器类中,去执行 preHandle 方法,判断用户名是否为张起灵,如果是,则返回true,继续执行 postHandleafterCompletion 这两个方法;如果用户名不是 张起灵,则直接返回 false,切断请求。(可以理解为你是非法用户,也就没必要继续执行其他内容了)。

4.8 运行结果 


5.写在结尾


最后这部分呢,我们来聊聊拦截器和过滤器的差别:

1.    拦截器是springmvc框架中的对象。过滤器是servlet中的对象。

2.    拦截器对象是由框架容器创建的。过滤器对象是由tomcat创建的。

3.    拦截器侧重于对请求做判断处理的,可以截断请求。过滤器侧重于对requestresponse对象的属性、参数设置值的。

4.    拦截器的执行时间有三个(控制器方法之前、控制器方法之后、请求完成之后)。过滤器执行时间只在请求之前。

5.    拦截器是对controller、动态资源进行拦截的。过滤器可以过滤所以请求(动态、静态)。

6.    拦截器和过滤器一起执行:先执行过滤器,后面是中央调度器,再后面是拦截器,最后才是控制器方法。

相关文章
|
4月前
|
前端开发 JavaScript Java
JAVAEE框架技术之4springMVC入门
JAVAEE框架技术之4springMVC入门
125 0
JAVAEE框架技术之4springMVC入门
|
4月前
SpringMVC之拦截器和异常处理器
【1月更文挑战第20天】SpringMVC之拦截器和异常处理器
60 0
|
9月前
|
XML 存储 Java
SpringMVC中支持的那些视图解析技术
SpringMVC中支持的那些视图解析技术
92 0
|
10月前
|
监控 前端开发 Java
SpringMVC之JSR303使用及拦截器使用(带你探索SpringMVC的新领域)
SpringMVC之JSR303使用及拦截器使用(带你探索SpringMVC的新领域)
66 0
|
15天前
|
前端开发 安全 Java
技术进阶:使用Spring MVC构建适应未来的响应式Web应用
【9月更文挑战第2天】随着移动设备的普及,响应式设计至关重要。Spring MVC作为强大的Java Web框架,助力开发者创建适应多屏的应用。本文推荐使用Thymeleaf整合视图,通过简洁的HTML代码提高前端灵活性;采用`@ResponseBody`与`Callable`实现异步处理,优化应用响应速度;运用`@ControllerAdvice`统一异常管理,保持代码整洁;借助Jackson简化JSON处理;利用Spring Security增强安全性;并强调测试的重要性。遵循这些实践,将大幅提升开发效率和应用质量。
39 7
|
4月前
|
前端开发 Java Apache
JAVAEE框架技术之6-springMVC拦截器和文件上传功能
JAVAEE框架技术之6-springMVC拦截器和文件上传功能
93 0
JAVAEE框架技术之6-springMVC拦截器和文件上传功能
序-Servlet和SpringMVC的联系和区别-配置路径先想好使用的使用的方法,然后匹配的需要的技术
序-Servlet和SpringMVC的联系和区别-配置路径先想好使用的使用的方法,然后匹配的需要的技术
|
3月前
|
JSON Java 数据库
技术笔记:SpringMVC常用注解
技术笔记:SpringMVC常用注解
|
4月前
SpringMVC拦截器的介绍,拦截器的基本实现,拦截器链配置
SpringMVC拦截器的介绍,拦截器的基本实现,拦截器链配置
43 2
|
4月前
|
前端开发 Java API
饼干探秘:深入Spring MVC中获取Cookie数据的技术解析
饼干探秘:深入Spring MVC中获取Cookie数据的技术解析
54 3