SpringMVC异步调用 && 跨域处理 && 拦截器 &&异常处理 && 整合文件上传 && 了解ResultFul

异步调用

异步请求参数的传递,参数是封装在请求体中。对比在地址栏中使用同步的参数传递,参数是使用字符串拼接在地址栏上。所以异步请求的参数获取 需要使用@ResponseBody注解。

异步请求接收普通参数

前端代码:

//为id="testAjax"的组件绑定点击事件
$("#testAjax").click(function(){
   //发送异步调用
    $.ajax({
       //请求方式:POST请求
       type:"POST",
       //请求的地址
       url:"ajaxController",
       //请求参数(也就是请求内容)
       data:'ajax message',
       //响应正文类型
       dataType:"json",
       //请求正文的MIME类型
       contentType:"application/text",
       success:function (data) {
            alert(data.code);
         }
    });
});

后端代码:

@RequestMapping("/ajaxController")
//使用@RequestBody注解,可以将请求体内容封装到指定参数中
public String ajaxController(@RequestBody String message){
    System.out.println("ajax request is running..."+message);
    int i= 1/0;
    return "page.jsp";
}

异步请求接收对象

前端传递的是json格式的数据:

data:'{"name":"Jock","age":39}',

后端处理:

@RequestMapping("/ajaxPojoToController")
//如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中
//注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射
public String  ajaxPojoToController(@RequestBody User user){
    System.out.println("controller pojo :"+user);
    return "page.jsp";
}

异步请求接收对象数组

前端传递的是json格式的数组:

data:'[{"name":"Jock","age":39},{"name":"Jockme","age":40}]',

后端处理:

@RequestMapping("/ajaxListToController")
//如果处理参数是List集合且封装了POJO,且页面发送的数据是JSON格式的对象数组,数据将自动映射到集合参数中
public String  ajaxListToController(@RequestBody List<User> userList){
    System.out.println("controller list :"+userList);
    return "page.jsp";
}

异步请求参数返回

前后端之间的数据都是通过json传递,所以需要转json的工具

在pom.xml中导入坐标

<!--json相关坐标3个-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.0</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.9.0</version>
</dependency>

在返回方法的上面加上@ResponceBody 注解 ,自动解析为json格式的数据。

跨域访问

  1. 协议
  2. 地址(ip)
  3. 端口
  4. 以上其中一个不同就视为跨域

默认情况下跨域访问是不支持的,如果你的方法或者模块需要跨域访问,只需要在方法上添加@CrossOrigin 注解即可。

拦截器

拦截器简介:是一种动态拦截方法调用的机制

作用:

1. 在指定的方法调用的前后执行预先设定好的代码
2. 阻止原始方法的执行

核心原理:AOP思想

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

在这里插入图片描述

在这里插入图片描述

拦截器开发入门

自定义拦截器类:

public class Myintercepter implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, 
    						HttpServletResponse response, 
    						Object handler) throws Exception {
    	// handler : 被调用的处理对象,本质上是一个方法对象,对反射中的Method对象进行了再包装
    	// 返回值为false,被拦截的处理器将不执行
        System.out.println("这是前置方法----a1");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, 
    					HttpServletResponse response, 
    					Object handler, 
    					ModelAndView modelAndView) throws Exception {
    		//ModelAndView :如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调账
          System.out.println("这是后置方法----b1");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, 
    					HttpServletResponse response, 
    					Object handler, 
    					Exception ex) throws Exception {
    	  // ex:如果处理器执行过程总出现异常对象,可以针对异常情况进行单独处理
          System.out.println("这是完成方法----c1");
    }
}

注意事项:自定义拦截器必须实现HandlerInterceptor,三个方法可以写任意个。前置方法中的返回值为true时,才会继续向下执行,为false时, 后置 和 完成都不会执行。执行顺序固定为 前置–>后置–>完成

拦截器值制作完成之后还需要在springMVC.xml文件中进行配置

<mvc:interceptors>
    <mvc:interceptor>
        <!--指定拦截路径-->
        <mvc:mapping path="/ajaxController"/>
        <!--指定拦截器-->
        <bean class="com.myTest.intercepter.Myintercepter"/>
    </mvc:interceptor>
</mvc:interceptors>

可以配置多个拦截器,执行顺序和拦截器的配置顺序相关。

在这里插入图片描述

在这里插入图片描述

异常处理

异常处理器:异常处理器需要实现HandlerExceptionResolver接口,在实现类上添加@Component注解,将这个类交给spring管理,spring看见实现了HandlerExceptionResolver接口,就知道时异常处理类,那么只要在这个模块中出现了异常那么都会被这个异常处理器捕获,进行处理。

异常处理类:

@Component
public class ExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {
        System.out.println("my exception is running ...."+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;
        //Exception ex 参数:异常发生时,异常就会被捕获,作为参数传递到这个类的这个方法中进行处理
    }
}

根据不同的异常进行不同的处理。

使用注解开发异常处理
@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";
    }

}

@ControllerAdvice 注解作用:申明这个类时异常通知类
@ExceptionHandler(NullPointerException.class) 注解作用:申明方法是异常处理器,后面添加实际异常处理类型,根据不同的异常执行不同的异常处理器。
@ResponseBody 注解作用:将数据转换为json返回(前提在pom文件中加载坐标),否则会被当作页面跳转。

使用注解开发和异常处理类的差别。注解开发 加载时机比较早,在DispatcherServlet加载完成之后就进行加载,比如说,前端传递的是String类型,后端使用int类型接收,那么注解方式能捕获到这个类型转换异常,使用继承接口的方式则捕获不到这个异常。

在这里插入图片描述

如何自定义异常?
实现对应异常接口
在这里插入图片描述
将对应异常分装为自定义异常
在这里插入图片描述
再异常处理中获取封装的信息,getMessage() 即可获取自己传入的信息
在这里插入图片描述

SpringMVC整合文件上传功能

因为是整合别人的功能首先肯定就是导入对应的坐标
pom.xml

<!--文件上传下载-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

在SpringMVC.xml配置文件中,将处理文件上传的bean申明

<!--配置文件上传处理器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!--设置文件上传文件大小上限,还有其他很多设置-->
    <property name="maxUploadSize" value="1024000000"/>
</bean>

在文件中使用,只需要在形参中申明这个类型的参数即可。Spring自动将文件封装到这个对象中。
注意:表单提交的属性名一定要和形参名相同,上传多个文件时,又形参名和name属性名进行对应。

@Controller
public class FileUploadController {

    @RequestMapping(value = "/fileupload")
    //参数中定义MultipartFile参数,用于接收页面提交的type=file类型的表单,要求表单名称与参数名相同
    public String fileupload(MultipartFile file,MultipartFile file1,MultipartFile file2, HttpServletRequest request) throws IOException {
        System.out.println("file upload is running ..."+file);
//        MultipartFile参数中封装了上传的文件的相关信息
//        System.out.println(file.getSize());  获取文件的字节大小
//        System.out.println(file.getBytes());  获取文件对应字节数组的地址 
//        System.out.println(file.getContentType());  获取上传文件的类型
//        System.out.println(file.getName());             获取形参名,就是上面的file
//        System.out.println(file.getOriginalFilename());  获取文件名
//        System.out.println(file.isEmpty());
        //首先判断是否是空文件,也就是存储空间占用为0的文件
        if(!file.isEmpty()){
            //如果大小在范围要求内正常处理,否则抛出自定义异常告知用户(未实现)
            //获取原始上传的文件名,可以作为当前文件的真实名称保存到数据库中备用
            String fileName = file.getOriginalFilename();
            //设置保存的路径
            String realPath = request.getServletContext().getRealPath("/images");
            //保存文件的方法,指定保存的位置和文件名即可,通常文件名使用随机生成策略产生,避免文件名冲突问题
            file.transferTo(new File(realPath,file.getOriginalFilename()));
        }
        //测试一次性上传多个文件
        if(!file1.isEmpty()){
            String fileName = file1.getOriginalFilename();
            //可以根据需要,对不同种类的文件做不同的存储路径的区分,修改对应的保存位置即可
            String realPath = request.getServletContext().getRealPath("/images");
            file1.transferTo(new File(realPath,file1.getOriginalFilename()));
        }
        if(!file2.isEmpty()){
            String fileName = file2.getOriginalFilename();
            String realPath = request.getServletContext().getRealPath("/images");
            file2.transferTo(new File(realPath,file2.getOriginalFilename()));
        }
        return "page.jsp";
    }
}

前端代码:

<form action="/fileupload" method="post" enctype="multipart/form-data">
    <%--文件上传表单的name属性值一定要与controller处理器中方法的参数对应,否则无法实现文件上传--%>
    上传LOGO:<input type="file" name="file"/><br/>
    上传照片:<input type="file" name="file1"/><br/>
    上传任意文件:<input type="file" name="file2"/><br/>
    <input type="submit" value="上传"/>
</form>

ResultFul开发入门

在这里插入图片描述

在这里插入图片描述

总的来说就是使用数字代替操作名称,在后端解析路径上的数字,根据数字不同进行不同的数据处理。

//rest风格访问路径完整书写方式
@RequestMapping("/user/{id}")
//使用@PathVariable注解获取路径上配置的具名变量,该配置可以使用多次
public String restLocation(@PathVariable Integer id){
    System.out.println("restful is running ....");
    return "success.jsp";
}

rest风格访问路径简化书写方式,配合类注解@RequestMapping使用,在对应模块的类上指定这个模块访问的名称。

//@Controller
//@ResponseBody
//设置rest风格的控制器
@RestController
//设置公共访问路径,配合下方访问路径使用
@RequestMapping("/user/")
public class UserController {
    //rest风格访问路径简化书写方式,配合类注解@RequestMapping使用
    @RequestMapping("{id}")
    public String restLocation2(@PathVariable Integer id){
        System.out.println("restful is running ....get:"+id);
        return "success.jsp";
    }
}

使用ResultFul访问风格之后,那么跳转的页面就是webapp(根目录下)的user文件夹下的页面。这点需要注意。

在实际工作中,我们都是给前端返回json数据,不会进行页面跳转。返回json数据需要@ResponseBody,这个配置的bean文件又需要交由bean管理,所以使用@Controller注解。@RestController注解,作用就是两者的合二为一。

但是现在我们并没有对请求方式进行识别,只是对访问路径进行了设置。

@RequestMapping("/user/")
public class UserController {
    //接收GET请求配置方式
    //@RequestMapping(value = "{id}",method = RequestMethod.GET)
    //接收GET请求简化配置方式,效果等同于上面注解。
    @GetMapping("{id}")
    public String get(@PathVariable Integer id){
        System.out.println("restful is running ....get:"+id);
        return "success.jsp";
    }

    //接收POST请求配置方式
    // @RequestMapping(value = "{id}",method = RequestMethod.POST)
    //接收POST请求简化配置方式
    @PostMapping("{id}")
    public String post(@PathVariable Integer id){
        System.out.println("restful is running ....post:"+id);
        return "success.jsp";
    }

    //接收PUT请求简化配置方式
    //@RequestMapping(value = "{id}",method = RequestMethod.PUT)
    //接收PUT请求简化配置方式
    @PutMapping("{id}")
    public String put(@PathVariable Integer id){
        System.out.println("restful is running ....put:"+id);
        return "success.jsp";
    }
    
    //接收DELETE请求简化配置方式
    //@RequestMapping(value = "{id}",method = RequestMethod.DELETE)
    //接收DELETE请求简化配置方式
    @DeleteMapping("{id}")
    public String delete(@PathVariable Integer id){
        System.out.println("restful is running ....delete:"+id);
        return "success.jsp";
    }
}

现在只需要在浏览器端指定访问的方式即可:但是在浏览器端指定访问方式时,需要注意,表单form的method属性只能指定get/post方式,put和delete方式需要进行另外设置

<form action="/user/1" method="post">
    <%--当添加了name为_method的隐藏域时,可以通过设置该隐藏域的值,修改请求的提交方式,切换为PUT请求或DELETE请求,但是form表单的提交方式method属性必须填写post--%>
    <%--该配置需要配合HiddenHttpMethodFilter过滤器使用,单独使用无效,请注意检查web.xml中是否配置了对应过滤器--%>
    <input type="hidden" name="_method" value="PUT"/>
    <input type="submit"/>
</form>

另外put方式和delete方式需要进行识别还需要配置过滤器,不然后端无法进行识别

在web.xml文件中进行入下配置

<!--配置拦截器,解析请求中的参数_method,否则无法发起PUT请求与DELETE请求,配合页面表单使用-->
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <!--只对serlvet访问进行拦截-->
    <servlet-name>DispatcherServlet</servlet-name>
</filter-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值