當我們需要封裝從頁面傳遞到後臺的請求參數時,簡單的方式就是使用一個工具類幫我們封裝,省很多力氣,還不容易出錯。那接下來就簡單介紹下這個BeanUtils工具類的實現原理,順便重溫下Java內省機制。
BeanUtils的底層是使用java內省機制完成的,而內省的實現要依賴java 的反射機制
首先說明:爲什麼map中的value值的格式爲String[]數組類型,因爲表單中可能存在多選框,所以需要數組接收。
一:那麼首先使用java反射來完成請求參數的封裝
/**
* User模型類
*/
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 + "]";
}
}
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
/**
* 使用java反射機制來完成參數封裝
*/
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方法進行參數封裝
二:使用內省方式封裝參數
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;
/**
* 使用內省機制完成參數封裝
*
*/
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();
System.out.println(name);
// 反射執行方法
writeMethod.invoke(userModel, map.get(name)[0]);
}
}
System.out.println("----------------");
System.out.println(userModel);
}
}
簡單說明:
內省機制,要通過屬性描述器將類中的所有屬性獲取到,然後再進行比對,封裝參數具體實現:
1. 獲取屬性描述器對象
2. 通過屬性描述器對象獲取模型類中所有屬性
3. 獲取模型類中set()方法
4. 獲取表單標籤中name屬性的值
5. 進行比對,反射執行方法,封裝參數