zoukankan      html  css  js  c++  java
  • Java方式配置Spring MVC

    概述

      使用Java方式配置Spring MVC,以及回顾一下Spring MVC的各种用法。


    Spring MVC简述

      关于Spring MVC的介绍网上有很多,这里就不再赘述了,只是要说一下,Spring MVC中的“MVC”是什么意思,它和三层架构是什么关系。

      可能有很多人说,在三层架构中,M就是数据访问层,V就是展现层,C就是应用层。

      听上去很有道理,但其实MVC就是数据模型(Model)+视图(View)+控制器(Controller),在Spring MVC中,有一个专门的类叫Model,用来和V之间的数据交互、传值;V指的是视图页面,包含JSP、Thymeleaf等;C就是控制器。MVC只存在于三层架构中的展现层。

    搭建一个Spring MVC项目

      1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      2     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      3     <modelVersion>4.0.0</modelVersion>
      4     <groupId>com.wisely</groupId>
      5     <artifactId>highlight_springmvc4</artifactId>
      6     <version>0.0.1-SNAPSHOT</version>
      7     <packaging>war</packaging>
      8 
      9     <properties>
     10         <!-- Generic properties -->
     11         <java.version>1.7</java.version>
     12         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     13         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
     14         <!-- Web -->
     15         <jsp.version>2.2</jsp.version>
     16         <jstl.version>1.2</jstl.version>
     17         <servlet.version>3.1.0</servlet.version>
     18         <!-- Spring -->
     19         <spring-framework.version>4.1.5.RELEASE</spring-framework.version>
     20         <!-- Logging -->
     21         <logback.version>1.0.13</logback.version>
     22         <slf4j.version>1.7.5</slf4j.version>
     23     </properties>
     24 
     25     <dependencies>
     26         <dependency>
     27             <groupId>javax</groupId>
     28             <artifactId>javaee-web-api</artifactId>
     29             <version>7.0</version>
     30             <scope>provided</scope>
     31         </dependency>
     32 
     33         <!-- Spring MVC -->
     34         <dependency>
     35             <groupId>org.springframework</groupId>
     36             <artifactId>spring-webmvc</artifactId>
     37             <version>${spring-framework.version}</version>
     38         </dependency>
     39 
     40         <!-- 其他web依赖 -->
     41         <dependency>
     42             <groupId>javax.servlet</groupId>
     43             <artifactId>jstl</artifactId>
     44             <version>${jstl.version}</version>
     45         </dependency>
     46         
     47         <dependency>
     48             <groupId>javax.servlet</groupId>
     49             <artifactId>javax.servlet-api</artifactId>
     50             <version>${servlet.version}</version>
     51             <scope>provided</scope>
     52         </dependency>
     53         
     54         <dependency>
     55             <groupId>javax.servlet.jsp</groupId>
     56             <artifactId>jsp-api</artifactId>
     57             <version>${jsp.version}</version>
     58             <scope>provided</scope>
     59         </dependency>
     60 
     61         <!-- Spring and Transactions -->
     62         <dependency>
     63             <groupId>org.springframework</groupId>
     64             <artifactId>spring-tx</artifactId>
     65             <version>${spring-framework.version}</version>
     66         </dependency>
     67 
     68         <!-- 使用SLF4J和LogBack作为日志 -->
     69         <dependency>
     70             <groupId>org.slf4j</groupId>
     71             <artifactId>slf4j-api</artifactId>
     72             <version>${slf4j.version}</version>
     73         </dependency>
     74         <dependency>
     75             <groupId>log4j</groupId>
     76             <artifactId>log4j</artifactId>
     77             <version>1.2.16</version>
     78         </dependency>
     79         <dependency>
     80             <groupId>org.slf4j</groupId>
     81             <artifactId>jcl-over-slf4j</artifactId>
     82             <version>${slf4j.version}</version>
     83         </dependency>
     84         <dependency>
     85             <groupId>ch.qos.logback</groupId>
     86             <artifactId>logback-classic</artifactId>
     87             <version>${logback.version}</version>
     88         </dependency>
     89         <dependency>
     90             <groupId>ch.qos.logback</groupId>
     91             <artifactId>logback-core</artifactId>
     92             <version>${logback.version}</version>
     93         </dependency>
     94         <dependency>
     95             <groupId>ch.qos.logback</groupId>
     96             <artifactId>logback-access</artifactId>
     97             <version>${logback.version}</version>
     98         </dependency>
     99 
    100         <!--对json和xml格式的支持 -->
    101         <dependency>
    102             <groupId>com.fasterxml.jackson.dataformat</groupId>
    103             <artifactId>jackson-dataformat-xml</artifactId>
    104             <version>2.5.3</version>
    105         </dependency>
    106 
    107         <!-- file upload -->
    108         <dependency>
    109             <groupId>commons-fileupload</groupId>
    110             <artifactId>commons-fileupload</artifactId>
    111             <version>1.3.1</version>
    112         </dependency>
    113         <!-- 非必需,可简化IO操作 -->
    114         <dependency>
    115             <groupId>commons-io</groupId>
    116             <artifactId>commons-io</artifactId>
    117             <version>2.3</version>
    118         </dependency>
    119 
    120         <dependency>
    121             <groupId>org.springframework</groupId>
    122             <artifactId>spring-test</artifactId>
    123             <version>${spring-framework.version}</version>
    124             <scope>test</scope>
    125         </dependency>
    126         
    127     
    128         <dependency>
    129             <groupId>junit</groupId>
    130             <artifactId>junit</artifactId>
    131             <version>4.11</version>
    132             <scope>test</scope>
    133         </dependency>
    134 
    135     </dependencies>
    136 
    137     <build>
    138         <plugins>
    139             <plugin>
    140                 <groupId>org.apache.maven.plugins</groupId>
    141                 <artifactId>maven-compiler-plugin</artifactId>
    142                 <version>2.3.2</version>
    143                 <configuration>
    144                     <source>${java.version}</source>
    145                     <target>${java.version}</target>
    146                 </configuration>
    147             </plugin>
    148             <plugin>
    149                 <groupId>org.apache.maven.plugins</groupId>
    150                 <artifactId>maven-war-plugin</artifactId>
    151                 <version>2.3</version>
    152                 <configuration>
    153                     <failOnMissingWebXml>false</failOnMissingWebXml>
    154                 </configuration>
    155             </plugin>
    156         </plugins>
    157     </build>
    158 </project>
    pom.xml(Maven)
     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <configuration scan="true" scanPeriod="1 seconds">
     3     <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
     4         <resetJUL>true</resetJUL>
     5     </contextListener>
     6     <jmxConfigurator/>
     7     <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
     8         <encoder>
     9             <pattern>logbak: %d{HH:mm:ss.SSS} %logger{36} - %msg%n</pattern>
    10         </encoder>
    11     </appender>
    12     <!--将org.springframework.web包下的类的日志级别设置为DEBUG,在开发Spring MVC时经常出现和参数类型相关的4XX错误,设置-->
    13     <!--此项可以看到更详细的错误信息-->
    14     <logger name="org.springframework.web" level="DEBUG"/>
    15     <root level="info">
    16         <appender-ref ref="console"/>
    17     </root>
    18 </configuration>
    logback.xml(日志配置)
     1 <%@ page language="java" contentType="text/html; charset=UTF-8"
     2     pageEncoding="UTF-8"%>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     4 <html>
     5 <head>
     6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     7 <title>Insert title here</title>
     8 </head>
     9 <body>
    10     <pre>
    11         Welcome to Spring MVC world
    12     </pre>
    13 </body>
    14 </html>
    index.jsp(演示页面)
      1 package com.wisely.highlight_springmvc4;
      2 
      3 import com.wisely.highlight_springmvc4.interceptor.DemoInterceptor;
      4 import com.wisely.highlight_springmvc4.messageconverter.MyMessageConverter;
      5 import org.springframework.context.annotation.Bean;
      6 import org.springframework.context.annotation.ComponentScan;
      7 import org.springframework.context.annotation.Configuration;
      8 import org.springframework.http.converter.HttpMessageConverter;
      9 import org.springframework.scheduling.annotation.EnableScheduling;
     10 import org.springframework.web.multipart.MultipartResolver;
     11 import org.springframework.web.multipart.commons.CommonsMultipartResolver;
     12 import org.springframework.web.servlet.config.annotation.*;
     13 import org.springframework.web.servlet.view.InternalResourceViewResolver;
     14 import org.springframework.web.servlet.view.JstlView;
     15 
     16 import java.util.List;
     17 
     18 /**
     19  * Spring MVC配置
     20  */
     21 @Configuration
     22 @EnableWebMvc//开启一些默认配置,如一些ViewResolver(视图解析器)或者MessageConverter(消息转换器)等。
     23 @EnableScheduling
     24 @ComponentScan("com.wisely.highlight_springmvc4")
     25 public class MyMvcConfig extends WebMvcConfigurerAdapter {// 2
     26 
     27     /**
     28      * 映射路径和实际页面的位置
     29      *
     30      * @return
     31      */
     32     @Bean
     33     public InternalResourceViewResolver viewResolver() {
     34         InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
     35         viewResolver.setPrefix("/WEB-INF/classes/views/");
     36         viewResolver.setSuffix(".jsp");
     37         viewResolver.setViewClass(JstlView.class);
     38         return viewResolver;
     39     }
     40 
     41     /**
     42      * 静态资源映射
     43      * @param registry
     44      */
     45     @Override
     46     public void addResourceHandlers(ResourceHandlerRegistry registry) {
     47         //addResourceHandler是对外暴露的访问路径,addResourceLocations是文件放置的目录。
     48         registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");
     49     }
     50 
     51     /**
     52      * 配置拦截器的Bean。
     53      * @return
     54      */
     55     @Bean
     56     public DemoInterceptor demoInterceptor() {
     57         return new DemoInterceptor();
     58     }
     59 
     60     /**
     61      * 重写addInterceptors方法,注册拦截器。
     62      * @param registry
     63      */
     64     @Override
     65     public void addInterceptors(InterceptorRegistry registry) {// 2
     66         registry.addInterceptor(demoInterceptor());
     67     }
     68 
     69     /**
     70      * 集中设置页面转向
     71      * 等同下列代码:
     72      *      @RequestMapping("/index")
     73      *      public String hello() {
     74      *          return "index";
     75      *      }
     76      * @param registry
     77      */
     78     @Override
     79     public void addViewControllers(ViewControllerRegistry registry) {
     80         registry.addViewController("/index").setViewName("/index");
     81         registry.addViewController("/toUpload").setViewName("/upload");
     82         registry.addViewController("/converter").setViewName("/converter");
     83         registry.addViewController("/sse").setViewName("/sse");
     84         registry.addViewController("/async").setViewName("/async");
     85     }
     86 
     87     /**
     88      * 不忽略路径参数中"."后面的值
     89      * @param configurer
     90      */
     91     @Override
     92     public void configurePathMatch(PathMatchConfigurer configurer) {
     93         configurer.setUseSuffixPatternMatch(false);
     94     }
     95 
     96     /**
     97      * 配置文件上传
     98      * @return
     99      */
    100     @Bean
    101     public MultipartResolver multipartResolver() {
    102         CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    103         multipartResolver.setMaxUploadSize(1000000);
    104         return multipartResolver;
    105     }
    106 
    107     @Override
    108     public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    109         converters.add(converter());
    110     }
    111 
    112     @Bean
    113     public MyMessageConverter converter() {
    114         return new MyMessageConverter();
    115     }
    116 }
    MyMvcConfig.java(Spring MVC配置)
     1 package com.wisely.highlight_springmvc4;
     2 
     3 import org.springframework.web.WebApplicationInitializer;
     4 import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
     5 import org.springframework.web.servlet.DispatcherServlet;
     6 
     7 import javax.servlet.ServletContext;
     8 import javax.servlet.ServletException;
     9 import javax.servlet.ServletRegistration.Dynamic;
    10 
    11 /**
    12  * Web配置
    13  * <p>
    14  * WebApplicationInitializer是Spring提供用来配置Servlet 3.0+配置的接口,从而实现了替代web.xml的位置。
    15  * 实现此接口将会自动被SpringServletContainerInitializer(用来启动Servlet 3.0容器)获取到。
    16  */
    17 public class WebInitializer implements WebApplicationInitializer {
    18 
    19     @Override
    20     public void onStartup(ServletContext servletContext)
    21             throws ServletException {
    22         //新建WebApplicationContext
    23         AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    24         //注册配置类
    25         ctx.register(MyMvcConfig.class);
    26         //将其和当前servletContext关联。
    27         ctx.setServletContext(servletContext);
    28 
    29         //注册Spring MVC的DispatcherServlet
    30         Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
    31         servlet.addMapping("/");
    32         servlet.setLoadOnStartup(1);
    33         servlet.setAsyncSupported(true);//开启异步方法支持
    34     }
    35 }
    WebInitializer.java(Web配置)

     Spring MVC的常用注解

      @Controller:

          @Controller注解在类上,表明这个类是Spring MVC里的Controller,将其声明为Spring的一个Bean,Dispatcher Servlet会自动扫描注解了此注解的类,并将Web请求映射到注解了@RequestMapping的方法上。

      @RequestMapping:

          @RequestMapping注解是用来映射Web请求(访问路径和参数)、处理类和方法的。@RequestMapping可注解在类或方法上。注解在方法上的@RequestMapping路径会继承注解在类上的路径,@RequestMapping支持Servlet的request和response作为参数,也支持对request和response的媒体类型进行配置。

      @ResponseBody:

          @ResponseBody支持将返回值放在response体内,而不是返回一个页面。我们在很多编写基于Ajax的程序的时候,可以以此注解返回数据而不是页面;此注解可放置在返回值前或方法上。

      @RequestBody:

          @RequestBody允许request的参数在request体中,而不是直接链接在地址后面。此注解放置在参数前。

      @PathVariable:

          @PathVariable用来接收路径参数,如/news/001,可接收001作为参数,此注解放置在参数前。

      @RestController:

          @RestController是一个组合注解,组合了@Controller和@@ResponseBody,这就意味着当你只开发一个和页面交互数据的控制器的适口,需要使用此注解。如果不用此注解的话,则需要使用@Controller和@ResponseBody两个注解。

      下面是一些例子。

     1 package com.wisely.highlight_springmvc4.domain;
     2 
     3 /**
     4  * 此类用来获取request对象参数和返回此对象到response。
     5  */
     6 public class DemoObj {
     7     private Long id;
     8     private String name;
     9 
    10     /**
    11      * jackson对对象和json做转换时一定需要此空构造。
    12      */
    13     public DemoObj() {
    14         super();
    15     }
    16 
    17     public DemoObj(Long id, String name) {
    18         super();
    19         this.id = id;
    20         this.name = name;
    21     }
    22 
    23     public Long getId() {
    24         return id;
    25     }
    26 
    27     public void setId(Long id) {
    28         this.id = id;
    29     }
    30 
    31     public String getName() {
    32         return name;
    33     }
    34 
    35     public void setName(String name) {
    36         this.name = name;
    37     }
    38 }
    DemoObj.java
     1 package com.wisely.highlight_springmvc4.web.ch4_3;
     2 
     3 import com.wisely.highlight_springmvc4.domain.DemoObj;
     4 import org.springframework.stereotype.Controller;
     5 import org.springframework.web.bind.annotation.PathVariable;
     6 import org.springframework.web.bind.annotation.RequestMapping;
     7 import org.springframework.web.bind.annotation.ResponseBody;
     8 
     9 import javax.servlet.http.HttpServletRequest;
    10 
    11 /**
    12  * 注解演示控制器
    13  */
    14 @Controller //此注解声明此类是一个控制器。
    15 @RequestMapping("/anno") //此注解映射此类的访问路径时/anno
    16 public class DemoAnnoController {
    17     /**
    18      * 此方法为标注路径,因此使用类级别的路径/anno。
    19      * produces可定制返回的response的媒体类型和字符集,若返回值是json对象,则设置produces = "application/json;charset=UTF-8"。
    20      *
    21      * @param request
    22      * @return
    23      */
    24     @RequestMapping(produces = "text/plain;charset=UTF-8")
    25     //此处的@ResponseBody用在方法返回值前面
    26     public @ResponseBody
    27     String index(HttpServletRequest request) { //可以直接使用HttpServletRequest作为参数,也可以直接使用HttpServletResponse作为参数。
    28         return "url:" + request.getRequestURL() + " can access";
    29     }
    30 
    31     @RequestMapping(value = "/pathvar/{str}", produces = "text/plain;charset=UTF-8")//设置路径中的参数
    32     public @ResponseBody
    33     String demoPathVar(@PathVariable String str, //结合@PathVariable注解,接收路径中的参数,访问路径为/anno/pathvar/xx
    34                        HttpServletRequest request) {
    35         return "url:" + request.getRequestURL() + " can access,str: " + str;
    36     }
    37 
    38     @RequestMapping(value = "/requestParam", produces = "text/plain;charset=UTF-8") //常规的request获取参数,访问路径为/anno/requestParam?id=1
    39     public @ResponseBody
    40     String passRequestParam(Long id, HttpServletRequest request) {
    41         return "url:" + request.getRequestURL() + " can access,id: " + id;
    42     }
    43 
    44     @RequestMapping(value = "/obj", produces = "application/json;charset=UTF-8")//映射参数到对象,访问路径为/anno/obj?id=1&name=xx
    45     @ResponseBody //@ResponseBody也可以用在方法上面
    46     public String passObj(DemoObj obj, HttpServletRequest request) {
    47         return "url:" + request.getRequestURL() + " can access, obj id: " + obj.getId() + " obj name:" + obj.getName();
    48     }
    49 
    50     @RequestMapping(value = {"/name1", "/name2"}, produces = "text/plain;charset=UTF-8")//将不同的路径映射到相同的方法上,访问路径为/anno/name1或者/anno/name2
    51     public @ResponseBody
    52     String remove(HttpServletRequest request) {
    53         return "url:" + request.getRequestURL() + " can access";
    54     }
    55 }
    DemoAnnoController.java
     1 package com.wisely.highlight_springmvc4.web.ch4_3;
     2 
     3 import com.wisely.highlight_springmvc4.domain.DemoObj;
     4 import org.springframework.web.bind.annotation.RequestMapping;
     5 import org.springframework.web.bind.annotation.RestController;
     6 
     7 /**
     8  * '@RestController'注解演示
     9  */
    10 @RestController //使用@RestController注解声明此类是控制器,并且返回数据时不需要@ResponseBody。
    11 @RequestMapping("/rest")
    12 public class DemoRestController {
    13 
    14     @RequestMapping(value = "/getjson",
    15             produces = {"application/json;charset=UTF-8"}) //设置返回数据的媒体类型为json。
    16     public DemoObj getjson(DemoObj obj) {
    17         return new DemoObj(obj.getId() + 1, obj.getName() + "yy");//直接返回对象,对象会自动转换成json。
    18     }
    19 
    20     @RequestMapping(value = "/getxml",
    21             produces = {"application/xml;charset=UTF-8"})//设置返回数据的媒体类型为xml
    22     public DemoObj getxml(DemoObj obj) {
    23         return new DemoObj(obj.getId() + 1, obj.getName() + "yy");//直接返回对象,对象会自动转换为xml。
    24     }
    25 }
    DemoRestController.java

    Spring MVC基本配置

      Spring MVC的定制配置需要无门的配置类继承一个WebMvcConfigurerAdapter类,并在此类使用@EnableWebMvc注解,来开启对Spring MVC的配置支持,这样我们就可以重写这个类的方法,完成我们的常用配置。

      静态资源映射:

     1 /**
     2      * 映射路径和实际页面的位置
     3      *
     4      * @return
     5      */
     6     @Bean
     7     public InternalResourceViewResolver viewResolver() {
     8         InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
     9         viewResolver.setPrefix("/WEB-INF/classes/views/");
    10         viewResolver.setSuffix(".jsp");
    11         viewResolver.setViewClass(JstlView.class);
    12         return viewResolver;
    13     }
    14 
    15     /**
    16      * 静态资源映射
    17      * @param registry
    18      */
    19     @Override
    20     public void addResourceHandlers(ResourceHandlerRegistry registry) {
    21         //addResourceHandler是对外暴露的访问路径,addResourceLocations是文件放置的目录。
    22         registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/assets/");
    23     }
    静态资源映射

      拦截器配置:

          拦截器实现对每一个请求处理前后进行相关的业务处理,类似于Servlet的Filter。

          可以让普通的Bean实现HanlderInterceptor接口或者继承HandlerInterceptorAdapter类来实现自定义拦截器。

          通过重写WebMvcConfigurerAdapter的addInterceptors方法来注册自定义的拦截器。

     1 package com.wisely.highlight_springmvc4.interceptor;
     2 
     3 import org.springframework.web.servlet.ModelAndView;
     4 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
     5 
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 /**
    10  * 拦截器
    11  */
    12 public class DemoInterceptor extends HandlerInterceptorAdapter {//集成HandlerInterceptorAdapter类来实现自定义拦截器
    13 
    14     @Override
    15     public boolean preHandle(HttpServletRequest request, //重写preHandle方法,在请求发生前执行
    16             HttpServletResponse response, Object handler) throws Exception {
    17         long startTime = System.currentTimeMillis();
    18         request.setAttribute("startTime", startTime);
    19         return true;
    20     }
    21 
    22     @Override
    23     public void postHandle(HttpServletRequest request, //重写postHandle方法,在请求完成后执行
    24             HttpServletResponse response, Object handler,
    25             ModelAndView modelAndView) throws Exception {
    26         long startTime = (Long) request.getAttribute("startTime");
    27         request.removeAttribute("startTime");
    28         long endTime = System.currentTimeMillis();
    29         System.out.println("本次请求处理时间为:" + new Long(endTime - startTime)+"ms");
    30         request.setAttribute("handlingTime", endTime - startTime);
    31     }
    32 
    33 }
    DemoInterceptor.java(拦截器)
     1     /**
     2      * 配置拦截器的Bean。
     3      * @return
     4      */
     5     @Bean
     6     public DemoInterceptor demoInterceptor() {
     7         return new DemoInterceptor();
     8     }
     9 
    10     /**
    11      * 重写addInterceptors方法,注册拦截器。
    12      * @param registry
    13      */
    14     @Override
    15     public void addInterceptors(InterceptorRegistry registry) {// 2
    16         registry.addInterceptor(demoInterceptor());
    17     }
    配置拦截器

      @ControllerAdvice:

          通过@ControllerAdvice,我们可以将对于控制器的全局配置放在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上,这对所有注解了@RequestMapping的控制器内的方法都有效。

          @ExceptionHandler:用于全局处理控制器里的异常。

          @InitBinder:用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到Model中。

          @ModelAttribute:这个注解本来的作用是绑定键值对到Model里,此处是让全局的@RequestMapping都能获得在此处设置的键值对。

     1 package com.wisely.highlight_springmvc4.advice;
     2 
     3 import org.springframework.ui.Model;
     4 import org.springframework.web.bind.WebDataBinder;
     5 import org.springframework.web.bind.annotation.ControllerAdvice;
     6 import org.springframework.web.bind.annotation.ExceptionHandler;
     7 import org.springframework.web.bind.annotation.InitBinder;
     8 import org.springframework.web.bind.annotation.ModelAttribute;
     9 import org.springframework.web.context.request.WebRequest;
    10 import org.springframework.web.servlet.ModelAndView;
    11 
    12 /**
    13  * 定制ControllerAdvice,处理全局异常
    14  */
    15 @ControllerAdvice //@ControllerAdvice声明一个控制器建言,@ControllerAdvice组合了@Component注解,所以自动注册为Spring的Bean。
    16 public class ExceptionHandlerAdvice { 
    17 
    18     @ExceptionHandler(value = Exception.class)//@ExceptionHandler在此处定义全局处理,通过@ExceptionHandler的value属性可过滤拦截的条件,此处拦截所有的Exception。
    19     public ModelAndView exception(Exception exception, WebRequest request) {
    20         ModelAndView modelAndView = new ModelAndView("error");// error页面
    21         modelAndView.addObject("errorMessage", exception.getMessage());
    22         return modelAndView;
    23     }
    24 
    25     @ModelAttribute //使用@ModelAttribute注解将键值对添加到全局,所有注解的@RequestMapping的方法可获得此键值对。
    26     public void addAttributes(Model model) {
    27         model.addAttribute("msg", "额外信息"); //3
    28     }
    29 
    30     @InitBinder //通过@InitBinder注解定制WebDataBinder
    31     public void initBinder(WebDataBinder webDataBinder) {
    32         webDataBinder.setDisallowedFields("id");//忽略掉request参数中的id参数
    33     }
    34 }
    ExceptionHandlerAdvice.java
     1 package com.wisely.highlight_springmvc4.web.ch4_4;
     2 
     3 import org.springframework.stereotype.Controller;
     4 import org.springframework.web.bind.annotation.ModelAttribute;
     5 import org.springframework.web.bind.annotation.RequestMapping;
     6 
     7 import com.wisely.highlight_springmvc4.domain.DemoObj;
     8 
     9 /**
    10  * 异常控制器
    11  */
    12 @Controller
    13 public class AdviceController {
    14     @RequestMapping("/advice")
    15     public String getSomething(@ModelAttribute("msg") String msg,DemoObj obj){//1
    16         
    17         throw new IllegalArgumentException("非常抱歉,参数有误/"+"来自@ModelAttribute:"+ msg);
    18     }
    19 
    20 }
    AdviceController.java
     1 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
     2 <%@ page language="java" contentType="text/html; charset=UTF-8"
     3     pageEncoding="UTF-8"%>
     4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     5 <html>
     6 <head>
     7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     8 <title>@ControllerAdvice Demo</title>
     9 </head>
    10 <body>
    11     ${errorMessage}
    12 </body>
    13 </html>
    error.jsp

    Spring MVC其他配置

      ViewController:

          快捷的页面转向,方便统一管理。

     1 /**
     2      * 集中设置页面转向
     3      * 等同下列代码:
     4      *      @RequestMapping("/index")
     5      *      public String hello() {
     6      *          return "index";
     7      *      }
     8      * @param registry
     9      */
    10     @Override
    11     public void addViewControllers(ViewControllerRegistry registry) {
    12         registry.addViewController("/index").setViewName("/index");
    13         registry.addViewController("/toUpload").setViewName("/upload");
    14         registry.addViewController("/converter").setViewName("/converter");
    15         registry.addViewController("/sse").setViewName("/sse");
    16         registry.addViewController("/async").setViewName("/async");
    17     }
    ViewController

      路径参数配置:

          在Spring MVC中,路径参数如果带“.”的话,“.”后面的值将被忽略,通过重写configurePathMatch方法可不忽略后面的值。

    1 /**
    2      * 不忽略路径参数中"."后面的值
    3      * @param configurer
    4      */
    5     @Override
    6     public void configurePathMatch(PathMatchConfigurer configurer) {
    7         configurer.setUseSuffixPatternMatch(false);
    8     }
    configurePathMatch

     Spring MVC高级配置

      文件上传配置:

     1 <%@ page language="java" contentType="text/html; charset=UTF-8"
     2     pageEncoding="UTF-8"%>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     4 <html>
     5 <head>
     6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     7 <title>upload page</title>
     8 
     9 </head>
    10 <body>
    11 
    12 
    13 <div class="upload">
    14     <form action="upload" enctype="multipart/form-data" method="post">
    15         <input type="file" name="file"/><br/>
    16         <input type="submit" value="上传">
    17     </form>
    18 </div>
    19 
    20 
    21 </body>
    22 </html>
    upload.jsp
     1     /**
     2      * 配置文件上传
     3      * @return
     4      */
     5     @Bean
     6     public MultipartResolver multipartResolver() {
     7         CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
     8         multipartResolver.setMaxUploadSize(1000000);
     9         return multipartResolver;
    10     }
    配置
     1 package com.wisely.highlight_springmvc4.web.ch4_5;
     2 
     3 import org.apache.commons.io.FileUtils;
     4 import org.springframework.stereotype.Controller;
     5 import org.springframework.web.bind.annotation.RequestMapping;
     6 import org.springframework.web.bind.annotation.RequestMethod;
     7 import org.springframework.web.bind.annotation.ResponseBody;
     8 import org.springframework.web.multipart.MultipartFile;
     9 
    10 import java.io.File;
    11 import java.io.IOException;
    12 
    13 @Controller
    14 public class UploadController {
    15     
    16     @RequestMapping(value = "/upload",method = RequestMethod.POST)
    17     public @ResponseBody String upload(MultipartFile file) {//使用MultipartFile file接收上传的文件
    18         
    19             try {
    20                 //使用FileUtils.writeByteArrayToFile快速写文件到磁盘
    21                 FileUtils.writeByteArrayToFile(new File("e:/upload/"+file.getOriginalFilename()), file.getBytes());
    22                 return "ok";
    23             } catch (IOException e) {
    24                 e.printStackTrace();
    25                 return "wrong";
    26             }
    27             
    28         
    29     }
    30 
    31 }
    UploadController

      自定义HttpMessageConverter:

           HttpMessageConverter是用来处理request和response里的数据的。Spring为我们内置了大量的HttpMessageConverter,例如MappingJackson2HttpMessageConverter、StringHttpMessageConverter等。除此之外,我们也可以自己定义。

     1 package com.wisely.highlight_springmvc4.messageconverter;
     2 
     3 import com.wisely.highlight_springmvc4.domain.DemoObj;
     4 import org.springframework.http.HttpInputMessage;
     5 import org.springframework.http.HttpOutputMessage;
     6 import org.springframework.http.MediaType;
     7 import org.springframework.http.converter.AbstractHttpMessageConverter;
     8 import org.springframework.http.converter.HttpMessageNotReadableException;
     9 import org.springframework.http.converter.HttpMessageNotWritableException;
    10 import org.springframework.util.StreamUtils;
    11 
    12 import java.io.IOException;
    13 import java.nio.charset.Charset;
    14 
    15 public class MyMessageConverter extends AbstractHttpMessageConverter<DemoObj> {//继承AbstractHttpMessageConverter接口来实现自定义的HttpMessageConverter
    16 
    17     public MyMessageConverter() {
    18         super(new MediaType("application", "x-wisely",Charset.forName("UTF-8")));//新建一个自定义的媒体类型application/x-wisely
    19     }
    20     
    21     /**
    22      * 重写readInternal方法,处理请求的数据。
    23      * 代码表明我们处理由“-”隔开的数据,并转成DemoObj的对象。
    24      */
    25     @Override
    26     protected DemoObj readInternal(Class<? extends DemoObj> clazz,
    27             HttpInputMessage inputMessage) throws IOException,
    28             HttpMessageNotReadableException {
    29         String temp = StreamUtils.copyToString(inputMessage.getBody(),
    30 
    31         Charset.forName("UTF-8"));
    32         String[] tempArr = temp.split("-");
    33         return new DemoObj(new Long(tempArr[0]), tempArr[1]);
    34     }
    35     
    36     /**
    37      * 表明本HttpMessageConverter只处理DemoObj这个类。
    38      */
    39     @Override
    40     protected boolean supports(Class<?> clazz) {
    41         return DemoObj.class.isAssignableFrom(clazz);
    42     }
    43     
    44     /**
    45      * 重写writeInternal,处理如何输出数据到response。
    46      * 此例中,我们在原样输出前面加上“hello:”。
    47      */
    48     @Override
    49     protected void writeInternal(DemoObj obj, HttpOutputMessage outputMessage)
    50             throws IOException, HttpMessageNotWritableException {
    51         String out = "hello:" + obj.getId() + "-"
    52                 + obj.getName();
    53         outputMessage.getBody().write(out.getBytes());
    54     }
    55 
    56 }
    MyMessageConverter.java
     1 /**
     2      * 在Spring MVC里注册HttpMessageConverter有两种方法:
     3      *      1:configureMessageConverters:重载会覆盖掉Spring MVC默认注册的多个HttpMessageConverter。
     4      *      2:extendMessageConverters:仅添加一个自定义的HttpMessageConverter,不覆盖默认注册的HttpMessageConverter。
     5      * @param converters
     6      */
     7     @Override
     8     public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
     9         converters.add(converter());
    10     }
    11 
    12     @Bean
    13     public MyMessageConverter converter() {
    14         return new MyMessageConverter();
    15     }
    配置
     1 package com.wisely.highlight_springmvc4.web.ch4_5;
     2 
     3 import org.springframework.stereotype.Controller;
     4 import org.springframework.web.bind.annotation.RequestBody;
     5 import org.springframework.web.bind.annotation.RequestMapping;
     6 import org.springframework.web.bind.annotation.ResponseBody;
     7 
     8 import com.wisely.highlight_springmvc4.domain.DemoObj;
     9 
    10 @Controller
    11 public class ConverterController {
    12     
    13     @RequestMapping(value = "/convert", produces = { "application/x-wisely" }) //指定返回的媒体类型为我们自定义的媒体类型application/x-wisely。
    14     public @ResponseBody DemoObj convert(@RequestBody DemoObj demoObj) {
    15         return demoObj;
    16     }
    17 }
    ConverterController.java
     1 <%@ page language="java" contentType="text/html; charset=UTF-8"
     2     pageEncoding="UTF-8"%>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     4 <html>
     5 <head>
     6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     7 <title>HttpMessageConverter Demo</title>
     8 </head>
     9 <body>
    10     <div id="resp"></div><input type="button" onclick="req();" value="请求"/>
    11 <script src="assets/js/jquery.js" type="text/javascript"></script>
    12 <script>
    13     function req(){
    14         $.ajax({
    15             url: "convert",
    16             data: "1-gaofei", //注意数据格式,使用“-”隔开
    17             type:"POST",
    18             contentType:"application/x-wisely", //contentType设置的媒体类型是我们自定义的application/x-wisely。
    19             success: function(data){
    20                 $("#resp").html(data);
    21             }
    22         });
    23     }
    24 
    25 </script>
    26 </body>
    27 </html>
    converter.jsp

     服务器端推送

      SSE(需新式浏览器支持):

     1 package com.wisely.highlight_springmvc4.web.ch4_5;
     2 
     3 import org.springframework.stereotype.Controller;
     4 import org.springframework.web.bind.annotation.RequestMapping;
     5 import org.springframework.web.bind.annotation.ResponseBody;
     6 
     7 import java.util.Random;
     8 
     9 @Controller
    10 public class SseController {
    11     /**
    12      * 这里使用输出的媒体类型为text/event-stream,这是服务器端SSE的支持,本例演示每5秒钟像浏览器推送随机消息。
    13      *
    14      * @return
    15      */
    16     @RequestMapping(value = "/push", produces = "text/event-stream")
    17     public @ResponseBody
    18     String push() {
    19         Random r = new Random();
    20         try {
    21             Thread.sleep(5000);
    22         } catch (InterruptedException e) {
    23             e.printStackTrace();
    24         }
    25         return "data:Testing 1,2,3" + r.nextInt() + "
    
    ";
    26     }
    27 
    28 }
    SseController.java
     1 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
     2 <%@ page language="java" contentType="text/html; charset=UTF-8"
     3     pageEncoding="UTF-8"%>
     4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     5 <html>
     6 <head>
     7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     8 <title>SSE Demo</title>
     9 
    10 </head>
    11 <body>
    12 
    13 
    14 <div id="msgFrompPush"></div>
    15 <script type="text/javascript" src="<c:url value="assets/js/jquery.js" />"></script>
    16 <script type="text/javascript">
    17 
    18 
    19  if (!!window.EventSource) { //EventSource对象只有新式的浏览器才有(Chrome、Firefox等),EventSource是SSE的客户端。
    20        var source = new EventSource('push'); 
    21        s='';
    22        source.addEventListener('message', function(e) {//添加SSE客户端监听,在此获得服务器端推送的消息
    23            s+=e.data+"<br/>";
    24            $("#msgFrompPush").html(s);
    25          
    26        });
    27 
    28        source.addEventListener('open', function(e) {
    29             console.log("连接打开.");
    30        }, false);
    31 
    32        source.addEventListener('error', function(e) {
    33             if (e.readyState == EventSource.CLOSED) {
    34                console.log("连接关闭");
    35             } else {
    36                 console.log(e.readyState);    
    37             }
    38        }, false);
    39     } else {
    40             console.log("你的浏览器不支持SSE");
    41     } 
    42 </script>
    43 </body>
    44 </html>
    sse.jsp

      Servlet3.0+的异步方法(跨浏览器):

    1 //注册Spring MVC的DispatcherServlet
    2         Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
    3         servlet.addMapping("/");
    4         servlet.setLoadOnStartup(1);
    5         servlet.setAsyncSupported(true);//开启异步方法支持
    配置
     1 package com.wisely.highlight_springmvc4.web.ch4_5;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.stereotype.Controller;
     5 import org.springframework.web.bind.annotation.RequestMapping;
     6 import org.springframework.web.bind.annotation.ResponseBody;
     7 import org.springframework.web.context.request.async.DeferredResult;
     8 
     9 import com.wisely.highlight_springmvc4.service.PushService;
    10 
    11 @Controller
    12 public class AysncController {
    13     @Autowired
    14     PushService pushService; //定时任务,定时更新DeferredResult
    15 
    16     /**
    17      * 返回给客户端DeferredResult
    18      * @return
    19      */
    20     @RequestMapping("/defer")
    21     @ResponseBody
    22     public DeferredResult<String> deferredCall() { //2
    23         return pushService.getAsyncUpdate();
    24     }
    25 
    26 }
    AysncController.java
     1 package com.wisely.highlight_springmvc4.service;
     2 
     3 import org.springframework.scheduling.annotation.Scheduled;
     4 import org.springframework.stereotype.Service;
     5 import org.springframework.web.context.request.async.DeferredResult;
     6 
     7 @Service
     8 public class PushService {
     9     private DeferredResult<String> deferredResult; //在PushService里产生DeferredResult给控制器使用,通过@Scheduled注解的方式定时更新DeferredResult。
    10 
    11     public DeferredResult<String> getAsyncUpdate() {
    12         deferredResult = new DeferredResult<String>();
    13         return deferredResult;
    14     }
    15 
    16     @Scheduled(fixedDelay = 5000)
    17     public void refresh() {
    18         if (deferredResult != null) {
    19             deferredResult.setResult(new Long(System.currentTimeMillis())
    20                     .toString());
    21         }
    22     }
    23 }
    PushService.java
     1 <%@ page language="java" contentType="text/html; charset=UTF-8"
     2     pageEncoding="UTF-8"%>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     4 <html>
     5 <head>
     6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     7 <title>servlet async support</title>
     8 
     9 </head>
    10 <body>
    11 
    12 
    13 
    14 <script type="text/javascript" src="assets/js/jquery.js"></script>
    15 <script type="text/javascript">
    16 
    17     deferred();//页面打开就向后台发送请求。
    18     
    19     function deferred(){
    20         $.get('defer',function(data){
    21             console.log(data); //在控制台输出服务端推送的数据。
    22             deferred(); //一次请求完成后再向后台发送请求。
    23         });
    24     }
    25 
    26 
    27 </script>
    28 </body>
    29 </html>
    async.jsp

     Spring MVC的测试

     1 package com.wisely.highlight_springmvc4.service;
     2 
     3 import org.springframework.stereotype.Service;
     4 
     5 @Service
     6 public class DemoService {
     7     
     8     public String saySomething(){
     9         return "hello";
    10     }
    11 
    12 }
    DemoService.java
     1 package com.wisely.highlight_springmvc4.web.ch4_6;
     2 
     3 
     4 import com.wisely.highlight_springmvc4.MyMvcConfig;
     5 import com.wisely.highlight_springmvc4.service.DemoService;
     6 import org.junit.Before;
     7 import org.junit.Test;
     8 import org.junit.runner.RunWith;
     9 import org.springframework.beans.factory.annotation.Autowired;
    10 import org.springframework.mock.web.MockHttpServletRequest;
    11 import org.springframework.mock.web.MockHttpSession;
    12 import org.springframework.test.context.ContextConfiguration;
    13 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    14 import org.springframework.test.context.web.WebAppConfiguration;
    15 import org.springframework.test.web.servlet.MockMvc;
    16 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
    17 import org.springframework.web.context.WebApplicationContext;
    18 
    19 import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    20 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    21 
    22 @RunWith(SpringJUnit4ClassRunner.class)
    23 @ContextConfiguration(classes = {MyMvcConfig.class})
    24 //@WebAppConfiguration注解在类上,用来声明加载的ApplicationContext是一个WebApplicationContext。
    25 //它的属性指定的是Web资源的位置,默认为src/main/webapp,本例修改为src/main/resource。
    26 @WebAppConfiguration("src/main/resources")
    27 public class TestControllerIntegrationTests {
    28     private MockMvc mockMvc; //MockMvc模拟MVC对象。
    29     
    30     @Autowired
    31     private DemoService demoService;//在测试用例中注入Spring的Bean。
    32     
    33     @Autowired 
    34     WebApplicationContext wac; //注入WebApplicationContext。
    35     
    36     @Autowired 
    37     MockHttpSession session; //注入模拟的Http Session。
    38     
    39     @Autowired 
    40     MockHttpServletRequest request; //注入模拟的Http Request。
    41     
    42     @Before //@Before注解表示在测试开始前进行的初始化工作。
    43     public void setup() {
    44         mockMvc =
    45                 MockMvcBuilders.webAppContextSetup(this.wac).build(); //通过MockMvcBuilders.webAppContextSetup(this.wac).build()初始化MockMvc。
    46         }
    47     
    48     @Test
    49     public void testNormalController() throws Exception{
    50         mockMvc.perform(get("/normal")) //模拟向/normal进行get请求。
    51                 .andExpect(status().isOk())//预期控制返回状态为200。
    52                 .andExpect(view().name("page"))//预期view的名称为page。
    53                 .andExpect(forwardedUrl("/WEB-INF/classes/views/page.jsp"))//预期页面转向的真正路径为/WEB-INF/classes/views/page.jsp。
    54                 .andExpect(model().attribute("msg", demoService.saySomething()));//预期model里的值是demoService.saySomething()的返回值hello。
    55                 
    56     }
    57     
    58     @Test
    59     public void testRestController() throws Exception{
    60         mockMvc.perform(get("/testRest")) //模拟向/testRest进行get请求。
    61         .andExpect(status().isOk())
    62          .andExpect(content().contentType("text/plain;charset=UTF-8"))//预期返回值的媒体类型为text/plain;charset=UTF-8。
    63         .andExpect(content().string(demoService.saySomething()));//预期返回值的内容是demoService.saySomething()的返回值hello。
    64     }
    65 
    66 }
    TestControllerIntegrationTests.java
     1 package com.wisely.highlight_springmvc4.web.ch4_6;
     2 
     3 import org.springframework.beans.factory.annotation.Autowired;
     4 import org.springframework.stereotype.Controller;
     5 import org.springframework.ui.Model;
     6 import org.springframework.web.bind.annotation.RequestMapping;
     7 
     8 import com.wisely.highlight_springmvc4.service.DemoService;
     9 
    10 //@Controller
    11 public class NormalController {
    12     @Autowired
    13     DemoService demoService;
    14     
    15 
    16     
    17     @RequestMapping("/normal")
    18     public  String testPage(Model model){
    19         model.addAttribute("msg", demoService.saySomething());
    20         return "page";
    21     }
    22 
    23 }
    NormalController.java
     1 <%@ page language="java" contentType="text/html; charset=UTF-8"
     2     pageEncoding="UTF-8"%>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
     4 <html>
     5 <head>
     6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
     7 <title>Test page</title>
     8 </head>
     9 <body>
    10     <pre>
    11         Welcome to Spring MVC world
    12     </pre>
    13 </body>
    14 </html>
    page.jsp
  • 相关阅读:
    haproxy教程
    haproxy和keepalived的理解(转载)
    redis集群搭建_超详细
    磁盘IO过高时的参考
    tomcat优化
    MYSQL数据库的主从复制
    k8s学习笔记-etcd介绍和集群搭建
    python排序算法二---冒泡排序
    Python排序算法一—快速排序
    python:如何判断字典a在字典b
  • 原文地址:https://www.cnblogs.com/gaofei-1/p/8971749.html
Copyright © 2011-2022 走看看