SpringMVC_04异步调用、拦截器和异常处理

SpringMVC_04跨域访问、异步调用、拦截器和异常处理

跨域访问

  • 定义:通过域名a下的操作访问域名b的资源(会出现无法访问的现象)

  • @CrossOrigin注解

    标注在处理器方法上方表示该方法支持跨域访问
    标注在处理器类上方表示该处理器类中的所有处理器方法均支持跨域访问

  • 为当前主机添加备用域名:修改windows安装目录下的host文件,添加( ip 域名)

异步调用

  • 形参注解@RequestBody:将异步提交数据组织成标注请求参数格式,赋值给形参

  • 处理简单参数

    //为id="testAjax"的组件绑定点击事件
    $("#testAjax").click(function(){
        //发送异步调用
        $.ajax({
            //请求方式:POST请求
            type:"POST",
            //请求的地址
            url:"ajaxController",
            //请求参数(也就是请求内容)
            data:'ajax message',
            //响应正文类型
            dataType:"text",
            //请求正文的MIME类型
            contentType:"application/text",
        });
    });
    
    @RequestMapping("/ajaxController")
    //使用@RequestBody注解,可以将请求体内容封装到指定参数中
    public String ajaxController(@RequestBody String message){
        System.out.println("ajax request is running..."+message);
        return "page.jsp";
    }
    
  • 处理POJO类型参数

    //为id="testAjaxPojo"的组件绑定点击事件
    $("#testAjaxPojo").click(function(){
        $.ajax({
            type:"POST",
            url:"ajaxPojoToController",
            data:'{"name":"Jock","age":39}',
            dataType:"text",
            contentType:"application/json",
        });
    });
    
    @RequestMapping("/ajaxPojoToController")
    //如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中
    //注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射
    public String  ajaxPojoToController(@RequestBody User user){
        System.out.println("controller pojo :"+user);
        return "page.jsp";
    }
    
  • 参数是封装了POJO的List集合

    //为id="testAjaxList"的组件绑定点击事件
    $("#testAjaxList").click(function(){
        $.ajax({
            type:"POST",
            url:"ajaxListToController",
            data:'[{"name":"Jock","age":39},{"name":"Jockme","age":40}]',
            dataType:"text",
            contentType:"application/json",
        });
    });
    
    @RequestMapping("/ajaxListToController")
    //如果处理参数是List集合且封装了POJO,且页面发送的数据是JSON格式的对象数组,数据将自动映射到集合参数中
    public String  ajaxListToController(@RequestBody List<User> userList){
        System.out.println("controller list :"+userList);
        return "page.jsp";
    }
    
  • @ResponseBody可写在方法上,也可以写在方法的返回值前面,基于jackson技术,将返回的POJO对象转成json格式数据

    //为id="testAjaxReturnJson"的组件绑定点击事件
    $("#testAjaxReturnJson").click(function(){
        //发送异步调用
        $.ajax({
            type:"POST",
            url:"ajaxReturnJson",
            //回调函数
            success:function(data){
                alert(data);
                alert(data['name']+" ,  "+data['age']);
            }
        });
    });
    
    @RequestMapping("/ajaxReturnJson")
    @ResponseBody
    //基于jackon技术,使用@ResponseBody注解可以将返回的POJO对象转成json格式数据
    public User ajaxReturnJson(){
        System.out.println("controller return json pojo...");
        User user = new User();
        user.setName("Jockme");
        user.setAge(39);
        return user;
    }
    
  • 基于jackson技术,使用@ResponseBody注解可以将返回的保存POJO对象的集合转成json数组格式数据

    //为id="testAjaxReturnJsonList"的组件绑定点击事件
    $("#testAjaxReturnJsonList").click(function(){
        //发送异步调用
        $.ajax({
            type:"POST",
            url:"ajaxReturnJsonList",
            //回调函数
            success:function(data){
                alert(data);
                alert(data.length);
                alert(data[0]["name"]);
                alert(data[1]["age"]);
            }
        });
    });
    
    @RequestMapping("/ajaxReturnJsonList")
    @ResponseBody
    //基于jackon技术,使用@ResponseBody注解可以将返回的保存POJO对象的集合转成json数组格式数据
    public List ajaxReturnJsonList(){
        System.out.println("controller return json list...");
        User user1 = new User();
        user1.setName("Tom");
        user1.setAge(3);
    
        User user2 = new User();
        user2.setName("Jerry");
        user2.setAge(5);
    
        ArrayList al = new ArrayList();
        al.add(user1);
        al.add(user2);
    
        return al;
    }
    
  • @CrossOrigin开启跨域访问

    //为id="testCross"的组件绑定点击事件
    $("#testCross").click(function(){
        //发送异步调用
        $.ajax({
            type:"POST",
            url:"http://www.aaa.com/cross",//先设置本地域名
            //回调函数
            success:function(data){
                alert("跨域调用信息反馈:"+data['name']+" ,  "+data['age']);
            }
        });
    });
    
    @RequestMapping("/cross")
    @ResponseBody
    @CrossOrigin
    public User cross(HttpServletRequest request){
        System.out.println("controller cross..."+request.getRequestURL());
        User user = new User();
        user.setName("Tom");
        user.setAge(39);
        return user;
    }
    

拦截器Interceptor

  • 定义:是一种动态拦截方法调用的机制

  • 作用:1.在指定的方法调用前后执行预先设定的代码

    ​ 2.阻止原始方法的执行

  • 核心原理:AOP思想

  • 拦截器链:多个拦截器按一定顺序,对原始被调用功能进行增强

  • 与过滤器的区别

    1.Filter属于Servlet技术,Interceptor属于SpringMVC技术

    2.Filter增强所有访问,Interceptor只增强SpringMVC的访问

  • 自定义一个拦截器

    定义一个类实现Interceptor接口

    package com.interceptor;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    //自定义拦截器需要实现HandleInterceptor接口
    public class MyInterceptor implements HandlerInterceptor {
        //处理器运行之前执行
        @Override
        //request:请求对象
        //response:响应对象
        //handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装
        public boolean preHandle(HttpServletRequest request,
                                 HttpServletResponse response,
                                 Object handler) throws Exception {
            System.out.println("前置运行----a1");
            //返回值为false将拦截原始处理器的运行
            //如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行
            return true;
        }
    
        //处理器运行之后执行
        @Override
        //modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整
        public void postHandle(HttpServletRequest request,
                               HttpServletResponse response,
                               Object handler,
                               ModelAndView modelAndView) throws Exception {
            System.out.println("后置运行----b1");
        }
    
        //所有拦截器的后置执行全部结束后,执行该操作
        @Override
        //es:处理器执行过程中出现异常对象,可以针对异常情况进行单独处理
        public void afterCompletion(HttpServletRequest request,
                                    HttpServletResponse response,
                                    Object handler,
                                    Exception ex) throws Exception {
            System.out.println("完成运行----c1");
        }
    
        //三个方法的运行顺序为    preHandle -> postHandle -> afterCompletion
        //如果preHandle返回值为false,三个方法仅运行preHandle
    }
    
    

    修改springmvc配置文件

    • mapping标签:可以配置多个,支持通配符*

      /*表示任意名称,/*仅表示根路径下任意名称,不再往下匹配目录

      **表示当前路径及其子路径,/**表示根路径及其子路径下任意名称

    • exclude-mapping标签:不包含的配置项,支持通配符

    • bean标签(ref标签):只能配置一个

    
    
    <bean id="myInterceptor" class="com.interceptor.MyInterceptor"/>
    <mvc:interceptors>
        <mvc:interceptor>
            
            <mvc:mapping path="/handleRun"/>
            
            <ref bean="myInterceptor"/>
        mvc:interceptor>
    mvc:interceptors>
    

    Controller控制器

    @Controller
    public class InterceptorController {
        @RequestMapping("/handleRun")
        public String handleRun() {
            System.out.println("业务处理器运行------------main");
            return "page.jsp";
        }
    }
    
  • 拦截器执行流程

    preHandle return ture—>handle—>postHandle—>afterCompletion—>其他

    preHandle return false—>其他

  • 拦截器链配置

    • 当配置多个拦截器时,形成拦截器链(a、b、c三个拦截器)
    • 拦截器链的运行顺序与配置的先后顺序一致(preHandle前置a->b->c->handle处理器->postHandle后置c->b->a->afterCompletion完成后c->b->a)
    • 当拦截器中出现对原始处理器的拦截,后面的拦截器会终止运行(b拦截,则b不运行postHandl和afterCOmpletion,c都不运行),前面的拦截器照常运行(b拦截,则a运行)
  • 责任链模式

    一种行为模式

    特征:沿着一条预先设定的任务链顺序执行,每个节点具有独立的工作任务

异常处理

  • 异常处理器:HandlerExceptionResolver接口

  • 实现HandlerExceptionResolver接口来处理异常,根据异常的种类不同,进行分类,返回不同信息

    无法拦截入参类型转换异常

    @Component
    public class ExceptionResolver implements HandlerExceptionResolver {
        @Override
        public ModelAndView resolveException(HttpServletRequest request,
                                             HttpServletResponse response,
                                             Object handler,
                                             Exception ex) {
            ModelAndView modelAndView = new ModelAndView();
            if( ex instanceof NullPointerException){
                //定义异常现象出现后,反馈给用户的信息
                modelAndView.addObject("msg","空指针异常");
            }else if ( ex instanceof  ArithmeticException){
                modelAndView.addObject("msg","算数运算异常");
            }else{
                modelAndView.addObject("msg","未知的异常");
            }
            //定义异常现象出现后,反馈给用户的页面
            modelAndView.setViewName("error.jsp");
            return modelAndView;
        }
    }
    
  • 使用注解实现异常分类管理

    在DispatcherServlet加载后就加载,可以拦截到入参类型转换异常

    类注解@ControllerAdvice:设置当前类为异常处理器类

    方法注解@ExceptionHandler:设置处理的实际异常类型

    @Component
    //使用注解开发异常处理器
    //声明该类是一个Controller的通知类,声明后该类就会被加载成异常处理器
    @ControllerAdvice
    public class ExceptionAdvice {
    
        //类中定义的方法携带@ExceptionHandler注解的会被作为异常处理器,后面添加实际处理的异常类型
        @ExceptionHandler(NullPointerException.class)
        @ResponseBody
        public String doNullException(Exception ex){
            return "空指针异常";
        }
    
        @ExceptionHandler(ArithmeticException.class)
        @ResponseBody
        public String doArithmeticException(Exception ex){
            return "ArithmeticException";
        }
    
        @ExceptionHandler(Exception.class)
        @ResponseBody
        public String doException(Exception ex){
            return "all";
        }
    }
    
  • 自定义异常

    定义格式:

    public class BusinessException extends RuntimeException {
    	public BusinessException() {
    		super();
    	}
    //覆盖父类所有的构造方法,转调父类构造方法
    }
    

    异常触发

    if(user.getName().trim().length()<4) {
    	throw new BusinessException("用户名长度必须在2-4位之间,请重新输入!");
    }
    

你可能感兴趣的:(SpringMVC)