日期:2014-05-20  浏览次数:21101 次

Play framework 2.0 -http表单提交和表单验证

?

#处理表单提交

?

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", "bob@gmail.com");
	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("bob@gmail.com", "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参数显示域的最少数目。

?

?

?

?