• 《Spring in action 4》(七)SpringMVC高级技术


    SpringMVC高级技术

    通过web.xml加载JavaConfig配置

    ​ 我们前面使用了纯web.xml形式加载applicationContext.xml和springmvc.xml配置文件来搭建一个web项目,也使用AbstractAnnotationConfigDispatcherServletInitializer纯java配置的形式加载ServletConfig.java和RootConfig.java配置类来搭建web项目,这次我们使用web.xml形式结合ServletConfig.java和RootConfig.java搭建项目。

    web.xml文件如下:

    <!DOCTYPE web-app PUBLIC
     "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
     "http://java.sun.com/dtd/web-app_2_3.dtd" >
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
    
      <!--使用 Java配置形式来加载ApplicationContext/RootConfig.java配置类-->
      <context-param>
        <param-name>contextClass</param-name>
        <param-value>
          org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
      </context-param>
      <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.ooyhao.spring.config.RootConfig</param-value>
      </context-param>
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
      </listener>
      
      <!--配置 Java配置形式的DispatcherServlet-->
      <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextClass</param-name>
          <param-value>
       	org.springframework.web.context.support.AnnotationConfigWebApplicationContext
          </param-value>
        </init-param>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>com.ooyhao.spring.config.ServletConfig</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>
    

    web加载配置类实现上传文件

    POM文件

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.ooyhao.spring</groupId>
      <artifactId>spring-in-action-07-01</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
    
      <name>spring-in-action-07-01 Maven Webapp</name>
      <url>http://www.example.com</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    
        <!--导入Servlet依赖-->
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>4.0.1</version>
        </dependency>
    
        <!--导入SpringMVC依赖-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.1.9.RELEASE</version>
        </dependency>
    
        <!--导入Jackson依赖-->
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.9.8</version>
        </dependency>
    
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-annotations</artifactId>
          <version>2.9.8</version>
        </dependency>
    
        <!--Junit测试依赖-->
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    
        <!--hibernate参数校验依赖-->
        <dependency>
          <groupId>org.hibernate.validator</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>6.1.0.Alpha3</version>
        </dependency>
    
        <!--整合Thymeleaf-->
        <dependency>
          <groupId>org.thymeleaf</groupId>
          <artifactId>thymeleaf</artifactId>
          <version>3.0.11.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.thymeleaf</groupId>
          <artifactId>thymeleaf-spring5</artifactId>
          <version>3.0.9.RELEASE</version>
        </dependency>
        
      </dependencies>
      <build>
        <finalName>spring-in-action-07-01</finalName>
        <pluginManagement>
          <plugins>
            <plugin>
              <artifactId>maven-clean-plugin</artifactId>
              <version>3.1.0</version>
            </plugin>
            <plugin>
              <artifactId>maven-resources-plugin</artifactId>
              <version>3.0.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.8.0</version>
            </plugin>
            <plugin>
              <artifactId>maven-surefire-plugin</artifactId>
              <version>2.22.1</version>
            </plugin>
            <plugin>
              <artifactId>maven-war-plugin</artifactId>
              <version>3.2.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-install-plugin</artifactId>
              <version>2.5.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-deploy-plugin</artifactId>
              <version>2.8.2</version>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    </project>
    

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://java.sun.com/xml/ns/javaee"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
             id="WebApp_ID" version="3.0">
      <display-name>Archetype Created Web Application</display-name>
    
      <!--使用 Java配置形式来加载ApplicationContext/RootConfig.java配置类-->
      <context-param>
        <param-name>contextClass</param-name>
        <param-value>
          org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
      </context-param>
      <context-param>
        <param-name> contextConfigLocation</param-name>
        <param-value>com.ooyhao.spring.config.RootConfig</param-value>
      </context-param>
      <listener>
        <listener-class>
          org.springframework.web.context.ContextLoaderListener
        </listener-class>
      </listener>
    
      <!--配置 Java配置形式的DispatcherServlet-->
      <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>
          org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
          <param-name>contextClass</param-name>
          <param-value>
          org.springframework.web.context.support.AnnotationConfigWebApplicationContext
          </param-value>
        </init-param>
    
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>com.ooyhao.spring.config.ServletConfig</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <multipart-config>
          <location>D:data</location>
          <max-file-size>52428800</max-file-size>
          <max-request-size>52428800</max-request-size>
          <file-size-threshold>0</file-size-threshold>
        </multipart-config>
      </servlet>
      <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>
    

    我们这里使用了web.xml文件来加载配置类的形式搭建web项目。为了实现文件上传,我们可以看出这个web.xml中与前一节不同的是,多个下面几行代码:

    <multipart-config>
      <location>D:data</location>
      <max-file-size>52428800</max-file-size>
      <max-request-size>52428800</max-request-size>
      <file-size-threshold>0</file-size-threshold>
    </multipart-config>
    

    这个就是用于配置文件上传的一些信息,

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

    ServletConfig

    /**
     * 描述:
     * 类【ServletConfig】
     *
     * @author ouYangHao
     * @create 2019-09-09 16:19
     */
    /*相当于springmvc.xml*/
    @Configuration
    @EnableWebMvc
    @ComponentScan(basePackages = "com.ooyhao.spring.**.controller")
    public class ServletConfig{
    
        @Bean
        public MultipartResolver multipartResolver(){
            StandardServletMultipartResolver resolver = 
              new StandardServletMultipartResolver();
            return resolver;
        }
    
        @Bean
        public SpringResourceTemplateResolver templateResolver(){
            SpringResourceTemplateResolver resolver = 
              new SpringResourceTemplateResolver();
            resolver.setPrefix("/WEB-INF/templates/");
            resolver.setSuffix(".html");
            resolver.setCharacterEncoding("utf-8");
            resolver.setCacheable(true);
            resolver.setTemplateMode(TemplateMode.HTML);
            return resolver;
        }
    
        @Bean
        public SpringTemplateEngine templateEngine(){
            SpringTemplateEngine engine = new SpringTemplateEngine();
            engine.setTemplateResolver(templateResolver());
            engine.setEnableSpringELCompiler(true);
            return engine;
        }
    
        @Bean
        public ThymeleafViewResolver viewResolver(){
            ThymeleafViewResolver resolver = new ThymeleafViewResolver();
            resolver.setCharacterEncoding("utf-8");
            resolver.setTemplateEngine(templateEngine());
            return resolver;
        }
    }
    

    配置文件中与以往不同的是,增加了一个MultipartResolver。

    register.html

    <!DOCTYPE html>
    <html  xmlns="http://www.w3.org/1999/xhtml"
           xmlns:th="http://www.thymeleaf.org">
    <head>
        <title>Blog</title>
        <meta charset="utf-8">
    </head>
    
        <style>
            span.error{
                color:red;
            }
            div.errors{
                background-color: #ffcccc;
                border: 2px solid red;
            }
            label.error{
                color:red;
            }
            input.error{
                background-color: #ffcccc;
            }
        </style>
    
    </head>
    <body>
    
        <h1>欢迎加入Spring的大家庭</h1>
    
        <form method="post" th:object="${user}" enctype="multipart/form-data" >
            <div class="errors" th:if="${#fields.hasErrors('*')}" >
                <ul>
                    <li th:each="err : ${#fields.errors('*')}" th:text="${err}"  >
                        Input is Incorrect
                    </li>
                </ul>
            </div>
            <label th:class="${#fields.hasErrors('username')} ? 'error' ">
              账号:
            </label>
            <input type="text"  th:field="*{username}" 
                   th:class="${#fields.hasErrors('username')} ? 'error'"/><br>
            <label th:class="${#fields.hasErrors('password')} ? 'error' ">
              密码:</label>
            <input type="password" th:field="*{password}" 
                   th:class="${#fields.hasErrors('password')} ? 'error'" /><br>
            <label th:class="${#fields.hasErrors('age')} ? 'error' ">年龄:</label>
            <input th:field="*{age}"  
                   th:class="${#fields.hasErrors('age')} ? 'error'"/><br>
            <label> 图片:</label>
            <input type="file" name="file" 
                   accept="image/jpeg,image/png,image/gif" ><br>
            <input type="submit" value="提交" ><br>
        </form>
    </body>
    </html>
    

    IndexController.java

    package com.ooyhao.spring.controller;
    
    import com.ooyhao.spring.bean.User;
    import com.ooyhao.spring.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.validation.Valid;
    import java.io.File;
    import java.io.IOException;
    
    @Controller
    public class IndexController {
    
        @Autowired
        private UserService userService;
    
        @GetMapping("/")
        public String home(){
            return "home";
        }
    
        @GetMapping("/register")
        public String toRegister(Model model){
            model.addAttribute("user",new User());
            return "register";
        }
    
        /*处理表单数据,并验证*/
        @PostMapping("/register")
        public String register(@Valid User user, MultipartFile file, 
                               BindingResult bindingResult, Model model) 
          throws IOException {
            if (bindingResult.hasErrors()){
                System.out.println("错误数目:" + bindingResult.getErrorCount());
                model.addAttribute(user);
                return "register";//注册失败,重新返回到注册页面
            }
            if (!file.isEmpty()){
                file.transferTo(
                  new File(System.currentTimeMillis()
                           +file.getOriginalFilename().substring(
        						file.getOriginalFilename().indexOf("."))));
            }
            userService.saveUser(user);
            return "redirect:/registerSuccess";
        }
    
        @GetMapping("/registerSuccess")
        public String registerSuccess(){
            return "registerSuccess";
        }
    
        @GetMapping("/registerFail")
        public String registerFail(){
            return "registerFail";
        }
    }
    

    Controller接收前端上传文件普通方式是使用byte[],或是Part接收,如下:

    @PostMapping("/register")
    public String register(@RequestPart("file") byte[] file){}
    
    
    @PostMapping("/register")
    public String register(@RequestPart("file") Part file){}
    

    但是,我们一般是使用SpringMVC的MultipartFile来接收文件。下面看一下这个接口的方法:

    public interface MultipartFile extends InputStreamSource {
    
    	String getName();
    
    	@Nullable
    	String getOriginalFilename();
    
    	@Nullable
    	String getContentType();
    
    	boolean isEmpty();
    
    	long getSize();
    
    	byte[] getBytes() throws IOException;
    
    	@Override
    	InputStream getInputStream() throws IOException;
    
    	default Resource getResource() {
    		return new MultipartFileResource(this);
    	}
    
    	void transferTo(File dest) throws IOException, IllegalStateException;
    
    	default void transferTo(Path dest) throws IOException, IllegalStateException {
    		FileCopyUtils.copy(getInputStream(), Files.newOutputStream(dest));
    	}
    }
    

    效果图:

    纯配置文件形式实现文件上传

    POM依赖

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
      http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.ooyhao.spring</groupId>
      <artifactId>spring-in-action-07-02</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
    
      <name>spring-in-action-07-02 Maven Webapp</name>
      <url>http://www.example.com</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    
        <!--导入Servlet依赖-->
        <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>4.0.1</version>
        </dependency>
    
        <!--导入SpringMVC依赖-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>5.1.9.RELEASE</version>
        </dependency>
    
        <!--导入Jackson依赖-->
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-databind</artifactId>
          <version>2.9.8</version>
        </dependency>
    
        <dependency>
          <groupId>com.fasterxml.jackson.core</groupId>
          <artifactId>jackson-annotations</artifactId>
          <version>2.9.8</version>
        </dependency>
    
        <!--Junit测试依赖-->
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
    
        <!--hibernate参数校验依赖-->
        <dependency>
          <groupId>org.hibernate.validator</groupId>
          <artifactId>hibernate-validator</artifactId>
          <version>6.1.0.Alpha3</version>
        </dependency>
    
        <!--整合Thymeleaf-->
        <dependency>
          <groupId>org.thymeleaf</groupId>
          <artifactId>thymeleaf</artifactId>
          <version>3.0.11.RELEASE</version>
        </dependency>
    
        <dependency>
          <groupId>org.thymeleaf</groupId>
          <artifactId>thymeleaf-spring5</artifactId>
          <version>3.0.9.RELEASE</version>
        </dependency>
      </dependencies>
    
      <build>
        <finalName>spring-in-action-07-02</finalName>
        <pluginManagement>
          <plugins>
            <plugin>
              <artifactId>maven-clean-plugin</artifactId>
              <version>3.1.0</version>
            </plugin>
            <plugin>
              <artifactId>maven-resources-plugin</artifactId>
              <version>3.0.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.8.0</version>
            </plugin>
            <plugin>
              <artifactId>maven-surefire-plugin</artifactId>
              <version>2.22.1</version>
            </plugin>
            <plugin>
              <artifactId>maven-war-plugin</artifactId>
              <version>3.2.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-install-plugin</artifactId>
              <version>2.5.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-deploy-plugin</artifactId>
              <version>2.8.2</version>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    </project>
    

    WebInit

    public class WebInit extends 
      AbstractAnnotationConfigDispatcherServletInitializer  {
    
    
        /*配置文件上传的一些参数*/
        /**
         *  MultipartConfigElement与 <multipart-config></multipart-config> 的默认值相同。
         *  都必须配置保存路径。
         * @param registration
         */
        @Override
        protected void customizeRegistration(
          ServletRegistration.Dynamic registration){
            MultipartConfigElement configElement = new MultipartConfigElement(
                    "D:\data\upload\",
                    52428800,
                    52428800,
                    0);
            registration.setMultipartConfig(configElement);
        }
    
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class[]{
                    RootConfig.class
            };
        }
    
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class[]{
                    ServletConfig.class
            };
        }
    
        @Override
        protected String[] getServletMappings() {
            return new String[]{
                    "/"
            };
        }
    }
    

    RootConfig.java

    package com.ooyhao.spring.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.FilterType;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    
    @ComponentScan(basePackages = "com.ooyhao.spring", useDefaultFilters = true,excludeFilters = {
            @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = EnableWebMvc.class)
    })
    @Configuration
    public class RootConfig {
    
    }
    

    ServletConfig.java

    package com.ooyhao.spring.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.multipart.MultipartResolver;
    import org.springframework.web.multipart.support.StandardServletMultipartResolver;
    import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
    import org.springframework.web.servlet.config.annotation.EnableWebMvc;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import org.thymeleaf.spring5.SpringTemplateEngine;
    import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
    import org.thymeleaf.spring5.view.ThymeleafViewResolver;
    import org.thymeleaf.templatemode.TemplateMode;
    
    @EnableWebMvc //开启webmvc
    @ComponentScan(basePackages = "com.ooyhao.spring.**.controller")
    @Configuration //标注为一个配置类
    public class ServletConfig implements WebMvcConfigurer {
    
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
    
        /*配置文件上传*/
        @Bean
        public MultipartResolver multipartResolver(){
            StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
            return resolver;
        }
    
        /*配置模板解析器*/
        @Bean
        public SpringResourceTemplateResolver templateResolver(){
            SpringResourceTemplateResolver resolver =
                    new SpringResourceTemplateResolver();
            resolver.setCacheable(true);
            resolver.setPrefix("/WEB-INF/templates/");
            resolver.setSuffix(".html");
            resolver.setCharacterEncoding("utf-8");
            resolver.setTemplateMode(TemplateMode.HTML);
            return resolver;
        }
    
        /*配置模板引擎*/
        @Bean
        public SpringTemplateEngine templateEngine(){
            SpringTemplateEngine engine = new SpringTemplateEngine();
            engine.setEnableSpringELCompiler(true);
            engine.setTemplateResolver(templateResolver());
            return engine;
        }
    
        /*配置视图解析器*/
        @Bean
        public ThymeleafViewResolver thymeleafViewResolver(){
            ThymeleafViewResolver resolver = new ThymeleafViewResolver();
            resolver.setTemplateEngine(templateEngine());
            resolver.setCharacterEncoding("utf-8");
            return resolver;
        }
    }
    

    IndexController

    package com.ooyhao.spring.controller;
    
    import com.ooyhao.spring.bean.User;
    import com.ooyhao.spring.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.validation.BindingResult;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.validation.Valid;
    import java.io.File;
    import java.io.IOException;
    
    @Controller
    public class IndexController {
    
        @Autowired
        private UserService userService;
    
        @GetMapping("/")
        public String home(){
            return "home";
        }
    
        @GetMapping("/register")
        public String toRegister(Model model){
            model.addAttribute("user",new User());
            return "register";
        }
    
        /*处理表单数据,并验证*/
        @PostMapping("/register")
        public String register(@Valid User user, MultipartFile file, BindingResult bindingResult, Model model) throws IOException {
            if (bindingResult.hasErrors()){
                System.out.println("错误数目:" + bindingResult.getErrorCount());
                model.addAttribute(user);
                return "register";//注册失败,重新返回到注册页面
            }
            if (!file.isEmpty()){
                file.transferTo(new File(System.currentTimeMillis()+file.getOriginalFilename().substring(file.getOriginalFilename().indexOf("."))));
            }
            userService.saveUser(user);
            return "redirect:/registerSuccess";
        }
    
        @GetMapping("/registerSuccess")
        public String registerSuccess(){
            return "registerSuccess";
        }
    
        @GetMapping("/registerFail")
        public String registerFail(){
            return "registerFail";
        }
    }
    

    效果

    总结

    ​ 至此,我们已经实现了使用纯Java配置的方式搭建了一个Springweb项目,并且通过配置的方式实现了文件上传。

    处理异常

    使用@ResponseStatus

    我们看一下下面这个代码:

    /*将参数写到路径上*/
    @GetMapping("/article/{id}")
    @ResponseBody
    public Article article(@PathVariable(value = "id") Integer id){
        Article article = null;
        try{
          article = articleService.findArticleById(id);
        }catch (ArticleNotFoundException e){
          e.printStackTrace();
        }
        return article;
    }
    
    //Service:
    public Article findArticleById(Integer id) {
      Article article = articles.get(id);
      if (article == null){
        throw new ArticleNotFoundException();
      }
      return article;
    }
    
    
    public class ArticleNotFoundException extends RuntimeException {}
    

    当我们访问时,如果findArticleById(id)查询出来为空时,按照当前的代码,会报500错误,但是正常情况我们希望抛出的是404.所以,在定义异常的时候,可以定义为:

    @ResponseStatus(value = HttpStatus.NOT_FOUND,reason = "Not Found")
    public class ArticleNotFoundException extends RuntimeException {}
    

    我们看一下@ResponseStatus注解

    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface ResponseStatus {
    
    	@AliasFor("code")
    	HttpStatus value() default HttpStatus.INTERNAL_SERVER_ERROR;
    
    	@AliasFor("value")
    	HttpStatus code() default HttpStatus.INTERNAL_SERVER_ERROR;
    
    	String reason() default "";
    }
    

    测试结果:

    编写异常处理方法

    如上一节中处理异常方法所示,在Handler中既包含正常业务逻辑代码,有包含处理异常的代码,那么有什么方法可以将异常处理代码剥离出来,Handler中只处理业务逻辑。

    @GetMapping("/article/{id}")
    @ResponseBody
    public Article article(@PathVariable(value = "id") Integer id){
     	Article article = articleService.findArticleById(id);
      	return article;
    }
    

    编写异常方法,即在当前controller中添加下列方法:

    @ExceptionHandler(ArticleNotFoundException.class)
    @ResponseBody
    public Map<String,Object> handleNotFoundException(){
        Map<String,Object> map = new HashMap<>();
        map.put("code",404);
        map.put("message","数据未查询到");
        return map;
    }
    

    测试结果:

    控制器通知处理异常

    ​ 我们都知道,在正常的项目中,我们不可能将所有的处理方法都写在一个Controller中,为了区分业务模块,我们会将所有的controller方法划分在不同的controller类中。如果此时还是使用上述处理方法来处理异常的话,那么我们会发现很多相同的处理异常的代码。Spring3.2之后,有了统一的处理方案就是使用@ControllerAdvice。

    https://www.cnblogs.com/yanggb/p/10859907.html

    包含@ControllerAdvice的方法可以包含一个或多个如下类型的方法:

    • @ExceptionHandler标注的方法
    • @InitBinder标注的方法
    • @ModelAttribute标注的方法

    @ExceptionHandler

    /**
    @ExceptionHandler的作用主要在于声明一个或多个类型的异常,当符合条件的Controller抛出这些异常之后将会对这些异常进行捕获,然后按照其标注的方法的逻辑进行处理,从而改变返回的视图信息。
     */ 
    @ControllerAdvice
    public class SpringControllerAdvice {
        @ExceptionHandler(RuntimeException.class)
        public ModelAndView runtimeExceptionHandler(RuntimeException e) {
            e.printStackTrace();
            return new ModelAndView("error");
        }
    }
    

    @InitBandler

    /**
    	对于@InitBinder,该注解的主要作用是绑定一些自定义的参数。一般情况下我们使用的参数通过@RequestParam,@RequestBody或者@ModelAttribute等注解就可以进行绑定了,但对于一些特殊类型参数,比如Date,它们的绑定Spring是没有提供直接的支持的,我们只能为其声明一个转换器,将request中字符串类型的参数通过转换器转换为Date类型的参数,从而供给@RequestMapping标注的方法使用。
    */
    @ControllerAdvice
    public class SpringControllerAdvice {
        @InitBinder
        public void globalInitBinder(WebDataBinder binder) {
            binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
      }
    }
    

    @ModelAttribute

    /**
    关于@ModelAttribute的用法,除了用于方法参数时可以用于转换对象类型的属性之外,其还可以用来进行方法的声明。如果声明在方法上,并且结合@ControllerAdvice,该方法将会在@ControllerAdvice所指定的范围内的所有接口方法执行之前执行,并且@ModelAttribute标注的方法的返回值还可以供给后续会调用的接口方法使用。
     */ 
    public class GlobalExceptionHandler {
    	@ModelAttribute
      	//应用到所有@RequestMapping注解方法
     	 //此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对
     	 public void addUser(Model model) { 
      		model.addAttribute("msg", "此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对");
         }
    }  
    

    实例

    @ControllerAdvice    
    public class GlobalExceptionHandler {    
    
        private final static String ERROR_PAGE = "error";    
    	
      	//异常处理
        @ExceptionHandler(Exception.class)    
        public ModelAndView handle(Exception e){     
            ModelAndView mv = new ModelAndView();    
            mv.addObject("message", e.getMessage());    
            mv.setViewName(ERROR_PAGE);    
            return mv;    
        }    
    
        @ModelAttribute
        //应用到所有@RequestMapping注解方法
        //此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对
        public void addUser(Model model) { 
            model.addAttribute("msg", "此处将键值对添加到全局,注解了@RequestMapping的方法都可以获得此键值对");
        }  
    
        @InitBinder  
        //应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
        //用来设置WebDataBinder,用于自动绑定前台请求参数到Model中。
        public void initBinder(WebDataBinder binder) {  
        } 
    } 
    

    全局异常处理

    /**
     * 描述:
     * 类【GlobalExceptionHandler】
     *
     * @author ouYangHao
     * @create 2019-09-10 10:51
     */
    @ControllerAdvice
    public class GlobalExceptionHandler {
    
        @ExceptionHandler(ArticleNotFoundException.class)
        @ResponseBody
        public Map<String,Object> handleNotFoundException(){
            Map<String,Object> map = new HashMap<>();
            map.put("code",404);
            map.put("message","数据未查询到");
            return map;
        }
    }
    

    跨重定向请求传递数据

    使用URL模板进行重定向

    可以使用下列方式来传递参数

    /*将参数写到路径上*/
      @GetMapping("/article/{id}")
      public String article(@PathVariable(value = "id") Integer id, Model model){
      model.addAttribute("id",id);
      model.addAttribute("username","ooyhao");
      return "redirect:/article/id/{id}";
    }
    
    
    @RequestMapping("/article/id/{id}")
    @ResponseBody
    public String articleId(@PathVariable(value = "id") Integer id){
      return "id:"+id;
    }
    

    ​ 但是上述方式只能传递普通参数,当我们需要传递对象的时候,这种方式就无能为力了。此时我们可以使用Spring flash来传递。

    代码如下:

    @GetMapping("/article/{id}")
    public String article(@PathVariable(value = "id") Integer id, RedirectAttributes attributes){
        Article article = articleService.findArticleById(id);
        attributes.addAttribute("id",id);
        attributes.addAttribute("username","ooyhao");
        attributes.addFlashAttribute(article);
        return "redirect:/article/id/{id}";
    }
    
    
    @RequestMapping("/article/id/{id}")
    @ResponseBody
    public Map<String,Object> articleId(@PathVariable(value = "id") Integer id,String username, Model model){
        Map<String,Object> map = new HashMap<>();
        map.put("id",id);
        map.put("username",username);
        map.put("article",model.asMap().get("article"));
        return map;
    }
    

    测试结果:

    总结:本节实现了文件上传,异常处理,以及跨重定向请求传递参数。

    源码:

    https://gitee.com/ooyhao/JavaRepo_Public/tree/master/Spring-in-Action/spring-in-action-07

    最后

    如果觉得不错的话,那就关注一下小编哦!一起交流,一起学习

    程序yuan
  • 相关阅读:
    摄像机标定公式推导
    roscpp源码阅读
    机器学习(Machine Learning)&深度学习(Deep Learning)资料汇总 (上)
    机器学习(Machine Learning)&深度学习(Deep Learning)资料(下)
    【概率论与数理统计】全概率公式和贝叶斯公式
    机器学习之一些基本概念及符号系统
    机器学习之代价函数(cost function)
    机器学习之逻辑回归(Logistic Regression)
    机器学习之神经网络模型-下(Neural Networks: Representation)
    机器学习之神经网络模型-上(Neural Networks: Representation)
  • 原文地址:https://www.cnblogs.com/ooyhao/p/11561821.html
Copyright © 2020-2023  润新知