Spring MVC中每個控制器中可以定義多個請求處理方法,我們把這種請求處理方法簡稱為Action,每個請求處理方法可以有多個不同的參數,以及一個多種類型的返回結果。
一、Action參數類型
如果在請求處理方法中需要訪問HttpSession對象,則可以添加HttpSession作為參數,Spring會將對象正確的傳遞給方法,如:public String action(HttpSession session);若需要訪問客戶端語言環境和HttpServletRequest對象,則可以在方法簽名上包含這樣的參數,如:public String action(HttpServletRequest request,Locale locale)。可以在請求中出現的參數類型有:
org.springframework.web.context.request.WebRequest
org.springframework.web.context.request.NativeWebRequest
java.util.Locale 當前請求的語言環境
java.util.TimeZone 時區
java.io.InputStream或java.io.Reader
java.io.OutputStream或java.io.Writer
org.springframework.http.HttpMethod
java.security.Principal
HttpEntity <?>參數用於訪問Servlet的HTTP請求的標題和內容
java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap 視圖隱含模型
org.springframework.web.servlet.mvc.support.RedirectAttributes 重定向
命令或表單對象
基本數據類型,如int,String,double...
復雜數據類型,如自定義的POJO對象
HandlerAdapter
org.springframework.validation.Errors / org.springframework.validation.BindingResult 驗證結果
org.springframework.web.bind.support.SessionStatus 會話狀態
org.springframework.web.util.UriComponentsBuilder
@PathVariable 注解參數訪問URI模板變量。
@MatrixVariable 注釋參數用於訪問位於URI路徑段鍵值對對,矩陣變量。
@RequestParam 注解參數訪問特定的Servlet請求參數,請求參數綁定。
@RequestHeader 注解參數訪問特定的servlet請求HTTP標頭,映射請求頭。
@RequestBody 注解參數訪問HTTP請求主體,注解映射請求體
@RequestPart 注解參數訪問“的multipart / form-data的”請求部分的內容。處理客戶端上傳文件,多部分文件上傳的支持
@SessionAttribute 注解參數會話屬性
@RequestAttribute 注解參數訪問請求屬性
1.1、自動參數映射
1.1.1、基本數據類型
方法的參數可以是任意基本數據類型,如果方法參數名與http中請求的參數名稱相同時會進行自動映射,視圖foo目錄下的index.jsp與示例代碼如下:
// 自動參數映射 @RequestMapping("/action0") public String action0(Model model, int id, String name) { model.addAttribute("message", "name=" + name + ",id=" + id); return "foo/index"; }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Foo</title> </head> <body> ${message} </body> </html>
運行結果如下:
包裝類型也一樣,但如果參數中沒有對應名稱與類型的數據則會異常。
1.1.2、自定義數據類型
除了基本數據類型,也可以自定義的數據類型,如一個自定義的POJO對象,Spring MVC會通過反射把請中的參數設置到對象中,轉換類型,示例代碼如下:

package com.zhangguo.springmvc03.entities; import java.io.Serializable; /** * 產品 */ public class Product implements Serializable { private static final long serialVersionUID = 1L; private int id; private String name; private double price; public Product() { } public Product(String name, double price) { super(); this.name = name; this.price = price; } public Product(int id, String name, double price) { super(); this.id = id; this.name = name; this.price = price; } @Override public String toString() { return "編號(id):" + this.getId() + ",名稱(name):" + this.getName() + ",價格(price):" + this.getPrice(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } }
// 自動參數映射自定義數據類型 @RequestMapping("/action01") public String action01(Model model, Product product) { model.addAttribute("message", product); return "foo/index"; }
運行結果如下:
示例中使用的是的URL中的參數,其實也可以是客戶端提交的任意參數,特別是表單中的數據。
1.1.3、復雜數據類型
這里指的復雜數據類型指的是一個自定義類型中還包含另外一個對象類型,如用戶類型中包含產品對象:
package com.zhangguo.springmvc03.entities; public class User { private String username; private Product product; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Product getProduct() { return product; } public void setProduct(Product product) { this.product = product; } }
示例代碼如下:
// 自動參數映射復雜數據類型 @RequestMapping("/action02") public String action02(Model model, User user) { model.addAttribute("message", user.getUsername() + "," + user.getProduct().getName()); return "foo/index"; }
測試運行結果:
為了方便這里我使用的是url,這里當然可以是一個表單,如下代碼所示:
<form method="post" action="foo/action02"> username:<input name="username" /><br/> pdctname:<input name="product.name" /><br/> <button>提交</button> </form>
1.1.4、數組
方法一:
提交時使用param1=aaa¶m1=bbb¶m1=3
接收時使用String param1[] 這種參數既可以獲取數組的值
示例:
//3.自動參數映射數組數據類型 @RequestMapping("/act03") public String act03(Model model,Integer[] id){ model.addAttribute("msg",Arrays.toString(id)); return "hi"; }
結果:
方法二:
提交時使用param1=aaa¶m1=bbb¶m1=3
接收時使用List<String> param1 這種參數既可以獲取數組的值
示例:
POJO Car.java

package com.zhangguo.springmvc01.entities; import java.util.ArrayList; import java.util.List; /**車*/ public class Car { /**編號*/ private int id; /**名稱*/ private String name; /**價格*/ private double price; /**尺寸*/ private Size size; private List<Integer> ids; public List<Integer> getIds() { return ids; } public void setIds(List<Integer> ids) { this.ids = ids; } public Car(int id, String name, double price) { this.id = id; this.name = name; this.price = price; } public Car() { } public Size getSize() { return size; } public void setSize(Size size) { this.size = size; } public static List<Car> getCars() { return cars; } public static void setCars(List<Car> cars) { Car.cars = cars; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Car{" + "id=" + id + ", name='" + name + '\'' + ", price=" + price + ", size=" + size + ", ids=" + ids + '}'; } public static List<Car> cars=new ArrayList<>(); static { cars.add(new Car(101,"朗逸",16.59)); cars.add(new Car(102,"菲斯塔",15.50)); cars.add(new Car(103,"雅閣",25.98)); cars.add(new Car(104,"卡羅拉",17.58)); cars.add(new Car(105,"軒逸",16.15)); } }
Action
@RequestMapping("/act02") public String act02(Model model,Car car){ model.addAttribute("msg",car); return "hi"; }
結果:
1.1.5、List集合類型
不能直接在action的參數中指定List<T>類型,定義一個類型包裝List集合在其中,ProductList類如下所示:
package com.zhangguo.springmvc03.entities; import java.util.List; //產品集合 public class ProductList { private List<Product> items; public List<Product> getItems() { return items; } public void setItems(List<Product> items) { this.items = items; } }
定義的action代碼如下所示:
// 集合類型 @RequestMapping("/action03") public String action03(Model model, ProductList products) { model.addAttribute("message", products.getItems().get(0) + "<br/>" + products.getItems().get(1)); return "foo/index"; }
在url中模擬表單數據,提交后的結果如下所示:
這里同樣可以使用一個表單向服務器提交數據。
TomCat高版本可能會產生如下錯誤:

java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986 at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:479) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:684) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745)
Get請求新的安全規范要求URL中不能直接帶[],如下所示:
25-Oct-2018 14:12:09.277 警告 [http-nio-8080-exec-2] org.apache.tomcat.util.http.parser.HttpParser.<clinit> Character [,] is not allowed and will continue to be rejected
解決辦法(四種):
1、替換url請求。不用{}[]特殊字符! * ’( ) ; : @ & = + $ , / ? # [ ])
2、對請求編碼解碼。 UrlDecode、UrlEncode
3、配置Tomcat對字符的支持:
3.1、更換Tomcat版本 (注,Tomcat從 7.0.73, 8.0.39, 8.5.7 版本后添加了對Url的限制。)
3.2、配置tomcat支持|{}等字符的方法是:
在 conf/catalina.properties 中最后添加一行:
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true tomcat.util.http.parser.HttpParser.requestTargetAllow=|{}[]
注3.2這種方法從8.5以后就被放棄的了,新的方法如下:
tomcat.util.http.parser.HttpParser.requestTargetAllow
is deprecated since Tomcat 8.5: tomcat official doc.
You can use relaxedQueryChars / relaxedPathChars
in the connectors definition to allow these chars: tomcat official doc.
修改conf/server.xml文件,如下所示:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8" relaxedQueryChars="],["/>
1.1.6、Map集合類型
Map與List的實現方式基本一樣,這里先定義了一個包裝Map的類型ProductMap,代碼如下所示:
package com.zhangguo.springmvc03.entities; import java.util.Map; /** * * 產品字典 */ public class ProductMap { private Map<String, Product> items; public Map<String, Product> getItems() { return items; } public void setItems(Map<String, Product> items) { this.items = items; } }
Action的定義如下:
// Map類型 @RequestMapping("/action04") public String action04(Model model, ProductMap map) { model.addAttribute("message", map.getItems().get("p1") + "<br/>" + map.getItems().get("p2")); return "foo/index"; }
測試運行結果如下:
集合類型基本都一樣,set也差不多,問題是如果為了獲得一個集合需要刻意去包裝會很麻煩,可以通過@RequestParam結合@RequestBody等注解完成。
1.2、@RequestParam參數綁定
簡單的參數可以使用上一節中講過的自動參數映射,復雜一些的需使用@RequestParam完成,雖然自動參數映射很方便,但有些細節是不能處理的,如參數是否為必須參數,名稱沒有辦法指定,參數的默認值就沒有有辦法做到了。如果使用@RequestParam可以實現請求參數綁定,Spring MVC會自動查找請求中的參數轉類型並將與參數進行綁定,示例代碼如下:
1.2.1、基本數據類型綁定與注解屬性
package com.zhangguo.springmvc03.controllers; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller @RequestMapping("/foo") public class FooController { @RequestMapping("/action1") public String action1(Model model, @RequestParam(required = false, defaultValue = "99") int id) { model.addAttribute("message", id); return "foo/index"; } }
@RequestParam共有4個注解屬性,required屬性表示是否為必須,默認值為true,如果請求中沒有指定的參數會報異常;defaultValue用於設置參數的默認值,如果不指定值則使用默認值,只能是String類型的。name與value互為別名關系用於指定參數名稱。
運行結果:
1.2.2、List與數組綁定基本數據類型
在上一節中我們使用自動參數映射是不能直接完成List與數組綁定的,結合@RequestParam可以輕松實現,示例代碼如下所示:
// List集合與數組類型 @RequestMapping("/action05") public String action05(Model model, @RequestParam("u") List<String> users) { model.addAttribute("message", users.get(0) + "," + users.get(1)); return "foo/index"; }
運行結果:
直接在URL中輸入測試數據可以綁定成功,使用表單同樣可行,頁面腳本如下:
<form action="bar/action11" method="post"> <p> <label>愛好:</label> <input type="checkbox" value="15" name="id" />閱讀 <input type="checkbox" value="20" name="id" />上網 <input type="checkbox" value="73" name="id" />電游 </p> <button>提交</button> </form>
請求處理方法action代碼如下:
// List與數組綁定基本數據類型 @RequestMapping("/action11") public String action11(Model model, @RequestParam("id") List<Integer> ids) { model.addAttribute("message", Arrays.deepToString(ids.toArray())); return "bar/index"; }
運行結果:
@RequestParam("id")是必須的,因為頁面中的表單name的名稱為id,所有服務器在收集數據時應該使用id頁非ids,如果同名則可以省去。
1.2.3、@RequestBody
@RequestBody 注解將HTTP請求正文插入方法中,使用適合的 HttpMessageConverter將請求體寫入某個對象。
作用:
1) 該注解用於讀取Request請求的body部分數據,使用系統默認配置的HttpMessageConverter進行解析,然后把相應的數據綁定到要返回的對象上;
2) 再把HttpMessageConverter返回的對象數據綁定到 controller中方法的參數上。
使用時機:
A) GET、POST方式提時, 根據request header Content-Type的值來判斷:
application/x-www-form-urlencoded, 可選(即非必須,因為這種情況的數據@RequestParam, @ModelAttribute也可以處理,當然@RequestBody也能處理);
multipart/form-data, 不能處理(即使用@RequestBody不能處理這種格式的數據);
其他格式, 必須(其他格式包括application/json, application/xml等。這些格式的數據,必須使用@RequestBody來處理);
B) PUT方式提交時, 根據request header Content-Type的值來判斷:
application/x-www-form-urlencoded, 必須;multipart/form-data, 不能處理;其他格式, 必須;
說明:request的body部分的數據編碼格式由header部分的Content-Type指定;
例如:
@RequestMapping(value = "user/login") @ResponseBody // 將ajax(datas)發出的請求寫入 User 對象中 public User login(@RequestBody User user) { // 這樣就不會再被解析為跳轉路徑,而是直接將user對象寫入 HTTP 響應正文中 return user; }
@requestBody注解常用來處理content-type不是默認的application/x-www-form-urlcoded編碼的內容,比如說:application/json或者是application/xml等。一般情況下來說常用其來處理application/json類型。
通過@requestBody可以將請求體中的JSON字符串綁定到相應的bean上,當然,也可以將其分別綁定到對應的字符串上。
例如:
$.ajax({ url:"/login", type:"POST", data:'{"userName":"admin","pwd","admin123"}', content-type:"application/json charset=utf-8", success:function(data){ alert("request success ! "); } });
action:
@requestMapping("/login") public void login(@requestBody String userName,@requestBody String pwd){ System.out.println(userName+" :"+pwd); }
這種情況是將JSON字符串中的兩個變量的值分別賦予了兩個字符串,但是呢假如我有一個User類,擁有如下字段:
String userName;
String pwd;
那么上述參數可以改為以下形式:@requestBody User user 這種形式會將JSON字符串中的值賦予user中對應的屬性上
需要注意的是,JSON字符串中的key必須對應user中的屬性名,否則是請求不過去的。
1.2.4、List與數組直接綁定自定義數據類型與AJAX
上一小節中我們綁定的集合中存放的只是基本數據類型,如果需要直接綁定更加復雜的數據類型則需要使用@RequestBody與@ResponseBody注解了,先解釋一下他們的作用:
@RequestBody 將HTTP請求正文轉換為適合的HttpMessageConverter對象。
@ResponseBody 將內容或對象作為 HTTP 響應正文返回,並調用適合HttpMessageConverter的Adapter轉換對象,寫入輸出流。
AnnotationMethodHandlerAdapter將會初始化7個轉換器,可以通過調用AnnotationMethodHandlerAdapter的getMessageConverts()方法來獲取轉換器的一個集合 List<HttpMessageConverter>,7個轉換器類型分別是
ByteArrayHttpMessageConverter
StringHttpMessageConverter
ResourceHttpMessageConverter
SourceHttpMessageConverter
XmlAwareFormHttpMessageConverter
Jaxb2RootElementHttpMessageConverter
MappingJacksonHttpMessageConverter
@RequestBody默認接收的Content-Type是application/json,因此發送POST請求時需要設置請求報文頭信息,否則Spring MVC在解析集合請求參數時不會自動的轉換成JSON數據再解析成相應的集合,Spring默認的json協議解析由Jackson完成。要完成這個功能還需要修改配置環境,具體要求如下:
a)、修改Spring MVC配置文件,啟用mvc注解驅動功能,<mvc:annotation-driven />
b)、pom.xml,添加jackson依賴,添加依賴的配置內容如下:
<!--jackson--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.7.4</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.7.4</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.7.4</version> </dependency>
c)、ajax請求時需要設置屬性dataType 為 json,contentType 為 'application/json;charse=UTF-8',data 轉換成JSON字符串,如果條件不滿足有可能會出現415異常。
Action定義的示例代碼如下:
// List與數組直接綁定自定義數據類型與AJAX @RequestMapping("/action21") public void action21(@RequestBody List<Product> products, HttpServletResponse response) throws IOException { response.setCharacterEncoding("UTF-8"); System.out.println(Arrays.deepToString(products.toArray())); response.getWriter().write("添加成功"); }
action21的參數@RequestBody List<Product> products是接收從客戶端發送到服務器的產品集合,默認的請求內容並非是application/json,而是:application/x-www-form-urlencoded,在參數前增加@RequestBody的作用是讓Spring MVC在收到客戶端請求時將選擇合適的轉換器將參數轉換成相應的對象。action22的返回值為List<Product>,且在方法上有一個注解@ResponseBody,系統會使用jackson將該對象自動序列化成json字符;在客戶端請求時設置內容類型為application/json,定義一個myform21.jsp頁面,頁面的腳本如下所示:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>List與數組直接綁定自定義數據類型與AJAX</title> </head> <body> <button type="button" onclick="addPdts_click1();">向服務器發送json</button> <button type="button" onclick="addPdts_click2();">接收服務器返回的json</button> <p id="msg"></p> <script type="text/javascript" src="<c:url value="/scripts/jQuery1.11.3/jquery-1.11.3.min.js"/>"></script> <script type="text/javascript"> var products = new Array(); products.push({ id : 1, name : "iPhone 6 Plus", price : 4987.5 }); products.push({ id : 2, name : "iPhone 7 Plus", price : 5987.5 }); products.push({ id : 3, name : "iPhone 8 Plus", price : 6987.5 }); function addPdts_click1() { $.ajax({ type : "POST", //請求謂詞類型 url : "bar/action21", data : JSON.stringify(products), //將products對象轉換成json字符串 contentType : "application/json;charset=UTF-8", //發送信息至服務器時內容編碼類型,(默認: "application/x-www-form-urlencoded") dataType : "text", //預期服務器返回的數據類型 success : function(result) { $("#msg").html(result); } }); } function addPdts_click2() { $.ajax({ type : "POST", //請求謂詞類型 url : "bar/action22", data : JSON.stringify(products), //將products對象轉換成json字符串 contentType : "application/json;charset=UTF-8", //發送信息至服務器時內容編碼類型,(默認: "application/x-www-form-urlencoded") dataType : "json", //預期服務器返回的數據類型 success : function(result) { var str = ""; $.each(result, function(i, obj) { str += "編號:" + obj.id + ",名稱:" + obj.name + ",價格:"+ obj.price + "<br/>"; }); $("#msg").html(str); } }); } </script> </body> </html>
頁面中有兩個方法,第一個方法是實現將一個json集合發送到服務器並映射成一個List集合;第二個方法是實現接收服務器返回的json對象。
點擊按鈕1時的運行結果如下:
控制台輸出:
[編號(id):1,名稱(name):iPhone 6 Plus,價格(price):4987.5, 編號(id):2,名稱(name):iPhone 7 Plus,價格(price):5987.5, 編號(id):3,名稱(name):iPhone 8 Plus,價格(price):6987.5]
點擊按鈕2時的運行結果如下:
1.3、重定向與Flash屬性
在一個請求處理方法Action中如果返回結果為“index”字符則表示轉發到視圖index,有時候我們需要重定向,則可以在返回的結果前加上一個前綴“redirect:”,可以重定向到一個指定的頁面也可以是另一個action,示例代碼如下:
// 重定向 @RequestMapping("/action2") public String action2(Model model) { return "foo/index"; } @RequestMapping("/action3") public String action3(Model model) { model.addAttribute("message", "action3Message"); return "redirect:action2"; }
當請求http://localhost:8087/SpringMVC02/foo/action3時運行結果如下:
在action3中返回的結果為redirect:action2,則表示重定向到action2這個請求處理方法,所有重定向都是以當前路徑為起點的,請注意路徑。在action3向model中添加了名稱message的數據,因為重定向到action2中會發起2次請求,為了保持action3中的數據Spring MVC自動將數據重寫到了url中。為了實現重定向時傳遞復雜數據,可以使用Flash屬性,示例代碼如下:
// 接收重定向參數 @RequestMapping("/action2") public String action2(Model model, Product product) { model.addAttribute("message", product); System.out.println(model.containsAttribute("product")); // true return "foo/index"; }
//重定向屬性 @RequestMapping("/action3") public String action3(Model model, RedirectAttributes redirectAttributes) { Product product = new Product(2, "iPhone7 Plus", 6989.5); redirectAttributes.addFlashAttribute("product", product); return "redirect:action2"; }
當訪問action3時,首先創建了一個product產口對象,將該對象添加到了Flash屬性中,在重定向后取出,個人猜測應該暫時將對象存入了Session中。當請求foo/action3時運行結果如下:
url地址已經發生了變化,product對象其實也已經被存入了model中,在action的視圖中可以直接拿到。
1.4、轉發
str=”forward : 路徑” 請求轉發到一個頁面中
str=”forward : controller的映射” 請求轉發到一個controller方法中
示例:
//11.轉發 @RequestMapping("/act11") public String act11(Model model){ return "hi"; } //12.轉發 @RequestMapping("/act12") public String act12(Model model){ model.addAttribute("msg","act12"); return "forward:act11"; }
結果:
URL沒有變化,數據存在可以直接使用。
1.5、@ModelAttribute模型特性
@ModelAttribute可以應用在方法參數上或方法上,他的作用主要是當注解在方法中時會將注解的參數對象添加到Model中;當注解在請求處理方法Action上時會將該方法變成一個非請求處理的方法,但其它Action被調用時會首先調用該方法。
1.5.1、注解在參數上
當注解在參數上時會將被注解的參數添加到Model中,並默認完成自動數據綁定,示例代碼如下:
@RequestMapping("/action6") public String action6(Model model, @ModelAttribute(name = "product", binding = true) Product entity) { model.addAttribute("message", model.containsAttribute("product") + "<br/>" + entity); return "foo/index"; }
運行結果:
其實不使用@ModelAttribute我也樣可以完成參數與對象間的自動映射,但使用注解可以設置更多詳細內容,如名稱,是否綁定等。
1.5.2、注解在方法上
用於標注一個非請求處理方法,通俗說就是一個非Action,普通方法。如果一個控制器類有多個請求處理方法,以及一個有@ModelAttribute注解的方法,則在調用其它Action時會先調用非請求處理的Action,示例代碼如下:
@RequestMapping("/action7") public String action7(Model model) { Map<String, Object> map = model.asMap(); for (String key : map.keySet()) { System.out.println(key + ":" + map.get(key)); } return "foo/index"; } @ModelAttribute public String noaction() { System.out.println("noaction 方法被調用!"); String message = "來自noaction方法的信息"; return message; }
當訪問http://localhost:8087/SpringMVC03/foo/action7時,控制台顯示結果如下:
非請求處理方法可以返回void,也可以返回一個任意對象,該對象會被自動添加到每一個要被訪問的Action的Model中,key從示例中可以看出為類型名稱。
二、Action返回值類型
ModelAndView
Model
Map 包含模型的屬性
View
String 視圖名稱
void
HttpServletResponse
HttpEntity<?>或ResponseEntity<?>
HttpHeaders
Callable<?>
DeferredResult<?>
ListenableFuture<?>
ResponseBodyEmitter
SseEmitter
StreamingResponseBody
其它任意類型,Spring將其視作輸出給View的對象模型
2.1、視圖中url問題
新增一個action5,代碼如下:
@RequestMapping("/action5") public String action5(Model model) { return "foo/action5"; }
在foo目錄下添加視圖action5.jsp,內容如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>action5的視圖</title> </head> <body> <img alt="風景" src="../../images/3.jpg"> </body> </html>
目標結構如下:
訪問結果:
這里圖片訪問不到的原因是因為:action5.jsp視圖此時並非以它所在的目錄為實際路徑,他是以當前action所在的控制器為起始目錄的,當前控制器的url為:http://localhost:8087/SpringMVC02/foo/,而圖片的src為:../../images/3.jpg,向上2級后變成:http://localhost:8087/images/3.jpg,但我們的項目實際路徑中並沒有存放3.jpg這張圖片,解決的辦法是在視圖中使用“絕對”路徑;另外一個問題是我們將靜態資源存放到WEB-INF下不太合理,因為該目錄禁止客戶端訪問,修改后的視圖如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>action5的視圖</title> </head> <body> <img alt="風景" src="<c:url value="/images/3.jpg"></c:url>"> </body> </html>
目錄結構變化后如下所示:
運行結果:
小結:主要是借助了標簽<c:url value="/images/3.jpg"></c:url>,將路徑轉換成“絕對路徑”;建議在引用外部資源如js、css、圖片信息時都使用該標簽解析路徑。
2.2、返回值為String
2.2.1、String作為視圖名稱
默認如果action返回String,此時的String為視圖名稱,會去視圖解析器的設定的目錄下查找,查找的規則是:URL= prefix前綴+視圖名稱 +suffix后綴組成,示例代碼如下:
//返回值為String @RequestMapping("/action31") public String action31(Model model) { model.addAttribute("message","action31"); return "bar/action31"; }
Spring MVC的配置文件內容如下:
<!-- 視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前綴 --> <property name="prefix" value="/WEB-INF/views/" /> <!-- 后綴 --> <property name="suffix" value=".jsp" /> </bean>
實際url=/WEB-INF/views/bar/action31.jsp
2.2.2、String作為內容輸出
如果方法聲明了注解@ResponseBody ,將內容或對象作為 HTTP 響應正文返回,並調用適合HttpMessageConverter的Adapter轉換對象,寫入輸出流。些時的String不再是路徑而是內容,示例腳本如下:
@RequestMapping("/action32") @ResponseBody public String action32() { return "not <b>path</b>,but <b>content</b>"; }
測試運行結果:
2.3、返回值為void
void在普通方法中是沒有返回值的意思,但作為請求處理方法並非這樣,存在如下兩種情況:
2.3.1、方法名默認作為視圖名
當方法沒有返回值時,方法中並未指定視圖的名稱,則默認視圖的名稱為方法名,如下代碼所示:
@RequestMapping("/action33") public void action33() { }
直接會去訪問的路徑是:url=/WEB-INF/views/bar/action33.jsp,bar是當前控制器映射的路徑,action33是方法名,上面的代碼等同於:
@RequestMapping("/action33") public String action33() { return "bar/action33"; //bar是控制器的路徑 }
可見URL= prefix前綴+控制器路徑+方法名稱 +suffix后綴組成。
2.3.2、直接響應輸出結果
當方法的返回值為void,但輸出流中存在輸出內容時,則不會去查找視圖,而是將輸入流中的內容直接響應到客戶端,響應的內容類型是純文本,如下代碼所示:
@RequestMapping("/action34") public void action34(HttpServletResponse response) throws IOException { response.getWriter().write("<h2>void method</h2>"); }
運行結果如下:
可以看到h2標簽並未渲染成標題。
2.4、返回值為ModelAndView
在舊的Spring MVC中ModelAndView使用頻率非常高,它可以同時指定須返回的模型與視圖對象或名稱,示例代碼如下:
@RequestMapping("/action35") public ModelAndView action35() { //1只指定視圖 //return new ModelAndView("/bar/index"); //2分別指定視圖與模型 //Map<String, Object> model=new HashMap<String,Object>(); //model.put("message", "ModelAndView action35"); //return new ModelAndView("/bar/index",model); //3同時指定視圖與模型 //return new ModelAndView("/bar/index","message","action35 ModelAndView "); //4分開指定視圖與模型 ModelAndView modelAndView=new ModelAndView(); //指定視圖名稱 modelAndView.setViewName("/bar/index"); //添加模型中的對象 modelAndView.addObject("message", "<h2>Hello ModelAndView</h2>"); return modelAndView; }
ModelAndView有個多構造方法重載,單獨設置屬性也很方便,運行結果如下:
2.5、返回值為Map
當返回結果為Map時,相當於只是返回了Model,並未指定具體的視圖,返回視圖的辦法與void是一樣的,即URL= prefix前綴+控制器路徑+方法名稱 +suffix后綴組成,示例代碼如下:
@RequestMapping("/action36") public Map<String, Object> action36() { Map<String, Object> model=new HashMap<String,Object>(); model.put("message", "Hello Map"); model.put("other", "more item"); return model; }
實際訪問的路徑是:/SpringMVC03/WEB-INF/views/bar/action36.jsp,返回給客戶端的map相當於模型,在視圖中可以取出。
2.6、返回值為任意類型
2.6.1、返回值為基本數據類型
當返回結果直接為int,double,boolean等基本數據類型時的狀態,測試代碼如下:
@RequestMapping("/action37") public Integer action37() { return 9527; }
測試運行的結果是:exception is java.lang.IllegalArgumentException: Unknown return value type異常。
如果確實需要直接將基本數據類型返回,則可以使用注解@ReponseBody。
@RequestMapping("/action38") @ResponseBody public int action38() { return 9527; }
運行結果:
2.6.2、當返值為自定義類型
當返回值為自定義類型時Spring會把方法認為是視圖名稱,與返回值為void的類似辦法處理URL,但頁面中獲得數據比較麻煩,示例代碼如下:
@RequestMapping("/action39") public Product action39() { return new Product(1,"iPhone",1980.5); }
如果存在action39對應的視圖,頁面還是可以正常顯示。
如果在action上添加@ResponseBody注解則返回的是Product本身,而非視圖,Spring會選擇一個合適的方式解析對象,默認是json。示例代碼如下:
@RequestMapping("/action39") @ResponseBody public Product action39() { return new Product(1,"iPhone",1980.5); }
運行結果:
如果是接收json值,則需要使用注解@RequestBody指定在相應參數上。
2.7、返回值為Model類型
該接口Model定義在包org.springframework.ui下,model對象會用於頁面渲染,視圖路徑使用方法名,與void類似。示例代碼如下:
@RequestMapping("/action40") public Model action40(Model model) { model.addAttribute("message", "返回類型為org.springframework.ui.Model"); return model; }
運行結果:
2.8、自定義輸出內容
2.8.1、輸出Excel
返回的類型還有許多如view等,通過view可指定一個具體的視圖,如下載Excel、Pdf文檔,其實它們也修改http的頭部信息,手動同樣可以實現,如下代碼所示:
@RequestMapping("/action41") @ResponseBody public String action41(HttpServletResponse response) { response.setHeader("Content-type","application/octet-stream"); response.setHeader("Content-Disposition","attachment; filename=table.xls"); return "<table><tr><td>Hello</td><td>Excel</td></tr></table>"; }
運行結果:
Content-disposition解釋:
Content-disposition 是 MIME 協議的擴展,MIME 協議指示 MIME 用戶代理如何顯示附加的文件。當 Internet Explorer 接收到頭時,它會激活文件下載對話框,它的文件名框自動填充了頭中指定的文件名。(請注意,這是設計導致的;無法使用此功能將文檔保存到用戶的計算機上,而不向用戶詢問保存位置。)
服務端向客戶端游覽器發送文件時,如果是瀏覽器支持的文件類型,一般會默認使用瀏覽器打開,比如txt、jpg等,會直接在瀏覽器中顯示,如果需要提示用戶保存,就要利用Content-Disposition進行一下處理,關鍵在於一定要加上attachment:
Response.AppendHeader("Content-Disposition","attachment;filename=FileName.txt");
Content-Type解釋:
MediaType,即是Internet Media Type,互聯網媒體類型;也叫做MIME類型,在Http協議消息頭中,使用Content-Type來表示具體請求中的媒體類型信息。
例如: Content-Type: text/html;charset:utf-8;
常見的MIME:

常見的媒體格式類型如下: text/html : HTML格式 text/plain :純文本格式 text/xml : XML格式 image/gif :gif圖片格式 image/jpeg :jpg圖片格式 image/png:png圖片格式 以application開頭的媒體格式類型: application/xhtml+xml :XHTML格式 application/xml : XML數據格式 application/atom+xml :Atom XML聚合格式 application/json : JSON數據格式 application/pdf :pdf格式 application/msword : Word文檔格式 application/octet-stream : 二進制流數據(如常見的文件下載) application/x-www-form-urlencoded : <form encType=””>中默認的encType,form表單數據被編碼為key/value格式發送到服務器(表單默認的提交數據的格式) 另外一種常見的媒體格式是上傳文件之時使用的: multipart/form-data : 需要在表單中進行文件上傳時,就需要使用該格式
2.8.2、導出XLS時增加BOM頭部解決亂碼問題
action代碼如下:
//21.下載附件,導出Excel,xls @RequestMapping("/act21") @ResponseBody public void act21(HttpServletResponse response) throws IOException { //POI //response.setContentType("text/html;charset=utf-8"); //response.setCharacterEncoding("utf-8"); //問題:下載xls問題用excel打開亂碼,用notepad++等工具轉成UTF-8格式(帶BOM)可以正常打開。 //解決:嚴格來說這並不是xls文件的問題,而是Excel處理文件編碼方式問題,Excel默認並不是以UTF-8來打開文件,所以在xls開頭加入BOM,告訴Excel文件使用utf-8的編碼方式。 response.setHeader("Content-Type","application/octet-stream;charset=utf-8"); response.setHeader("Content-Disposition","attachment;filename=Cars.xls"); PrintWriter out = response.getWriter(); //加上bom頭,解決excel打開亂碼問題 byte[] bomStrByteArr = new byte[] { (byte) 0xef, (byte) 0xbb, (byte) 0xbf }; String bomStr = new String(bomStrByteArr, "UTF-8"); out.write(bomStr); StringBuffer str=new StringBuffer(""); str.append("<table border=1 width=100%>"); str.append("<tr><th>編號</th><th>名稱</th><th>價格</th></tr>"); for (Car car: Car.cars) { str.append("<tr><td>"+car.getId()+"</td><td>"+car.getName()+"</td><td>"+car.getPrice()+"</td></tr>"); } str.append("</table>"); out.write(str.toString()); }
導出結果:
2.8.3、導出CSV格式
上面的方式並非Excel原生支持的,只是轉換HTML的結果,轉換成csv更好,占用空間更少。
逗號分隔值CSV
逗號分隔值(Comma-Separated Values,CSV,有時也稱為字符分隔值,因為分隔字符也可以不是逗號),其文件以純文本形式存儲表格數據(數字和文本)。純文本意味着該文件是一個字符序列,不含必須像二進制數字那樣被解讀的數據。CSV文件由任意數目的記錄組成,記錄間以某種換行符分隔;每條記錄由字段組成,字段間的分隔符是其它字符或字符串,最常見的是逗號或制表符。通常,所有記錄都有完全相同的字段序列。通常都是純文本文件。建議使用WORDPAD或是記事本(NOTE)來開啟,再則先另存新檔后用EXCEL開啟,也是方法之一。
規則
1、開頭是不留空,以行為單位。 2、可含或不含列名,含列名則居文件第一行。 3、一行數據不跨行,無空行。 4、以半角逗號(即,)作分隔符,列為空也要表達其存在。 5、列內容如存在半角引號(即"),替換成半角雙引號("")轉義,即用半角引號(即"")將該字段值包含起來。 6、文件讀寫時引號,逗號操作規則互逆。 7、內碼格式不限,可為 ASCII、Unicode 或者其他。 8、不支持數字 9、不支持特殊字符
示例
1997,Ford,E350,"ac, abs, moon",3000.00 1999,Chevy,"Venture ""Extended Edition""","",4900.00 1999,Chevy,"Venture ""Extended Edition, Very Large""","",5000.00 1996,Jeep,Grand Cherokee,"MUST SELL!
action代碼如下:
//22.下載附件,導出Excel,csv @RequestMapping("/act22") @ResponseBody public void act22(HttpServletResponse response) throws IOException { //POI //response.setContentType("text/html;charset=utf-8"); //response.setCharacterEncoding("utf-8"); response.setHeader("Content-Type","application/octet-stream;charset=utf-8"); response.setHeader("Content-Disposition","attachment;filename=Cars.csv"); PrintWriter out = response.getWriter(); //加上bom頭,解決excel打開亂碼問題 byte[] bomStrByteArr = new byte[] { (byte) 0xef, (byte) 0xbb, (byte) 0xbf }; String bomStr = new String(bomStrByteArr, "UTF-8"); out.write(bomStr); StringBuffer str=new StringBuffer(""); str.append("編號,名稱,價格\r\n"); for (Car car: Car.cars) { str.append(car.getId()+","+car.getName()+","+car.getPrice()+"\r\n"); } response.getWriter().write(str.toString()); }
結果:
2.8、@ResponseBody
默認情況下面Spring MVC會使用如下流程處理請求與響應結果:
@ResponseBody是作用在方法上的,@ResponseBody 表示該方法的返回結果直接寫入 HTTP response body 中,一般在異步獲取數據時使用【也就是AJAX】,在使用 @RequestMapping后,返回值通常解析為跳轉路徑,但是加上 @ResponseBody 后返回結果不會被解析為跳轉路徑,而是直接寫入 HTTP response body 中。 比如異步獲取 json 數據,加上 @ResponseBody 后,會直接返回 json 數據。@RequestBody 將 HTTP 請求正文插入方法中,使用適合的 HttpMessageConverter 將請求體寫入某個對象。
如下面的源代碼所示,ResponseBody可以同時注解在方法與控制器上面:

/* * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.bind.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation that indicates a method return value should be bound to the web * response body. Supported for annotated handler methods in Servlet environments. * * <p>As of version 4.0 this annotation can also be added on the type level in * which case it is inherited and does not need to be added on the method level. * * @author Arjen Poutsma * @since 3.0 * @see RequestBody * @see RestController */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ResponseBody { }
如果注解在控制器上面將作用與每一個方法上,每個方法都將受到影響。
2.9、@RestController
Spring 4 MVC中提供的@RestController,使用最少的代碼來構建一個Restful Web Service,支持返回xml或json數據,這個可以讓用戶選擇,通過URL后綴.xml或.json來完成。
REST即表述性狀態傳遞(英文:Representational State Transfer,簡稱REST)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟件架構風格。它是一種針對網絡應用的設計和開發方式,可以降低開發的復雜性,提高系統的可伸縮性。
目前在三種主流的Web服務實現方案中,因為REST模式的Web服務與復雜的SOAP和XML-RPC對比來講明顯的更加簡潔,越來越多的web服務開始采用REST風格設計和實現。例如,Amazon.com提供接近REST風格的Web服務進行圖書查找;雅虎提供的Web服務也是REST風格的。
Rest風格的URL:
新增: http://www.zhangguo.com/order POST 修改: http://www.zhangguo.com/order/1 PUT update?id=1 獲取:http://www.zhangguo.com/order/1 GET get?id=1 刪除: http://www.zhangguo.com/order/1 DELETE delete?id=1
實現方法一:
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping(value="/restservice") public class RestService { public final static String SUCCEEDD="show"; /** * get請求 * url: http://localhost:8080/springmvc/restservice/testRestGet/12 * @param id * 查詢的參數 * @return */ @RequestMapping(value="/testRestGet/{id}",method=RequestMethod.GET) public String testRestGet(@PathVariable("id") Integer id){ System.out.println("rest 風格的GET請求..........id=" +id); return SUCCEEDD; } /** * post新增 * url: http://localhost:8080/springmvc/restservice/testRestPost * @return */ @RequestMapping(value="/testRestPost",method=RequestMethod.POST) public String testRestPost(){ System.out.println("rest 風格的POST請求.......... "); return SUCCEEDD; } /** * PUT 修改操作 * url: http://localhost:8080/springmvc/restservice/testRestPut/put123 * @param name * @return */ @RequestMapping(value="/testRestPut/{name}",method=RequestMethod.PUT) public String testRestPut(@PathVariable("name") String name){ System.out.println("rest 風格的PUT請求..........name="+name); return SUCCEEDD; } /** * DELETE刪除操作 * url: http://localhost:8080/springmvc/restservice/testRestDelete/11 * @param id * @return */ @RequestMapping(value="/testRestDelete/{id}",method=RequestMethod.DELETE) public String testRestDelete(@PathVariable Integer id){ System.out.println("rest 風格的DELETE請求..........id="+id); return SUCCEEDD; } }
不難發現@RestController是繼承自@Controller與@ResponseBody的,所以它同時擁有他們的特性:
/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.web.bind.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.stereotype.Controller; /** * A convenience annotation that is itself annotated with * {@link Controller @Controller} and {@link ResponseBody @ResponseBody}. * <p> * Types that carry this annotation are treated as controllers where * {@link RequestMapping @RequestMapping} methods assume * {@link ResponseBody @ResponseBody} semantics by default. * * <p><b>NOTE:</b> {@code @RestController} is processed if an appropriate * {@code HandlerMapping}-{@code HandlerAdapter} pair is configured such as the * {@code RequestMappingHandlerMapping}-{@code RequestMappingHandlerAdapter} * pair which are the default in the MVC Java config and the MVC namespace. * In particular {@code @RestController} is not supported with the * {@code DefaultAnnotationHandlerMapping}-{@code AnnotationMethodHandlerAdapter} * pair both of which are also deprecated. * * @author Rossen Stoyanchev * @author Sam Brannen * @since 4.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller @ResponseBody public @interface RestController { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any * @since 4.0.1 */ String value() default ""; }
可以輕松的將上面的代碼修改為@RestController注解實現。
package com.zhangguo.springmvc01.controller; import com.zhangguo.springmvc01.entities.Car; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/car") public class CarController { @GetMapping("/{id}") public Car getCar(@PathVariable int id){ return null; } @DeleteMapping("/{id}") public Car deleteCar(@PathVariable int id){ return null; } @PostMapping public Car addCar(Car car){ return null; } @PutMapping public Car updateCar(Car car){ return null; } }
2.10、小結
使用 String 作為請求處理方法的返回值類型是比較通用的方法,這樣返回的邏輯視圖名不會和請求 URL 綁定,具有很高的靈活性,而模型數據又可以通過Model控制。
使用void,map,Model時,返回對應的邏輯視圖名稱真實url為:prefix前綴+控制器路徑+方法名 +suffix后綴組成。
使用String,ModelAndView返回視圖名稱可以不受請求的url綁定,ModelAndView可以設置返回的視圖名稱。
另外在非MVC中使用的許多辦法在Action也可以使用。
三、Spring MVC亂碼解決方法
3.1、頁面編碼
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
3.2、URL中的亂碼
改tomcat中server.xml中Connector的port=“8080”,加上一個 URIEncoding=”utf-8”
3.3、配置過濾器,指定所有請求的編碼
(1)配置spring的編碼過濾器,為了防止spring中post方式提交的時候中文亂碼,方法:修改web.xml文件,添加spring的編碼過濾器
<!-- 配置編碼方式過濾器,注意一點:要配置在所有過濾器的前面 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
(2)配置編碼過濾器,方法:先創建filter類,再修改web.xml文件,注意的是放在spring的編碼過濾器之后
filter類:

package com.qiyuan.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class EncoidingFilter implements Filter { private String encoding=""; @Override public void destroy() { // TODO Auto-generated method stub } //過濾方法 是否往下執行 @Override public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest)arg0; HttpServletResponse response=(HttpServletResponse)arg1; request.setCharacterEncoding(encoding); response.setCharacterEncoding(encoding); //過濾通行證 chain.doFilter(request, response); } //根據web.xml文件的配置進行初始化 @Override public void init(FilterConfig arg0) throws ServletException { this.encoding = arg0.getInitParameter("Encoding"); } }
修改web.xml,添加如下配置:
<!-- 配置編碼過濾 --> <filter> <filter-name>EncoidingFilter</filter-name> <filter-class>com.qiyuan.filter.EncoidingFilter</filter-class> <init-param> <param-name>Encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>EncoidingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3.4、文件編碼
將文件另存為utf-8格式
3.5、數據庫編碼
連接字符串指定編碼格式
public static String URL="jdbc:mysql://127.0.0.1:3306/mvcdb?useUnicode=true&characterEncoding=UTF-8"
創建數據庫的時候指定utf-8編碼格式
3.6、IDE中文件與工程的編碼
工程編碼(最后一開始建立工程就設置整個工程的編碼,如UTF-8)
四、示例
https://zhangguo5.coding.net/public/SpringMVCDemo/SpringMVCDemo/git
五、視頻
https://www.bilibili.com/video/av16991874/
六、作業
1、重現文中所有示例
2、定義一個員工實體(Employee),實現批量添加員工功能,在表單中可以一次添加多個員工,數據可以不持久化,使用JSTL渲染頁面,數據要發到服務器后再響應到頁面中
3、繼續完善個人項目的前后台頁面
4、定義一個員工實體(Employee),實現批量添加員工功能,在表單中可以一次添加多個員工,數據可以不持久化,使用AJAX渲染頁面,數據要發到服務器后再響應到頁面中
5、個人項目后台至少3個頁面(登錄,主頁,二級頁面),前端至少6個頁面
6、將第4題修改為CRUD,使用JSTL實現,使用集合,可以不持久化到數據庫。
7、升級員工管理功能,實現如下功能:
7.1、添加
7.2、修改
7.3、刪除
7.4、批量刪除
7.5、查詢
7.6、導出(XLS、CSV、DOC)
7.7、導入(上傳,POI解析,組員選作)
嘗試使用Rest風格