zoukankan      html  css  js  c++  java
  • SpringMVC第七篇【RESTful支持、拦截器】

    RESTful支持

    我们在学习webservice的时候可能就听过RESTful这么一个名词,当时候与SOAP进行对比的…那么RESTful究竟是什么东东呢???

    RESTful(Representational State Transfer)软件开发理念,RESTful对http进行非常好的诠释

    如果一个架构支持RESTful,那么就称它为RESTful架构…

    以下的文章供我们了解:

    http://www.ruanyifeng.com/blog/2011/09/restful

    综合上面的解释,我们总结一下什么是RESTful架构:

    •   (1)每一个URI代表一种资源;
    •   (2)客户端和服务器之间,传递这种资源的某种表现层;
    •   (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现”表现层状态转化”

    其实一般的架构并不能完全支持RESTful的,因此,只要我们的系统支持RESTful的某些功能,我们一般就称作为支持RESTful架构

    url的RESTful实现

    非RESTful的http的url:http://localhost:8080/items/editItems.action?id=1&….

    RESTful的url是简洁的:http:// localhost:8080/items/editItems/1

    更改DispatcherServlet的配置

    从上面我们可以发现,url并没有.action后缀的,因此我们要修改核心分配器的配置

    
        <!-- restful的配置 -->
        <servlet>
            <servlet-name>springmvc_rest</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 加载springmvc配置 -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <!-- 配置文件的地址 如果不配置contextConfigLocation, 默认查找的配置文件名称classpath下的:servlet名称+"-serlvet.xml"即:springmvc-serlvet.xml -->
                <param-value>classpath:spring/springmvc.xml</param-value>
            </init-param>
    
        </servlet>
        <servlet-mapping>
            <servlet-name>springmvc_rest</servlet-name>
            <!-- rest方式配置为/ -->
            <url-pattern>/</url-pattern>
        </servlet-mapping>

    在Controller上使用PathVariable注解来绑定对应的参数

    
        //根据商品id查看商品信息rest接口
        //@RequestMapping中指定restful方式的url中的参数,参数需要用{}包起来
        //@PathVariable将url中的{}包起参数和形参进行绑定
        @RequestMapping("/viewItems/{id}")
        public @ResponseBody ItemsCustom viewItems(@PathVariable("id") Integer id) throws Exception{
            //调用 service查询商品信息
            ItemsCustom itemsCustom = itemsService.findItemsById(id);
    
            return itemsCustom;
    
        }
    

    当DispatcherServlet拦截/开头的所有请求,对静态资源的访问就报错:我们需要配置对静态资源的解析

    
        <!-- 静态资源 解析 -->
        <mvc:resources location="/js/" mapping="/js/**" />
        <mvc:resources location="/img/" mapping="/img/**" />
    

    /**就表示不管有多少层,都对其进行解析,/*代表的是当前层的所有资源..


    SpringMVC拦截器

    在Struts2中拦截器就是我们当时的核心,原来在SpringMVC中也是有拦截器的

    用户请求到DispatherServlet中,DispatherServlet调用HandlerMapping查找Handler,HandlerMapping返回一个拦截的链儿(多个拦截),springmvc中的拦截器是通过HandlerMapping发起的。

    实现拦截器的接口:

    
    public class HandlerInterceptor1 implements HandlerInterceptor {
    
        //在执行handler之前来执行的
        //用于用户认证校验、用户权限校验
        @Override
        public boolean preHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler) throws Exception {
    
            System.out.println("HandlerInterceptor1...preHandle");
    
            //如果返回false表示拦截不继续执行handler,如果返回true表示放行
            return false;
        }
        //在执行handler返回modelAndView之前来执行
        //如果需要向页面提供一些公用 的数据或配置一些视图信息,使用此方法实现 从modelAndView入手
        @Override
        public void postHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            System.out.println("HandlerInterceptor1...postHandle");
    
        }
        //执行handler之后执行此方法
        //作系统 统一异常处理,进行方法执行性能监控,在preHandle中设置一个时间点,在afterCompletion设置一个时间,两个时间点的差就是执行时长
        //实现 系统 统一日志记录
        @Override
        public void afterCompletion(HttpServletRequest request,
                HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            System.out.println("HandlerInterceptor1...afterCompletion");
        }
    
    }

    配置拦截器

    
        <!--拦截器 -->
        <mvc:interceptors>
            <!--多个拦截器,顺序执行 -->
            <!-- <mvc:interceptor>
                <mvc:mapping path="/**" />
                <bean class="cn.itcast.ssm.controller.interceptor.HandlerInterceptor1"></bean>
            </mvc:interceptor>
            <mvc:interceptor>
                <mvc:mapping path="/**" />
                <bean class="cn.itcast.ssm.controller.interceptor.HandlerInterceptor2"></bean>
            </mvc:interceptor> -->
    
            <mvc:interceptor>
                <!-- /**可以拦截路径不管多少层 -->
                <mvc:mapping path="/**" />
                <bean class="cn.itcast.ssm.controller.interceptor.LoginInterceptor"></bean>
            </mvc:interceptor>
        </mvc:interceptors>

    测试执行顺序

    如果两个拦截器都放行

    
    测试结果:
    HandlerInterceptor1...preHandle
    HandlerInterceptor2...preHandle
    
    HandlerInterceptor2...postHandle
    HandlerInterceptor1...postHandle
    
    HandlerInterceptor2...afterCompletion
    HandlerInterceptor1...afterCompletion
    
    总结:
    执行preHandle是顺序执行。
    执行postHandle、afterCompletion是倒序执行

    1 号放行和2号不放行

    
    测试结果:
    HandlerInterceptor1...preHandle
    HandlerInterceptor2...preHandle
    HandlerInterceptor1...afterCompletion
    
    总结:
    如果preHandle不放行,postHandle、afterCompletion都不执行。
    只要有一个拦截器不放行,controller不能执行完成
    

    1 号不放行和2号不放行

    
    测试结果:
    HandlerInterceptor1...preHandle
    总结:
    只有前边的拦截器preHandle方法放行,下边的拦截器的preHandle才执行。

    日志拦截器或异常拦截器要求

    • 将日志拦截器或异常拦截器放在拦截器链儿中第一个位置,且preHandle方法放行

    拦截器应用-身份认证

    拦截器拦截

    
    public class LoginInterceptor implements HandlerInterceptor {
    
        //在执行handler之前来执行的
        //用于用户认证校验、用户权限校验
        @Override
        public boolean preHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler) throws Exception {
    
            //得到请求的url
            String url = request.getRequestURI();
    
            //判断是否是公开 地址
            //实际开发中需要公开 地址配置在配置文件中
            //...
            if(url.indexOf("login.action")>=0){
                //如果是公开 地址则放行
                return true;
            }
    
            //判断用户身份在session中是否存在
            HttpSession session = request.getSession();
            String usercode = (String) session.getAttribute("usercode");
            //如果用户身份在session中存在放行
            if(usercode!=null){
                return true;
            }
            //执行到这里拦截,跳转到登陆页面,用户进行身份认证
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
    
            //如果返回false表示拦截不继续执行handler,如果返回true表示放行
            return false;
        }
        //在执行handler返回modelAndView之前来执行
        //如果需要向页面提供一些公用 的数据或配置一些视图信息,使用此方法实现 从modelAndView入手
        @Override
        public void postHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler,
                ModelAndView modelAndView) throws Exception {
            System.out.println("HandlerInterceptor1...postHandle");
    
        }
        //执行handler之后执行此方法
        //作系统 统一异常处理,进行方法执行性能监控,在preHandle中设置一个时间点,在afterCompletion设置一个时间,两个时间点的差就是执行时长
        //实现 系统 统一日志记录
        @Override
        public void afterCompletion(HttpServletRequest request,
                HttpServletResponse response, Object handler, Exception ex)
                throws Exception {
            System.out.println("HandlerInterceptor1...afterCompletion");
        }
    
    }

    Controller

    
    @Controller
    public class LoginController {
    
    
        //用户登陆提交方法
        @RequestMapping("/login")
        public String login(HttpSession session, String usercode,String password)throws Exception{
    
            //调用service校验用户账号和密码的正确性
            //..
    
            //如果service校验通过,将用户身份记录到session
            session.setAttribute("usercode", usercode);
            //重定向到商品查询页面
            return "redirect:/items/queryItems.action";
        }
    
        //用户退出
        @RequestMapping("/logout")
        public String logout(HttpSession session)throws Exception{
    
            //session失效
            session.invalidate();
            //重定向到商品查询页面
            return "redirect:/items/queryItems.action";
    
        }
    
    
    }
    
  • 相关阅读:
    java int转byte数组
    业务网关-操作手册
    业务网关-配置
    H2数据库的导入、导出(CSV)
    sequelize踩坑处理:时间格式化
    引入koa-static处理静态资源
    MySql利用case when实现批量更新多条记录的不同值实现方法
    Sequelize增删改查及批量新增或批量更新(bulkCreate的updateOnDuplicate)等常用接口
    数据结构队列、双端队列、队列系算法题解析
    配置webpack中externals来减少打包后vendor.js的体积
  • 原文地址:https://www.cnblogs.com/zhong-fucheng/p/7554353.html
Copyright © 2011-2022 走看看