springmvc第二天

本文详细介绍了SpringMVC中的异步调用,包括发送和接受异步请求参数,以及如何使用@RequestBody注解进行数据映射。此外,还深入探讨了拦截器的概念,对比了拦截器与过滤器的区别,并展示了自定义拦截器的开发过程和配置。同时,文章还讲解了异常处理和文件上传下载的实现,包括HandlerExceptionResolver接口和MultipartResolver的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

异步调用

发送异步请求

 $(function () {
        $("#add_btn").on("click",function () {
           var name=$("input[name='name']").val();
           var username=$("input[name='username']").val();
           var password=$("input[name='password']").val();
           var sex=$("input[name='sex']").val();
           var age=$("input[name='age']").val();
           var birthday=$("input[name='birthday']").val();
           var user={
               name:name,
               username:username,
               password:password,
               sex:sex,
               age:age,
               birthday:birthday
           };
            var str=JSON.stringify(user);
           $.ajax({
               url:"user/ajax_add",
               type:"post",
               data:str,
               dataType:"json",//服务器返回的数据类型是json格式字符串
               contentType:"application/json",//客户端传递参数格式是json格式字符串
               success:function (data){
                   $("#id").html(data.id);
                   $("#name").html(data.name);
                   $("#username").html(data.username);
                   $("#password").html(data.password);
                   $("#sex").html(data.sex);
                   $("#age").html(data.age);
                   $("#birthday").html(data.birthday);
                   $("#createTime").html(data.createTime);
                   alert(data);
               }
           })
        });
    });

接受异步请求参数

@RequestBody

类型: 形参注解
位置:处理器类中的方法形参前方
作用:将异步提交数据组织成标准请求参数格式,并赋值给形参

范例:

@RequestMapping("/ajax_add")
    //@ResponseBody 把服务器端的java对象转换成json格式字符串发送到客户端
    @ResponseBody
    //@RequestBody把客户端传递的json格式字符串转换成java对象
    public User add2(@RequestBody User user){
        System.out.println(user);
        return user;
    }
  • 注解添加到Pojo参数前方时,封装的异步提交数据按照Pojo的属性格式进行关系映射
  • 注解添加到集合参数前方时,封装的异步提交数据按照集合的存储结构进行关系映射
@RequestMapping("/ajaxPojoToController")
//如果处理参数是POJO,且页面发送的请求数据格式与POJO中的属性对应,@RequestBody注解可以自动映射对应请求数据到POJO中
//注意:POJO中的属性如果请求数据中没有,属性值为null,POJO中没有的属性如果请求数据中有,不进行映射
public String  ajaxPojoToController(@RequestBody User user){
    System.out.println("controller pojo :"+user);
    return "page.jsp";
}

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

异步请求接受响应数据

  • 方法返回值为Pojo时,自动封装数据成json对象数据
 @RequestMapping("/ajaxReturnJson")
@ResponseBody
public User ajaxReturnJson(){
    System.out.println("controller return json pojo...");
    User user = new User();
    user.setName("Jockme");
    user.setAge(40);
    return user;
}  
  • 方法返回值为List时,自动封装数据成json对象数组数据
 @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;
}

拦截器

拦截器概念

拦截器( Interceptor)是一种动态拦截方法调用的机制
作用:
   	1. 在指定的方法调用前后执行预先设定后的的代码
 	2. 阻止原始方法的执行

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

拦截器VS过滤器

  • 归属不同: Filter属于Servlet技术, Interceptor属于SpringMVC技术
  • 拦截内容不同: Filter对所有访问进行增强, Interceptor仅针对SpringMVC的访问进行增强

自定义拦截器开发过程

  • 实现HandlerInterceptor接口
    //自定义拦截器需要实现HandleInterceptor接口
public class MyInterceptor implements HandlerInterceptor {
    //处理器运行之前执行
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) throws Exception {
        System.out.println("前置运行----a1");
        //返回值为false将拦截原始处理器的运行
        //如果配置多拦截器,返回值为false将终止当前拦截器后面配置的拦截器的运行
        return true;
    }

    //处理器运行之后执行
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("后置运行----b1");
    }

    //所有拦截器的后置执行全部结束后,执行该操作
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) throws Exception {
        System.out.println("完成运行----c1");
    }

    //三个方法的运行顺序为    preHandle -> postHandle -> afterCompletion
    //如果preHandle返回值为false,三个方法仅运行preHandle
}
  • 配置拦截器
<!--配置自定义拦截器,拦截器业务处理类和拦截的请求地址/**指根路径下所有的请求,不管目录层数-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.entor.interceptor.TestInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
<mvc:interceptors>
    <!--开启具体的拦截器的使用,可以配置多个-->
    <mvc:interceptor>
        <!--设置拦截器的拦截路径,支持*通配-->
        <!--/**         表示拦截所有映射-->
        <!--/*          表示拦截所有/开头的映射-->
        <!--/user/*     表示拦截所有/user/开头的映射-->
        <!--/user/add*  表示拦截所有/user/开头,且具体映射名称以add开头的映射-->
        <!--/user/*All  表示拦截所有/user/开头,且具体映射名称以All结尾的映射-->
        <mvc:mapping path="/*"/>
        <mvc:mapping path="/**"/>
        <mvc:mapping path="/handleRun*"/>
        <!--设置拦截排除的路径,配置/**或/*,达到快速配置的目的-->
        <mvc:exclude-mapping path="/b*"/>
        <!--指定具体的拦截器类-->
        <bean class="MyInterceptor"/>
    </mvc:interceptor>

</mvc:interceptors>
注意:配置顺序为先配置执行位置,后配置执行类

拦截器配置与方法参数

前置处理方法
原始方法之前运行

public boolean preHandle(HttpServletRequest request,
                         HttpServletResponse response,
                         Object handler//目标对象,也就是要访问controller里的方法
                         ) throws Exception {
    System.out.println("preHandle");
    return true;
}

参数

request:请求对象
response:响应对象
handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装

返回值

返回值为false,被拦截的处理器将不执行

后置处理方法
原始方法运行后运行,如果原始方法被拦截,则不执行

 public void postHandle(HttpServletRequest request,
                       HttpServletResponse response,
                       Object handler,
                       ModelAndView modelAndView) throws Exception {
    System.out.println("postHandle");
}

参数

modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整  

完成处理方法
拦截器最后执行的方法,无论原始方法是否执行

public void afterCompletion(HttpServletRequest request,
                            HttpServletResponse response,
                            Object handler,
                            Exception ex) throws Exception {
    System.out.println("afterCompletion");
}

参数

ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理 

多拦截器配置

在这里插入图片描述
责任链模式

责任链模式是一种行为模式
特征:
	沿着一条预先设定的任务链顺序执行,每个节点具有独立的工作任务
优势:
	独立性:只关注当前节点的任务,对其他任务直接放行到下一节点
	隔离性:具备链式传递特征,无需知晓整体链路结构,只需等待请求到达后进行处理即可
	灵活性:可以任意修改链路结构动态新增或删减整体链路责任
解耦:将动态任务与原始任务解耦
弊端:
	链路过长时,处理效率低下
	可能存在节点上的循环引用现象,造成死循环,导致系统崩溃  

异常处理

HandlerExceptionResolver接口(异常处理器)

 @Component
public class ExceptionResolver implements HandlerExceptionResolver {
    public ModelAndView resolveException(HttpServletRequest request,
                                         HttpServletResponse response,
                                         Object handler,
                                         Exception ex) {
        System.out.println("异常处理器正在执行中");
        ModelAndView modelAndView = new ModelAndView();
        //定义异常现象出现后,反馈给用户查看的信息
        modelAndView.addObject("msg","出错啦! ");
        //定义异常现象出现后,反馈给用户查看的页面
        modelAndView.setViewName("error.jsp");
        return modelAndView;
    }
}

根据异常的种类不同,进行分门别类的管理,返回不同的信息

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;
    }
}

注解开发异常处理器

使用注解实现异常分类管理

名称: @ControllerAdvice
类型: 类注解
位置:异常处理器类上方
作用:设置当前类为异常处理器类

使用注解实现异常分类管理

名称: @ExceptionHandler
类型: 方法注解
位置:异常处理器类中针对指定异常进行处理的方法上方
作用:设置指定异常的处理方式
范例:
说明:处理器方法可以设定多个

范例:

 /**
 * @ControllerAdvice+@ExceptionHandler实现全局异常捕获,系统其他类方法中发生异常都会被捕获到
 */
//@ControllerAdvice
    @RestControllerAdvice//相当于@ControllerAdvice+@ExceptionHandler
public class GlobalException {
    @ExceptionHandler(Exception.class)
    public String exception(){
        return "exception";
    }
    @ExceptionHandler(RuntimeException.class)
    public String runtimeException(){
        return "runtimeException";
    }

    @ExceptionHandler(NullPointerException.class)
    public String nullPointerException(){
        return "nullPointerException";
    }

    @ExceptionHandler(ArithmeticException.class)
    public String arithmeticException(){
        return "arithmeticException";
    }
}

文件上传下载

MultipartResolver接口

  • MultipartResolver接口定义了文件上传过程中的相关操作,并对通用性操作进行了封装
  • MultipartResolver接口底层实现类CommonsMultipartResovler
  • CommonsMultipartResovler并未自主实现文件上传下载对应的功能,而是调用了apache的文件上传下载组件
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

文件上传
controller代码

<body>
    <form method="post" enctype="multipart/form-data" action="uploadfile">
        文件:<input type="file" name="file"><br>
        文件:<input type="file" name="file"><br>
        文件:<input type="file" name="file"><br>
            <input type="submit" value="上传"/>
    </form>
</body>

jsp页面

@Controller
public class UploadController {
    @RequestMapping("/uploadfile")
    public String uploadFile(MultipartFile[] file, HttpServletRequest request){
        //获取服务器存放上传文件的绝对路径
        String realPath = request.getServletContext().getRealPath("upload");
        File f=new File(realPath);
        if(!f.exists()){//判断文件是否存在,不存在则创建
            f.mkdirs();
        }
        System.out.println(f);

       for(MultipartFile ff:file){
           //获取上传文件的名称
           String filename = ff.getOriginalFilename();
           //获取上传文件的大小
           long size = ff.getSize();
           //获取上传文件类型
           String contentType = ff.getContentType();
           try {
               ff.transferTo(new File(f,filename));
           } catch (IOException e) {
               e.printStackTrace();
           }
       }

        return "success";
    }
}

文件下载
jsp页面

<head>
    <title>文件下载</title>
</head>
<body>
<a href="downLoad?filename=4.jpg">4.jpg</a><br>
<a href="downLoad?filename=3.jpg">3.jpg</a><br>
<a href="downLoad?filename=1.jpg">1.jpg</a><br>
</body>
</html>

controller代码

public class DownloadController {
    @RequestMapping("/downLoad")
    public ResponseEntity<byte[]> downLoad(HttpServletRequest request, HttpServletResponse response , String filename ) throws IOException {
    //服务器上下载文件存放绝对路径地址
        String realPath = request.getServletContext().getRealPath("upload");
        //下载文件对象
        File file=new File(realPath,filename);
        FileInputStream fis = new FileInputStream(file);
        //创建文件大小的字节数组缓冲区
        byte[] b = new byte[fis.available()];
        //把文件内容读取到数组中
        fis.read(b);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add("Content-Disposition","attachment;filename="+ URLEncoder.encode(file.getName(),"utf-8"));
        return new ResponseEntity<>(b,httpHeaders, HttpStatus.OK);

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值