控制器參數(Parameter)
WebMVC模組不但讓編寫控制器變得非常簡單,處理請求參數也變得更容易! WebMVC會根據控制器方法參數或類別成員的註解配置,自動轉換與方法參數或類別成員對應的資料類型,參數的綁定涉及以下註解:
##基本參數註解
- @RequestParam:綁定請求中的參數;
- @RequestHeader:綁定請求頭中的參數變數;
- @CookieVariable:綁定Cookie中的參數變數;
value:參數名稱,若未指定則預設採用方法參數變數名;prefix:參數名稱前綴,預設為"";defaultValue:指定參數的預設值,預設為"";範例程式碼:
@Controller @RequestMapping("/demo") public class DemoController { @RequestMapping("/param") public IView testParam(@RequestParam String name, @RequestParam(defaultValue = "18") Integer age, @RequestParam(value = "name", prefix = "user") String username, @RequestHeader(defaultValue = "BASIC") String authType, @CookieVariable(defaultValue = "false") Boolean isLogin) { System.out.println("AuthType: " + authType); System.out.println("IsLogin: " + isLogin); return View.textView("Hi, " + name + ", UserName: " + username + ", Age: " + age); } }
http://localhost:8080/demo/param?name=webmvc&user.name=ymper
控制台输出: AuthType: BASIC IsLogin: false 浏览器输出: Hi, webmvc, UserName: ymper, Age: 18
- ##@ PathVariable:綁定請求對應中的路徑參數變數;
- value:參數名稱,若未指定則預設採用方法參數變數名稱;
範例程式碼:
@Controller @RequestMapping("/demo") public class DemoController { @RequestMapping("/path/{name}/{age}") public IView testPath(@PathVariable String name, @PathVariable(value = "age") Integer age, @RequestParam(prefix = "user") String sex) { return View.textView("Hi, " + name + ", Age: " + age + ", Sex: " + sex); } }
透過瀏覽器存取URL測試:http://localhost:8080/demo/path/webmvc/20?user.sex=F
執行結果:Hi, webmvc, Age: 20, Sex: F
注意
:基於路徑的參數變數必須是連續的,如:
- 正確:/path/{name}/{age}
- 錯誤:/path/{name}/age/{sex}
@ModelBind:值物件參數綁定註解; - #prefix:綁定的參數名稱前綴,可選參數,預設為"";
範例程式碼:
public class DemoVO { @PathVariable private String name; @RequestParam private String sex; @RequestParam(prefix = "ext") private Integer age; // 省略Get和Set方法 } @Controller @RequestMapping("/demo") public class DemoController { @RequestMapping("/bind/{demo.name}") public IView testBind(@ModelBind(prefix = "demo") DemoVO vo) { String _str = "Hi, " + vo.getName() + ", Age: " + vo.getAge() + ", Sex: " + vo.getSex(); return View.textView(_str); } }
透過瀏覽器存取URL測試:http://localhost:8080/demo/bind/webmvc?demo.sex=F&demo.ext.age=20
執行結果:Hi, webmvc, Age: 20, Sex: F
##@ParameterEscape:控制器方法參數轉義註解;
可以透過WebMVC模組設定參數
parameter_escape_order
設定是在控制器方法參數執行驗證之前還是之後執行參數轉義動作,參數取值範圍為before
或after
#,預設為after
即參數驗證之後進行轉義;scope:字串參數轉義範圍,預設為Type.EscapeScope.DEFAULT;
- 取值範圍包括:JAVA, JS, HTML, XML, SQL, CSV, DEFAULT;
- 預設值DEFAULT,它完成了對SQL和HTML兩個轉義;
#skiped:通知父級註解目前方法或參數的轉義操作將被忽略,預設為false;
processor:自訂字串參數轉義處理器;
- #可以透過IParameterEscapeProcessor介面實作自訂的轉義邏輯;
- #預設實現為DefaultParameterEscapeProcessor;
範例程式碼一:
@Controller @RequestMapping("/demo") @ParameterEscape public class DemoController { @RequestMapping("/escape") public IView testEscape(@RequestParam String content, @ParameterEscape(skiped = true) @RequestParam String desc) { System.out.println("Content: " + content); System.out.println("Desc: " + desc); return View.nullView(); } } // 或者:(两段代码执行结果相同) @Controller @RequestMapping("/demo") public class DemoController { @RequestMapping("/escape") @ParameterEscape public IView testEscape(@RequestParam String content, @ParameterEscape(skiped = true) @RequestParam String desc) { System.out.println("Content: " + content); System.out.println("Desc: " + desc); return View.nullView(); } }
透過瀏覽器存取URL測試:
http://localhost:8080/demo/escape?content=<p>content$<br><script>alert("hello");</script></p>&desc=<script>alert("hello");</script>
執行結果:控制台輸出)
#Content: <p>content$<br><script>alert("hello");</script></p> Desc: <script>alert("hello");</script>
範例一說明:
- 由於控制器類別被宣告了@ParameterEscape註解,代表整個控制器類別中所有的請求參數都需要被轉義,因此參數content的內容被成功轉義;
- 由於參數desc宣告的@ParameterEscape註解中skiped值被設定為true,表示跳過上級設置,因此參數內容未被轉義;
範例程式碼二:
@Controller @RequestMapping("/demo") @ParameterEscape public class DemoController { @RequestMapping("/escape2") @ParameterEscape(skiped = true) public IView testEscape2(@RequestParam String content, @ParameterEscape @RequestParam String desc) { System.out.println("Content: " + content); System.out.println("Desc: " + desc); return View.nullView(); } }
透過瀏覽器存取URL測試:
#http://localhost:8080/demo/escape2?content=<p>content$<br><script>alert("hello");</script></p>&desc=<script>alert("hello");</script>
執行結果:(控制台輸出)
Content: <p>content$<br><script>alert("hello");</script></p> Desc: <script>alert("hello");</script>
範例二說明:
- 雖然控制器類別被宣告了@ParameterEscape註解,但控制器方法透過skiped設定跳過轉義,這表示被宣告的方法參數內容不進行轉義操作,因此參數content的內容未被轉義;
- 由於參數desc宣告了@ParameterEscape註解,表示該參數需要轉義,因此參數內容被成功轉義;
注意:當控制器類別和方法都宣告了@ParameterEscape註解時,則類別上宣告的註解將視為無效;
非單例控制器的特殊用法
單例控制器與非單例控制器的區別:
- 單例控制器類別在WebMVC模組初始化時就已經實例化;
- 非單例控制器類別則是在每次接收到請求時都會建立實例對象,請求結束後該實例對像被釋放;
基於上述描述,非單例控制器是可以透過類別成員來接收請求參數,範例程式碼如下:
#@Controller(singleton = false) @RequestMapping("/demo") public class DemoController { @RequestParam private String content; @RequestMapping("/sayHi") public IView sayHi(@RequestParam String name) { return View.textView("Hi, " + name + ", Content: " + content); } }
透過瀏覽器存取URL測試:
#http://localhost:8080/demo/sayHi?name=YMPer&content=Welcome!
此範例程式碼的執行結果:
Hi, YMPer, Content: Welcome!
注意:在單例模式下,WebMVC模組將忽略為控制器類別成員賦值,同時也建議在單例模式下不要使用成員變數做為參數,並發多線程環境下會發生意想不到的問題! !