3.7捆绑和验证。
找到actionbean,又找到处理方法,接下应该是执行处理方法,等一等,仔细想一下,处理方法要处理什么东西,处理是要处理用户用表单传进来的数据。那么就是说先要把数据传进来,在structs中,采用formbean做为接受数据的bean。而stripes采用actionbean的属性做为接受数据。因为接收的数据都是有一定的相关性,比如:user.name,user.sex等。既然在业务层采用User等做为PO,那么能不能就直接传到User中去呢,如果这样就有一些问题,比如采用User作为actionbean的一个属性,那么如何把数据传到属性对象的属性中,每个属性都有可能是PO对象,但是如果PO类没有实例化,怎么办?用过structs人深有体会。就算你把数据传到PO对象去了,那么用户输入的nested的属性格式出错了怎么办,要验证。这个nested的属性验证也是很复杂的问题。格式正确了,因为用户输入的数据都是string,类型不统一,就得进行类型转换。类型转换还不能和验证分开,如果你把用户输入的string数据要验证大于100,你总不可能先在验证时转换成int,判断是否大于100,如果大于,ok,进行捆绑又进行转换。最好的办法是什么样的验证是类型转换之前,什么样的验证是在类型转换之后。
也就是说捆绑验证类型转换三者是分不开的。说明这一节是很难的。
Stripes最大的优点就是在这个方面。给我带来极大的方便。
3.7.1 bind(ActionBean, ActionBeanContext,boolean)
BindingAndValidation和其它的组件一样,都是采用拦截的形式合到stripes系统中去,BindingAndValidation所有的功能都集中在DefaultActionBeanPropertyBinder的ValidationErrors bind(ActionBean bean, ActionBeanContext context, boolean validate)函数中。
在这个函数共分成如下步骤:
(1)、获取所请求的actionbean的所有字段的验证信息,放在名为validationInfos的Map<String, ValidationMetadata>。
(2)、从ActionBeanContext中获取用户提交的所有数据。放在名为parameters的
Map<ParameterName, String[]>中。
(3)、验证那些必填(不能为空)的字段。validateRequiredFields(parameters, bean, fieldErrors)。
(4)、对于用户提交的每一个字段都进行:

1、判断字段对应的actionbean中属性的类型(比如string,int)等。
2、判断字段是否允许bind到对应的actionbean中属性中去。此能是1.5新增。
3、进行验证前的类型预转换。
4、类型转换。
5、把字段的值 bind 到actionbean中对应的属性中。
(5)、通过bindMissingValuesAsNull(bean, context)对没有bind的属性进行处理。
(6)doPostConversionValidations()进行验证后的转换。

函数如下:
public ValidationErrors bind(ActionBean bean, ActionBeanContext context, boolean validate) {

//获取该actionbean的ValidationErrors对象。
ValidationErrors fieldErrors = context.getValidationErrors();
//获取该actionbean的所有字段的验证信息
Map<String, ValidationMetadata> validationInfos = this.configuration .getValidationMetadataProvider().getValidationMetadata(bean.getClass());

// Take the ParameterMap and turn the keys into ParameterNames
//从request. ParameterMap取值并把Map中的键值放入ParameterNames
Map<ParameterName, String[]> parameters = getParameters(context);

// Run the required validation first to catch fields that weren't even submitted
//验证那些必填(不能为空)的字段
if (validate) {
validateRequiredFields(parameters, bean, fieldErrors);
}

// Converted values for all fields are accumulated in this map to //make post-conversion. validation go a little easier
Map<ParameterName, List<Object>> allConvertedFields = new TreeMap<ParameterName, List<Object>>();

// First we bind all the regular parameters
for (Map.Entry<ParameterName, String[]> entry : parameters.entrySet()) { List<Object> convertedValues = null;
ParameterName name = entry.getKey();
try {
// exact name of the param in the request
String pname = name.getName();
if (!StripesConstants.SPECIAL_URL_KEYS.contains(pname)
&& !fieldErrors.containsKey(pname)) {
log.trace("Running binding for property with name: ", name);

// Determine the target type
ValidationMetadata validationInfo = validationInfos.get(name.getStrippedName());
PropertyExpressionEvaluation eval;
try {
eval = new PropertyExpressionEvaluation(PropertyExpression
.getExpression(pname), bean);
}
catch (Exception e) {
if (pname.equals(context.getEventName())) continue;
else throw e;
}
Class<?> type = eval.getType();
Class<?> scalarType = eval.getScalarType();

// Check to see if binding into this expression is permitted
if (!isBindingAllowed(eval)) continue;
if (type == null&& (validationInfo == null || validationInfo.converter() == null)) {
if (!pname.equals(context.getEventName())) {
log.trace("Could not find type for property '", name.getName(),"' of '", bean.getClass().getSimpleName(),"' probably because it's not ", "a property of the bean. Skipping binding.");
} continue;
}
String[] values = entry.getValue();

// Do Validation and type conversion
List<ValidationError> errors = new ArrayList<ValidationError>();

// If the property should be ignored, skip to the next property
if (validationInfo != null && validationInfo.ignore()) {
continue; }

if (validate && validationInfo != null) {
doPreConversionValidations(name, values, validationInfo, errors);
}

// Only do type conversion if there aren't errors already
if (errors.isEmpty()) {
convertedValues = convert(bean, name, values, scalarType, validationInfo, errors);
allConvertedFields.put(name, convertedValues);
}

// If have errors, save them, otherwise bind the parameter to the form
if (errors.size() > 0) {
fieldErrors.addAll(name.getName(), errors);
}
else if (convertedValues.size() > 0) {
bindNonNullValue(bean, eval, convertedValues, type, scalarType);
}
else {
bindNullValue(bean, name.getName(), type);
}
}
}
catch (Exception e) {
handlePropertyBindingError(bean, name, convertedValues, e, fieldErrors);
}
}

// Null out any values that were in the form, but values were not supplied
bindMissingValuesAsNull(bean, context);
// Then we figure out if any files were uploaded and bind those too
StripesRequestWrapper request = StripesRequestWrapper.findStripesWrapper(context.getRequest());
if (request.isMultipart()) {
Enumeration<String> fileParameterNames = request.getFileParameterNames();

while (fileParameterNames.hasMoreElements()) {
String fileParameterName = fileParameterNames.nextElement();
FileBean fileBean = request.getFileParameterValue(fileParameterName);
log.trace("Attempting to bind file parameter with name [", fileParameterName, "] and value: ", fileBean);

if (fileBean != null) {
try { bind(bean, fileParameterName, fileBean); }
catch (Exception e) {
log.debug(e, "Could not bind file property with name [", fileParameterName, "] and value: ", fileBean);
}
}
}
}

// Run post-conversion validation after absolutely everything has //been bound and validated so that the expression validation can have //access to the full state of the bean
if (validate) {
doPostConversionValidations(bean, allConvertedFields, fieldErrors);
}
return fieldErrors;
}
评论
发表评论

您还没有登录,请登录后发表评论

jljlpch
搜索本博客
最近加入圈子
存档
最新评论