YMP Online Manual /控制器参数(Parameter)

控制器参数(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设定是在控制器方法参数执行验证之前还是之后执行参数转义动作,参数取值范围为beforeafter,默认为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=

    content$

    &desc=

    执行结果:(控制台输出)

    Content: <p>content$<br><script>alert("hello");</script></p> Desc: 

    示例一说明:

    • 由于控制器类被声明了@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=

    content$

    &desc=

    执行结果:(控制台输出)

    Content: 

    content$

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