控制器参数(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); } }
通过浏览器访问URL测试:
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模块将忽略为控制器类成员赋值,同时也建议在单例模式下不要使用成员变量做为参数,在并发多线程环境下会发生意想不到的问题!!