Springmvc中的转发重定向和拦截器

Springmvc中的转发重定向和拦截器

可变参数

可变参数在设计方法时,使用数据类型...来声明参数类型,例如:public static void function(int... numbers)
在实现方法体时,可变参数是作为数组来处理

public class Test {
    
    public static void main(String[] args) {
        System.out.println(Test.sum(1,2,3));
        System.out.println(Test.sum(1,2,3,4,54));
    }

    public static int sum(int... numbers){
        int sum=0;
        
        for(int i=0;i<numbers.length;i++){
            sum+=numbers[i];
        }
        return sum;
    }
}

注意: 每个方法中,最多只允许存在1个可变参数,并且,如果存在可变参数,那么必须是最后一个参数

转发和重定向

  • 在控制器内部处理请求的方法中,默认返回字符串时的处理方式是转发,转发的值是view组件的名称,比如return "login",实质上会根据视图解析器(ViewResolver)得到最终负责显示的页面,而通过return redirect:路径这样的语法表示重定向,在redirect:右侧的内容是路径,这个路径通常使用相对的路径,是以当前客户端的地址栏中的路径为标准进行参考,例如当前的地址为:http://localhost:8080/Project/user/reg.do,然后return "redirect:login.do",则会重定向到http://localhost:8080/Project/user/login.do,如果return "redirect:/main/index.do"或者return "redirect:../main/index.do",则会重定向到http://localhost:8080/Project/main/index.do

forward:

  • 默认的方式,但是也是可以使用return "forward:login"
  • 返回的一定是一个view,经过视图解析器之后会转发到指定的视图

redirect:

  • 重定向 : return "redirect:login.do"
  • 返回的是一个Controller方法的路径,而不是一个view,这个不会经过视图解析器,而是直接跳转

实例

@RequestMapping(value="/handle_reg.do", method=RequestMethod.POST)
    public String handleReg(User user,ModelMap map) {
        try {
            userService.reg(user);
            System.out.println("注册成功!");
            return "redirect:login.do";  //重定向到login.do这个控制方法,login.do对应的就是转发到login.jsp
        } catch (UsernameConflictException e) {
            System.out.println(e.getMessage());
            map.put("errorMessage", e.getMessage());
            return "error";
        }
    }
    
    @RequestMapping(value="login.do")
    public String handleLogin() {
        return "login";
    }

拦截器

基本概念

  1. 拦截器(interceptor)是springmvc中的一个组件,是运行在DispatcherServlet之后,运行在Controller之前的
  2. 拦截器可以决定对某些符合条件的进行拦截或者放行,所以,通常用于对一些具有相同运行条件的功能进行约束

使用拦截器

自定义拦截器类

  1. 创建一个拦截类(DemoInterceptor),实现HandlerInterceptor接口
public class DemoInterceptor implements HandlerInterceptor {

    /**
     * 处理器执行之前调用
     * @param request  HttpServletRequest对象,可以获取请求参数等等
     * @param response HttpServletResponse对象
     * @param Handler  拦截器的Controller对象
     * @return 如果返回false,就会中断处理流程,不会处理后续的拦截器和Controller。如果返回true,则会执行后续的拦截器和处理器
     */
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        
        System.out.println("DemoInterceptor的PreHandler执行");
        return true;
    }

    /**
     * 处理器执行之后调用,跳转到指定视图之前调用
     * @param request  HttpServletRequest对象
     * @param response HttpServletResponse对象
     * @param Handler  拦截器的Controller对象
     * @param modelAndView  ModelAndView对象,其中存放的是处理结果和视图的信息
     */
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        /**
         * 1. 可以自己设计逻辑,例如某些情况下返回false,返回true
         * 2. 返回true表示执行后续的处理器和拦截器,返回false会中断处理流程
         */
        System.out.println("handler:"+handler);
        System.out.println("DemoInterceptor的PostHandler执行");
        //设置视图的名称,那么执行完成之后就会条跳转到index.jsp页面
        //modelAndView.setViewName("index");  
    }
    
    /**
     * 请求处理完成之后调用
     */
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("DemoInterceptor的afterCompletion执行");

    }

}

在springmvc的配置文件中配置

  1. 配置拦截的路径:<mvc:mapping path=""/> 可以使用通配符* 比如:/**匹配所有的路径,/user/*只能匹配/user的子路径
  2. 配置不拦截的路径 : <mvc:exclude-mapping path=""/> 可以配置多个
  3. 配置拦截器类(bean) : <bean class="">

配置

  • 必须按照上面的顺序配置,否则将会报错
    <!-- 配置拦截器,其中可以配置多个拦截器 -->
    <mvc:interceptors>
        
        <mvc:interceptor>
        
            <!-- 配置拦截器的拦截路径,拦截/user下的全部处理器方法映射
                比如:http://localhost:8080/Springmvc/user/login.do这个请求就会被拦截
             -->
            <mvc:mapping path="/user/*"/>
            
            <!-- 配置不被该拦截器拦截器的controller方法,这个是可选配置
                比如:http://localhost:8080/Springmvc/user/index.do将不会被拦截器
            -->
            <mvc:exclude-mapping path="/user/index.do"/> 
            <mvc:exclude-mapping path="/user/login.do"/>  
            
            <!-- 配置拦截器的bean,指定的是全类名 -->
            <bean class="cn.tedu.spring.interceptor.DemoInterceptor"></bean>
        </mvc:interceptor>
        
    </mvc:interceptors>

其中实现的方法

  1. public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler)
    • 该方法在controller处理请求之前执行
    • 如果返回的false,则会中断处理流程,不会执行后续的拦截器和处理器,返回true会执行后续的拦截器和处理器
    • 可以自行设计逻辑返回false或者true
  2. public void postHandle(HttpServletRequest request,HttpServletResponse response, Object handler,ModelAndView modelAndView)
    • 处理器执行之后,视图处理之前调用,此时可以通过对ModelAndView对数据和视图进行处理
    • 当然需要prehandler方法返回true才会执行
  3. public void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex)
    • 所有的请求处理完毕之后调用,比如性能监控中,我们可以在此记录结束时间和消耗时间,还可以进行一些资源处理
    • 当然需要prehandler方法返回true才会执行

演示登录检查

  1. 登录检查: 当涉及到用户信息的修改,查看什么的,必须要验证是否登录,因此需要设计拦截器验证登录
  2. 先设定登录数据,即: 在login.jsp中添加登录按钮,登录完成之后,需要自己定义一个标记存储在session中,比如用户的id或者用户的对象
  3. 我们使用用户的id作为标记验证是否已经的登录,如果用户登录成功,会在session中添加一个uid的属性
  4. 用户退出登录使用session.invalidate();清除session,并且重定向到登录界面

自定义拦截器(LoginInterceptor)

  • 具体流程在prehandler方法中写的很清楚
public class LoginInterceptor implements HandlerInterceptor{
    /*
     * 在处理器执行之前调用(non-Javadoc)
     * 1. 获取session
     * 2. 读取session中的uid的值
     *      如果为null,表示没有登录,那么直接重定向到登录界面,同时返回false,不需要执行后面的流程了
     *      如果不为null,表示已经登录了,那么直接返回true,继续执行后面的拦截器或者处理器
     */
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {
        HttpSession session=request.getSession();   //获取session
        Object uid=session.getAttribute("uid");  //读取session中的对象
        //如果uid存在,那么即可登录完成
        if (uid!=null) {
            return true;   //返回true,登录成功就需要执行后续的流程
        }
        response.sendRedirect(request.getContextPath()+"/user/login.do");  //重定向到登录界面
        return false;   //返回false,后面的流程也不用执行了,直接中断
    }

    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
    }

    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        
    }
}

springmvc中配置拦截器

  • 由于这里只是跳转到用户中心需要验证登录,那么只是匹配了user_center.do
<!-- 配置拦截器,其中可以配置多个拦截器 -->    
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/user/user_center.do"/>
            <bean class="cn.tedu.spring.interceptor.LoginInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

多个拦截器的执行顺序

  • 根据在springmvc配置文件中配置的顺序执行,即是在<mvc:interceptors>下配置的拦截器的顺序,如果对同一个路径进行了拦截器,那么先配置的先拦截

拦截器和过滤器的区别(主要的区别)

  1. 拦截器是springmvc中,仅仅当使用springmvc才可以使用拦截器,过滤器是Java EE体系中的,无论使用哪种框架都可以使用过滤器
  2. 拦截器在DispatcherServlet之后,在处理器之前执行,过滤器在DispatcherServlet之前执行
  3. 过滤器会在所有的servlet之前执行(所有的请求都会执行),而拦截器会在springmvc中DispatcherServlet之后执行,所以过滤器在项目中可以过滤任何请求(只要是配置了对应的路径),而拦截器只会在DispatcherServlet处理的请求的基础之上进行拦截

总结

  • 当多种请求都需要做相同或者极为相似的任务时,可以使用拦截器
  • 开发好拦截器,那么需要在springmvc的配置文件中配置
  • <mvc:interceptors>可以有如果若干个<mvc:interceptor>,即是配置若干个拦截器,配置的多个拦截器将会形成拦截器链,如果配置多个拦截器对同一个路径都会拦截,那么会按照配置的节点顺序执行。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,218评论 1 92
  • 对于java中的思考的方向,1必须要看前端的页面,对于前端的页面基本的逻辑,如果能理解最好,不理解也要知道几点。 ...
    神尤鲁道夫阅读 782评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,490评论 18 139
  • “我无意放大世界的善意,也无意放大世界的恶意,只是依照比例,老实接受有晴有雨的天气,世界与我,相互而已”
    ZWE阅读 138评论 0 0
  • 15年前的今天我成为你的妻子,一路走来风风雨雨,有欢笑也有泪水,共同见证了我们点点滴滴的幸福。 我们相识...
    涓涓浅语阅读 956评论 0 3