控制器參數(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=<p>content$<br><script>alert("hello");</script></p>&desc=<script>alert("hello");</script>

    執行結果:控制台輸出)

    #
    Content: <p>content$<br><script>alert(&quot;hello&quot;);</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(&quot;hello&quot;);</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模組將忽略為控制器類別成員賦值,同時也建議在單例模式下不要使用成員變數做為參數,並發多線程環境下會發生意想不到的問題! !

#