本篇文章我們來學(xué)習(xí)一下SpringMVC中是如何處理請求中的參數(shù)的。
回想一下原生Servlet是如何處理請求參數(shù)的?我們需要使用HttpServletRequest調(diào)用getParameter方法進(jìn)行獲取,就像這樣:
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 獲取參數(shù)值
String username = req.getParameter("username");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
下面來看看SpringMVC是如何處理這一需求的。
@RequestParam
在SpringMVC中,我們可以直接在方法上聲明入?yún)@取請求參數(shù),比如:
@Controller
public class HelloController {
@RequestMApping("/hello")
public String hello(String username) {
System.out.println(username);
return "success";
}
}
那在傳遞參數(shù)的時候參數(shù)名就必須指定為username,這樣處理方法就能夠直接獲取到請求參數(shù),當(dāng)然了,這樣獲取有一個弊端,就是參數(shù)名被固定了,只能是username,我們可以在參數(shù)前添加@RequestParam注解來解決:
@RequestMapping("/hello")
public String hello(@RequestParam("user") String username) {
System.out.println(username);
return "success";
}
此時參數(shù)名就可以隨意定義,轉(zhuǎn)而由@RequestParam注解來指定需要接收的參數(shù)名。
當(dāng)請求中未攜帶user參數(shù)時,程序就會出錯:
Resolved exception caused by handler execution: org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'user' is not present
這是因?yàn)锧RequestParam默認(rèn)要求參數(shù)必須攜帶,否則就會報(bào)錯,可以通過修改注解中的required屬性值來解決這一個問題:
@RequestMapping("/hello")
public String hello(@RequestParam(value = "user",required = false) String username) {
System.out.println(username);
return "success";
}
此時無論是否攜帶user參數(shù),程序都不會出錯,當(dāng)未攜帶user參數(shù)時,username值為null。
還可以通過配置defaultValue屬性值來指定當(dāng)參數(shù)未攜帶時的默認(rèn)值:
@RequestMapping("/hello")
public String hello(@RequestParam(value = "user",required = false,defaultValue = "zhang") String username) {
System.out.println(username);
return "success";
}
此時當(dāng)請求未攜帶user參數(shù)時,username值為 zhang 。
@RequestHeader
SpringMVC中也能非常方便地獲取請求頭中的信息,如:
@RequestMapping("/hello")
public String hello(@RequestHeader("User-Agent") String userAgent) {
System.out.println(userAgent);
return "success";
}
通過@RequestHeader注解即可輕松獲取請求頭信息,其value值為請求頭的key,和@RequestParam注解類似,當(dāng)試圖去獲取一個不存在的請求頭時,程序便會報(bào)錯:
@RequestMapping("/hello")
public String hello(@RequestHeader("test") String userAgent) {
System.out.println(userAgent);
return "success";
}
報(bào)錯信息為:
Missing request header 'test' for method parameter of type String
所以也可以在注解中添加required屬性來解決:
@RequestMapping("/hello")
public String hello(@RequestHeader(value = "test",required = false) String userAgent) {
System.out.println(userAgent);
return "success";
}
defaultValue屬性也是一樣的用法。
@RequestBody
在前后端分離的項(xiàng)目開發(fā)中,后端接收到的往往并不是一個直接的字符參數(shù),而是一串JSON數(shù)據(jù),那么該如何處理JSON類型的請求參數(shù)呢?
其實(shí)很簡單,先接收到JSON參數(shù),再通過一些第三方庫將JSON解析成正常的屬性值即可,而在SpringMVC中,可以直接使用@RequestBody注解來解決:
@RequestMapping("/hello")
public String hello(@RequestBody String json) {
System.out.println(json);
return "success";
}
通過這種方式能夠獲取到前端提交的JSON參數(shù):
{"name:"張三","age":"20"}
你還可以直接將請求參數(shù)中的JSON串轉(zhuǎn)換為Bean對象:
@RequestMapping("/hello")
public String hello(@RequestBody Person person) {
System.out.println(person);
return "success";
}
此時SpringMVC將按照參數(shù)名和Person對象中的屬性名進(jìn)行一一對應(yīng),并將參數(shù)值封裝到Person中生成一個對象,這樣便極大地方便了開發(fā)流程。
@CookieValue
通過@CookieValue注解可以很方便地獲取到請求中的cookie信息:
@RequestMapping("/hello")
public String hello(@CookieValue("_ga") String ga) {
System.out.println(ga);
return "success";
}
同理,若是獲取不存在的cookie,也會出現(xiàn)錯誤,解決方案和前面是一樣的,就不再贅述了。
傳入對象類型
當(dāng)請求參數(shù)較為復(fù)雜時,比如一個對象,如果借助@RequestParam注解,就必須這樣:
@RequestMapping("/hello")
public String hello(
@RequestParam("name") String name,
@RequestParam("age") Integer age,
@RequestParam("sex") Character sex,
@RequestParam("address") String address
) {
System.out.println(name);
System.out.println(age);
System.out.println(sex);
System.out.println(address);
return "success";
}
并且隨著參數(shù)的增多,這種冗余的代碼還要繼續(xù)編寫,為此,SpringMVC有一個更加優(yōu)雅的解決方案,就是直接接收一個對象類型的參數(shù),所以,要先將這些參數(shù)封裝成一個對象:
@Data
@ToString
public class Person {
private String name;
private Integer age;
private Character sex;
private String address;
}
此時方法中只需接收一個Person類型的參數(shù)即可:
@RequestMapping("/hello")
public String hello(Person person) {
System.out.println(person);
return "success";
}
它同時還支持級聯(lián)封裝,如:
@Data
@ToString
public class Person {
private String name;
private Integer age;
private Character sex;
private Address address;
}
@Data
@ToString
public class Address {
private String province;
private String city;
}
現(xiàn)在Person對象中的地址屬性仍然是一個對象,SpringMVC仍然能夠?qū)?shù)據(jù)準(zhǔn)確無誤地封裝到Person參數(shù)中,但請求參數(shù)在傳遞時就需要通過 . 來進(jìn)行傳送,比如:
http://localhost:8080/hello?name=zhangsan&sex=f&age=20&address.province=jiangxi&address.city=nanchang
需要注意的是請求參數(shù)中的參數(shù)名必須和對象中定義的屬性名一致。
傳入原生API
有時候一些需求也不得不使用到原生的API,比如設(shè)置cookie、session等,SpringMVC當(dāng)然也考慮到了這一點(diǎn),所以若是想使用原生的API,則直接寫到方法的入?yún)⒅屑纯桑纾?/p>
@RequestMapping("/hello")
public String hello(HttpServletResponse response) {
Cookie cookie = new Cookie("test", "test");
response.addCookie(cookie);
return "success";
}
想操作Session,就將HttpSession作為參數(shù)傳入:
@RequestMapping("/hello")
public String hello(HttpSession session) {
session.setAttribute("test","test");
return "success";
}
SpringMVC支持以下九個ServletAPI的對象:
1.HttpServletRequest2.HttpServletResponse3.HttpSession4.JAVA.security.Principal5.Locale6.InputStream7.OutputStream8.Reader9.Writer
這九個對象都能夠直接以參數(shù)的形式傳入方法中。
解決亂碼問題
如果在發(fā)送請求時攜帶的參數(shù)是中文的,就會產(chǎn)生亂碼,在原生的Servlet開發(fā)中,我們通常使用:
request.setCharacterEncoding("UTF-8");
但這是用來解決POST請求亂碼的,對于響應(yīng)的亂碼,應(yīng)使用:
response.setContentType("text/html;charset=utf-8");
然而在SpringMVC中,我們通常不會使用到HttpServletRequest和HttpServletResponse對象,那么亂碼問題該如何解決呢?
可以定義一個Filter過濾器,來攔截所有請求,并在過濾器中集中處理亂碼的問題,SpringMVC已經(jīng)考慮到了這一點(diǎn),并為我們提供了一個專門解決亂碼問題的過濾器CharacterEncodingFilter,只需在web.xml文件中進(jìn)行配置:
<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>
注意:若項(xiàng)目中配置了多個Filter,則CharacterEncodingFilter一定要配置在其它Filter之前。
以上便是有關(guān)SpringMVC中處理請求參數(shù)的全部內(nèi)容!