#處理表單提交
1.定義一個表單
play.data包下包含一些幫助處理Http表單數據提交和校驗的工具。最容易的處理表單提交的方式是定義一個play.data.Form來包裝現有的類:
- public class User {
- public String email;
- public String password;
- }
- Form<User> userForm = form(User.class);
注:底層數據綁定通過Spring的數據綁定實現。
這個表單可以生成一個User的結果值,值是HashMap<String,String>數據。
- Map<String,String> anyData = new HashMap();
- anyData.put("email", "[email protected]");
- anyData.put("password", "secret");
- User user = userForm.bind(anyData).get();
如果你在作用域中有可用的請求,你可以直接從請求內容中綁定:
- User user = userForm.bindFromRequest().get();
2.定義約束
你可以添加額外的約束,在使用JSR-303(Bean驗證)註解時將會在綁定的過程中檢測約束。
- public class User {
- @Required
- public String email;
- public String password;
- }
play.data.validation.Constraints類包含了若干內建的驗證註解。
你也可以通過在你的代碼中增加一個validate方法,自己定製一個驗證。
- public class User {
- @Required
- public String email;
- public String password;
- public String validate() {
- if(authenticate(email,password) == null) {
- return "Invalid email or password";
- }
- return null;
- }
- }
3.處理數據綁定錯誤
當然有驗證,就需要處理綁定時出現的錯誤。
- if(userForm.hasErrors()) {
- return badRequest(form.render(userForm));
- } else {
- User user = userForm.get();
- return ok("Got user " + user);
- }
4.初始化默認值填充表單
有時候你需要給表單填充默認值,典型的如:
- userForm.fill(new User("[email protected]", "secret"))
5.註冊用戶自定義數據綁定器
萬一你要爲一個自定義對象定義一個與表單域之間的映射關係,你就需要註冊一個新的格式化工具(Formatter )。
例如爲JodaTime的本地時間對象定義一個映射:
- Formatters.register(LocalTime.class, new Formatters.SimpleFormatter<LocalTime>() {
- private Pattern timePattern = Pattern.compile("([012]?\\\\d)(?:[\\\\s:\\\\._\\\\-]+([0-5]\\\\d))?");
- @Override
- public LocalTime parse(String input, Locale l) throws ParseException {
- Matcher m = timePattern.matcher(input);
- if (!m.find()) throw new ParseException("No valid Input",0);
- int hour = Integer.valueOf(m.group(1));
- int min = m.group(2) == null ? 0 : Integer.valueOf(m.group(2));
- return new LocalTime(hour, min);
- }
- @Override
- public String print(LocalTime localTime, Locale l) {
- return localTime.toString("HH:mm");
- }
- });
#使用表單模板幫助類(助手)
Play提供了若干幫助類幫助你渲染Html模板中的表單域。
1.創建<form>標籤
第一個幫助是創建<form>標籤。這是一個非常簡單的助手,它能根據你傳遞進來的檢索路徑自動的設置好action和method標籤參數。
- @helper.form(action = routes.Application.submit()) {
- }
也可以傳遞一組額外的參數,它會被加到生成的html中:
- @helper.form(action = routes.Application.submit(), 'id -> "myForm") {
- }
2.渲染一個input元素
views.html.helper包下有若干個input的助手,你給它們表單域,它們會展示相應的Html表單控件,有填充值,約束和錯誤信息。
- @(myForm: Form[User])
- @helper.form(action = routes.Application.submit()) {
- @helper.inputText(myForm("username"))
- @helper.inputPassword(myForm("password"))
- }
對於表單助手,你也可以指定額外的參數,它同樣會加到生成的Html中:
- @helper.inputText(myForm("username"), 'id -> "username", 'size -> 30)
注意:除了以下劃線"_"字符打頭的參數名稱外,所有額外的參數都會被加到生成的Html中。以下劃線打頭的名稱爲構造函數的參數域保留。
3.自己處理HTML input的創建
還有一個更通用的input輔助,讓您編寫想要的HTML結果:
- @helper.input(myForm("username")) { (id, name, value, args) =>
- <input type="date" name="@name" id="@id" @toHtmlArgs(args)>
- }
4.字段(或域)的構造
一個被渲染的字段不僅僅包含一個input標籤,它也需要<lable>和一大堆你的css框架裏用到的其他標籤來裝飾。
所有的input助手(輔助類)都隱含一個FieldConstructor ,用來處理這個問題。默認的構建器生成如下的html代碼:
- <dl class="error" id="username_field">
- <dt><label for="username"><label>Username:</label></dt>
- <dd><input type="text" name="username" id="username" value=""></dd>
- <dd class="error">This field is required!</dd>
- <dd class="error">Another error</dd>
- <dd class="info">Required</dd>
- <dd class="info">Another constraint</dd>
- </dl>
這個默認的域構造器支持額外的選項,你可以給input助手傳遞參數。
- '_label -> "Custom label"
- '_id -> "idForTheTopDlElement"
- '_help -> "Custom help"
- '_showConstraints -> false
- '_error -> "Force an error"
- '_showErrors -> false
4.Twitter bootstrap域構建
還有另外一個內建的字段構造器並用在Twitter Bootstrap上。
(引用:Bootstrap是一套用於開發網頁應用,符合HTML和CSS簡潔但優美規範的庫。Bootstrap由動態CSS語言Less寫成,在很多方面類似CSS框架Blueprint。經過編譯後,Bootstrap就是衆多CSS的合集。想要了解Bootstrap的細節,開發者請參考Twitter的官方指南和演示示例。)
要使用它只需要把它引入到當前作用域:
- @import helper.twitterBootstrap._
它會生成類似這樣的html代碼:
- div class="clearfix error" id="username_field">
- <label for="username">Username:</label>
- <div class="input">
- <input type="text" name="username" id="username" value="">
- <span class="help-inline">This field is required!, Another error</span>
- <span class="help-block">Required, Another constraint</d</span>
- </div>
- </div>
這個構造器和默認的構造器一樣有相同的選項設置。
5.寫自己的域構造器
你經常需要寫自己的域構造器,以這個例子作爲開始吧:
- @(elements: helper.FieldElements)
- <div class="@if(elements.hasErrors) {error}">
- <label for="@elements.id">@elements.label</label>
- <div class="input">
- @elements.input
- <span class="errors">@elements.errors.mkString(", ")</span>
- <span class="help">@elements.infos.mkString(", ")</span>
- </div>
- </div>
注:這僅僅是個示例。你可以寫的更加複雜。也可以通過使用 @elements.field訪問原始域。
前面的域構造器可以這樣使用:
- @implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
- @inputText(myForm("username"))
6.處理重複值
最後一個輔助類可以使得爲重複值生成input變的容易。假如你有這樣的表單定義。
- val myForm = Form(
- tuple(
- "name" -> text,
- "emails" -> list(email)
- )
- )
現在表單能包含多少email域你就的生成多少input。那麼你可以使用repeat輔助完成:
- @inputText(myForm("name"))
- @repeat(myForm("emails"), min = 1) { emailField =>
- @inputText(emailField)
- }
即使相應表單數據是空,也可以使用min參數顯示域的最少數目。