我们都知道,作为一个与用户交互的系统,都存在找数据的交互。然后,由于用户输入的数据都是千变万化的,有时可能不是系统所期望的数据,比如用户输入非数字类型等。即使我们认为所有用户输入的数据都是正确的,但是我们还是需要验证用户输入的值。
在Erlang-Web中,验证用户输入数据的基本类型是通过wpart_valid模块来实现的,它收集用户的输入数据,并对数据的基本类型进行验证,比如判断一个数据是否是整数类型,或者是否是一个主键等。在Erlang-Web中,验证器是怎么知道这个值的基本类型的呢?在这里,我们可以定义一个自定义的复合类型的记录来申明。
首先,我们定义一个是与表结构相同的记录,另外一个是与之对应的记录类型,它描述了各个字段的值类型等。
-record(link,{id,title,uri,text}).
-record(link_types,
{
id = {integer, [{description, "Link ID"},{private, true},{primary_key}]},
title = {string, [{description, "Title"},{min_length, 1}]},
uri = {string, [{description, "URI http://"},{min_length, 1}]},
text = {text, [{description, "Description"},{max_length, 255},{rows, 5},{cols, 40}]}
}
).
保存这个记录到link.hrl,然后定义与此记录对应的一个wtype文件:
-module (wtype_link).
-export([validate/1, get_record_info/1]).
-include("link.hrl").
get_record_info(link_types) -> #link_types{}
get_record_info(link) -> record_info(fields, link).
validate(From) ->
SuperField = get_record_info(link),
SuperType = get_record_info(link_types),
wpart_valid:validate(SuperField, SuperType, From ++ ["link"]).
这个文件的主要作用一是生成一个html页面,二是当用户提交数据时,对用户提交的数据根据link_types来进行验证,不如是否是Int类型,text的值最大长度是否超过255等。其中最后"wpart_valid:validate(SuperField, SuperType, From ++ ["link"])"中的"link"是为了创建一个默认的唯一名称,它代表一个用户自定义的类型,然后用通用工具重新创建它们。函数get_record_info/1的作用是用来保存动态变化类型的,在我们这个例子中,用根据link、link_types,结合起来保存link的各个字段的类型。
下面,我们看看Erlang-Web的验证工具是怎么来验证一个int类型的,首先,我们新建一个wtype,命名为wtype_integer,并且导出validate/1函数:
-module (wtype_integer).
-export([validate/1]).
validate({Types,Input}) ->
case wpart_valid:is_private(Types) of
true ->
{ok, Input};
false ->
case catch list_to_integer(Input) of
Int when is_integer(Int) ->
case check_min(Int, Types) of
{ok, Int} ->
case check_max(Int, Types) of
{ok, Int} -> {ok, Int};
ErrorMax -> ErrorMax
end;
ErrorMin -> ErrorMin
end;
_ -> {error, {not_integer, Input}}
end
end.
函数的参数被传递进来,并且进行验证。它们始终都是一个元组{Types,Input},Types是从记录link_types中重写的,Input是用户输入的值,它们是与link_types记录中的字段一一对应的。在记录link_types中,我们看到id被定义为private,说明这个字段在页面上是不可见并且不会被用户编辑的。
上面我们自己编写了一个验证int类型的函数,现在我们看看在控制器中是怎么来验证的。在控制器中,我们不需要像上面那样,自己对用户的输入写函数进行验证,我们可以在dataflow中编写一个验证函数,利用Erlang-Web自带的验证工具来验证用户的输入,下面是代码片段:
dataflow(create) -> [authenticate, validate, validate_logic];
validate(create,_) ->
validate_tool:validate_cu(link, create);
error(create, not_valid) ->
Err = wpart:fget("__error"),
Message = "ERROR: Incomplete input or wrong type in form!" ++
" Reason: " ++ Err,
wpart:fset("error_message",Message),
Not_validated = wtype_link:prepare_initial(),
wpart:fset("__edit", Not_validated),
{template, "templates/link/add_link.html"};
利用dataflow,我们可以很容易的自己创建一个验证器validate,它利用了Erlang-Web的框架工具去调用并且分析来自wpart_valid的响应。只要在验证过程中出现了错误,dataflow将会确保error/2函数被调用,error函数将构建错误信息并且把错误信息用红色标记显示到页面上。下面是完整的代码:
link.hrl
-record(link,{id,title,uri,text}).
-record(link_types,
{
id = {integer, [{description, "Link ID"},{private, true},{primary_key}]},
title = {string, [{description, "Title"},{min_length, 1}]},
uri = {string, [{description, "URI http://"},{min_length, 1}]},
description = {text, [{optional,"Description"},{description, "Description"},{max_length, 10000}]}
}).
wtype_link.erl
-module(wtype_link).
-export([validate/1,get_record_info/1]).
-include("link.hrl").
get_record_info(link_types) -> #link_types{};
get_record_info(link) -> record_info(fields,link).
validate(Form) ->
SuperField = get_record_info(link),
SuperType = get_record_info(link_types),
wpart_valid:validate(SuperField,SuperType,Form ++ ["link"]).
控制器linkAdmin.erl
-module(linkAdmin).
-export([dataflow/1,error/2,validate/2]).
-export([add/1]).
-include("link.hrl").
dataflow(add) -> [validate].
validate(add,_) ->
validate_tool:validate_cu(link, add).
error(add, not_valid) ->
Link = wpart:fget("__not_validated"),
wpart:fset("__edit", wpart_db:build_record_structure(link, Link)),
{template, "add_link.html"}.
add(Args) ->
{template, "success.html"}.
add_link.html
<html>
<head>
<title>Erlang Web Example Page</title>
</head>
<body>
<center>
<wpart:form type="link" action="/create_link"/>
</center>
</body>
</html>
dispatch.conf
{static, "^/add_link$", "add_link.html"}.
{dynamic, "^/create_link$", {linkAdmin, add}}.
运行效果图: