当我们需要封装从页面传递到后台的请求参数时,简单的方式就是使用一个工具类帮我们封装,省很多力气,还不容易出错。那接下来就简单介绍下这个BeanUtils工具类的实现原理,顺便重温下java内省机制。
BeanUtils的底层是使用java内省机制完成的,而内省的实现要依赖java 的反射机制
首先说明:为什么map中的value值的格式为String[]数组类型,因为表单中可能存在多选框,所以需要数组接收。
一:那么首先使用java反射来完成请求参数的封装
package com.wanghang.domain;
/**
* User模型类
*
* @author Hang.W
* @version 1.0, 2016-12-24 12:53:10
*/
public class UserModel {
private String username;
private String password;
public UserModel() {
}
public UserModel(String username, String password) {
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "UserModel [username=" + username + ", password=" + password
+ "]";
}
}
package com.wanghang.reflect;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import com.wanghang.domain.UserModel;
/**
* 使用java反射机制来完成参数封装
*
* @author Hang.W
* @version 1.0, 2016-12-24 12:42:04
*/
public class Reflect {
/**
* 通过反射注入参数
*
* @throws Exception
*/
@Test
public void reflect() throws Exception {
// 创建一个Map集合,封装(假设从页面传递的)参数
Map<String, String[]> map = new HashMap<String, String[]>();
map.put("username", new String[] {"张三"});
map.put("password", new String[] {"123"});
// 创建User模型类
UserModel userModel = new UserModel();
// 获取map中所有的key
Set<String> keys = map.keySet();
// 通过反射获取UserModel类中所有的方法(包括私有)
Method[] methods = userModel.getClass().getDeclaredMethods();
// 判断方法名是否和 "set" + 从页面表单获取name属性的值相同
for(String key : keys) {
// 从页面上获取的name属性的值加上"set"
String newKey = "set" + key;
for (Method method : methods) {
// 获取方法名
String name = method.getName();
// 判断
if(newKey.equalsIgnoreCase(name)) {
// 相同,反射执行方法 invoke("对象", "参数")
method.invoke(userModel, map.get(key)[0]);
}
}
}
System.out.println(userModel);
}
}
简单说明:
我们要封装从表单标签(例:用户名:<inputtype=”text” name=”username”>)传递的参数,那么我们就可以从表单中name属性作为切入点,使用反射机制,封装参数。
具体实现:
1. 首先获取表单标签name属性中的值,
2. 获取对象模型类中的所有方法
3. 进行比对,执行setXXX方法进行参数封装
二:使用内省方式封装参数
package com.wanghang.reflect;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.wanghang.domain.UserModel;
/**
* 使用内省机制完成参数封装
*
* @author Hang.W
* @version 1.0, 2016-12-24 14:32:30
*/
public class Introspect {
/**
* 通过内省封装参数
*
* @throws Exception
*/
@Test
public void introspect() throws Exception {
// 创建一个Map集合,封装(假设从页面传递的)参数
Map<String, String[]> map = new HashMap<String, String[]>();
map.put("username", new String[] {"张三"});
map.put("password", new String[] {"123"});
// 创建User模型类
UserModel userModel = new UserModel();
// 获取BeanInfo对象
BeanInfo beanInfo = Introspector.getBeanInfo(UserModel.class);
// 通过BeanInfo对象获取所有的属性描述器(说白了,就是获取所有的属性)
PropertyDescriptor[] propertyDescriptor = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor prop : propertyDescriptor) {
//System.out.println(prop);
// 通过属性描述器,获取写方法
Method writeMethod = prop.getWriteMethod();
if(writeMethod != null) {
// 获取所有属性的名字(与表单标签中填写的相同)
String name = prop.getName();
// 反射执行方法
writeMethod.invoke(userModel, map.get(name)[0]);
}
}
System.out.println(userModel);
}
}
简单说明:
内省机制,要通过属性描述器将类中的所有属性获取到,然后再进行比对,封装参数
具体实现:
1. 获取属性描述器对象
2. 通过属性描述器对象获取模型类中所有属性
3. 获取模型类中set()方法
4. 获取表单标签中name属性的值
5. 进行比对,反射执行方法,封装参数