zoukankan      html  css  js  c++  java
  • 第7章 Spring MVC的高级技术

    1、配置其它的Servlet和Filter

    按照 AbstractAnnotationConfigDispatcherServletInitializer 的定义,它会创
    建 DispatcherServlet 和 ContextLoaderListener 。但是,如果你想注册其他的 Servlet 、 Filter 或 Listener 的话,那该怎么办呢?
    基于 Java 的初始化器( initializer )的一个好处就在于我们可以定义任意数量的初始化器类。因此,如果我们想往 Web 容器中注册其他组件的
    话,只需创建一个新的初始化器就可以了。最简单的方式就是实现 Spring 的 WebApplicationInitializer 接口。

    不过,如果你只是注册 Filter ,并且该 Filter 只会映射到 DispatcherServlet 上的话,那么
    在 AbstractAnnotationConfigDispatcherServletInitializer 中还有一种快捷方式。
    为了注册 Filter 并将其映射到 DispatcherServlet ,所需要做的仅仅是重
    载 AbstractAnnotationConfigDispatcherServletInitializer 的 getServlet-Filters() 方法。例如,在如下的代码中,重
    载了 AbstractAnnotationConfig-DispatcherServletInitializer 的 getServletFilters() 方法以注册 Filter :

    2、处理 multipart 形式的数据

    简单的说就是form表单的文件框上传的处理,spring mvc需要配置处理器

    从 Spring 3.1 开始, Spring 内置了两个 MultipartResolver 的实现供我们选择:

    • CommonsMultipartResolver :使用 Jakarta Commons FileUpload 解析 multipart 请求;
    • StandardServletMultipartResolver :依赖于 Servlet 3.0 对 multipart 请求的支持(始于 Spring 3.1 )

    这里我们只说Servlet3.0形式的配置,也推荐这种方式,至少不会需要其它第三方的jar包:

    第一步

    兼容 Servlet 3.0 的 StandardServletMultipartResolver 没有构造器参数,也没有要设置的属性。这样,在 Spring 应用上下文中,将其
    声明为 bean 就会非常简单,如下所示:

     

    第二步

    如果我们配置 DispatcherServlet 的 Servlet 初始化类继承了 Abstract
    AnnotationConfigDispatcherServletInitializer 或 AbstractDispatcher-ServletInitializer 的话,那么我们不会直
    接创建 DispatcherServlet 实例并将其注册到 Servlet 上下文中。这样的话,将不会有对 Dynamic Servlet registration 的引用供我们使用
    了。但是,我们可以通过重载 customizeRegistration() 方法(它会得到一个 Dynamic 作为参数)来配置 multipart 的具体细节:

    构造器支持设置参数:

    • 上传文件的最大容量(以字节为单位)。默认是没有限制的。
    • 整个 multipart 请求的最大容量(以字节为单位),不会关心有多少个 part 以及每个 part 的大小。默认是没有限制的。
    • 在上传的过程中,如果文件大小达到了一个指定最大容量(以字节为单位),将会写入到临时文件路径中。默认值为 0 ,也就是所有上传
    • 的文件都会写入到磁盘上

    第三步

    配置好了我们需要在控制器把文件接过来呀,可以使用MultipartFile,当然我们还可以使用Part,

    通过 Part 参数的形式接受文件上传,那么就没有必要配置 MultipartResolver 了。只有使
    用 MultipartFile 的时候,我们才需要 MultipartResolver 。不过需要注意临时路径必须配置,当然自己可以在接受过来之后自己不用提供的接口,自己写保存的逻辑。

    @RequestMapping(value = "/upload", method = RequestMethod.POST)
        public ModelAndView upload(@RequestParam("file") MultipartFile file, HttpServletRequest request){
            String msg = "";
            try {
                File root = new File("D:/uploads/");
                if(!root.exists()){
                   root.mkdir();
                }
                File f = new File("/uploads/"+file.getOriginalFilename());
    
                FileOutputStream fos = new FileOutputStream(f);
                fos.write(file.getBytes());
                fos.flush();
                fos.close();
                msg = "上传成功!";
            } catch (IOException e) {
                e.printStackTrace();
                msg = "上传失败!";
            }
            ModelAndView mav = new ModelAndView("result");
            mav.addObject("msg",msg);
            return mav;
        }
        @RequestMapping(value = "/upload2" , method = RequestMethod.POST)
        public ModelAndView upload2(@RequestParam("file") Part file){
            String msg = "";
            try {
                System.out.println(file.getSubmittedFileName());
                File f = new File("/uploads/"+file.getSubmittedFileName());
                InputStream is = file.getInputStream();
                FileOutputStream fos = new FileOutputStream(f);
                int index;
                byte[] bytes = new byte[1024];
                while ((index = is.read(bytes)) != -1) {
                    fos.write(bytes, 0, index);
                    fos.flush();
                }
                fos.close();
                is.close();
                msg = "上传成功!";
            } catch (IOException e) {
                e.printStackTrace();
                msg = "上传失败!";
            }
            ModelAndView mav = new ModelAndView("result");
            mav.addObject("msg",msg);
            return mav;
        }

    3、处理异常

    Spring 提供了多种方式将异常转换为响应:

    • 特定的 Spring 异常将会自动映射为指定的 HTTP 状态码;
    • 异常上可以添加 @ResponseStatus 注解,从而将其映射为某一个 HTTP 状态码;
    • 在方法上可以添加 @ExceptionHandler 注解,使其用来处理异常。

    特定异常转换为http状态码

    异常上可以添加 @ResponseStatus 注解,从而将其映射为某一个 HTTP 状态码

    import org.springframework.http.HttpStatus;
    import org.springframework.web.bind.annotation.ResponseStatus;
    
    @ResponseStatus(value = HttpStatus.NOT_FOUND , reason = "not found!")
    public class CodeFoundException extends RuntimeException {
        public CodeFoundException(){}
        public CodeFoundException(String msg){
            super(msg);
        }
    }

    在方法上可以添加 @ExceptionHandler 注解,使其用来处理异常

    @RequestMapping(value = "/error" , method = RequestMethod.GET)
        public ModelAndView error(@RequestParam("code") String code){
            if("1".equals(code))
                //throw new CodeFoundException("就是测试一下!");
                throw new DuplicateCodeFoundException("就是测试一下!");
            ModelAndView mav = new ModelAndView("error");
            return mav;
        }
    
        @ExceptionHandler(DuplicateCodeFoundException.class)
        public ModelAndView handleDuplicateCodeFound(){
            ModelAndView mav = new ModelAndView("codefound");
    
            return mav;
        }

    如果控制器类的特定切面能够运用到整个应用程序的所有控制器中,那么这将会便利很多。举例来说,如果要在多个控制器中处理异常,
    那 @ExceptionHandler 注解所标注的方法是很有用的。不过,如果多个控制器类中都会抛出某个特定的异常,那么你可能会发现要在所有
    的控制器方法中重复相同的 @ExceptionHandler 方法。或者,为了避免重复,我们会创建一个基础的控制器类,所有控制器类要扩展这个
    类,从而继承通用的 @ExceptionHandler 方法。
    Spring 3.2 为这类问题引入了一个新的解决方案:控制器通知。控制器通知( controller advice )是任意带有 @ControllerAdvice 注解的类,
    这个类会包含一个或多个如下类型的方法:

    • @ExceptionHandler 注解标注的方法;
    • @InitBinder 注解标注的方法;
    • @ModelAttribute 注解标注的方法。

    在带有 @ControllerAdvice 注解的类中,以上所述的这些方法会运用到整个应用程序所有控制器中带有 @RequestMapping 注解的方法
    上。
    @ControllerAdvice 注解本身已经使用了 @Component ,因此 @ControllerAdvice 注解所标注的类将会自动被组件扫描获取到,就像
    带有 @Component 注解的类一样。

    @ControllerAdvice 最为实用的一个场景就是将所有的 @ExceptionHandler 方法收集到一个类中,这样所有控制器的异常就能在一个地
    方进行一致的处理。例如,我们想将 DuplicateSpittleException 的处理方法用到整个应用程序的所有控制器上。如下的程序清单展现
    的 AppWideExceptionHandler 就能完成这一任务,这是一个带有 @ControllerAdvice 注解的类。

    4、重定向和转发

    在控制器方法返回的视图名称中,我们借助了 “redirect:” 前缀的力量。当控制器方法返回的 String 值以 “redirect:” 开头的
    话,那么这个 String 不是用来查找视图的,而是用来指导浏览器进行重定向的路径

    return new ModelAndView("redirect:/")

    我们知道重定向是会丢失参数的,但是spring有一种保存数据方法使用 flash 属性。 

     

    转发,url不变,参数不丢失,前缀forward:

    return new ModelAndView("forward:/dengluPost")
  • 相关阅读:
    java 13-6 Char的包装类Character
    java13-5 JDK1.5以后的一个新特性和Integer的面试题
    java 13-4 Integer和String、int之间的转换,进制转换
    java 13-3 int类型的包装包Integer
    java 13-2 Arrays工具类
    java 13-1 数组高级二分查找
    java12
    kafka语句示例
    zookeeper安装
    redhat java配置
  • 原文地址:https://www.cnblogs.com/xuzhen97/p/9287495.html
Copyright © 2011-2022 走看看