Java方式配置Spring MVC

概述

  使用Java方式配置Spring MVC,以及回顧一下Spring MVC的各類用法。javascript


 

Spring MVC簡述

  關於Spring MVC的介紹網上有不少,這裏就再也不贅述了,只是要說一下,Spring MVC中的「MVC」是什麼意思,它和三層架構是什麼關係。html

  可能有不少人說,在三層架構中,M就是數據訪問層,V就是展示層,C就是應用層。java

  聽上去頗有道理,但其實MVC就是數據模型(Model)+視圖(View)+控制器(Controller),在Spring MVC中,有一個專門的類叫Model,用來和V之間的數據交互、傳值;V指的是視圖頁面,包含JSP、Thymeleaf等;C就是控制器。MVC只存在於三層架構中的展示層。jquery

搭建一個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:web

      @Controller註解在類上,代表這個類是Spring MVC裏的Controller,將其聲明爲Spring的一個Bean,Dispatcher Servlet會自動掃描註解了此註解的類,並將Web請求映射到註解了@RequestMapping的方法上。ajax

  @RequestMapping:spring

      @RequestMapping註解是用來映射Web請求(訪問路徑和參數)、處理類和方法的。@RequestMapping可註解在類或方法上。註解在方法上的@RequestMapping路徑會繼承註解在類上的路徑,@RequestMapping支持Servlet的request和response做爲參數,也支持對request和response的媒體類型進行配置。apache

  @ResponseBody:json

      @ResponseBody支持將返回值放在response體內,而不是返回一個頁面。咱們在不少編寫基於Ajax的程序的時候,能夠以此註解返回數據而不是頁面;此註解可放置在返回值前或方法上。api

  @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() + "\n\n";
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
相關文章
相關標籤/搜索