【JavaEE】Java內省Introspector、PropertyDescriptor與JavaBean

Windsor90發表於2017-02-06

1.Java內省概念

Sun公司開發了一套API,專門用於操作Java物件的屬性。【Introspector】
在開發框架時,需要使用Java物件的屬性來封裝程式的資料,使用反射技術完成此類操作過於麻煩,我們使用內省。
內省(Introspector) 是Java 語言對 JavaBean 類屬性、事件的一種預設處理方法。

JavaBean是一種特殊的類,主要用於傳遞資料資訊,這種類中的方法主要用於訪問私有的欄位,且方法名符合某種命名規則。
如果在兩個模組之間傳遞資訊,可以將資訊封裝進JavaBean中,這種物件稱為”值物件”(Value Object),或”VO”。
方法比較少。這些資訊儲存在類的私有變數中,通過set()、get()獲得。
在Student中有屬性name, age, birthday。我們可以通過getName, setName來訪問name屬性,這就是預設的規則。
Java JDK中提供了一套 API 用來訪問某個屬性的 getter/setter 方法,這就是內省。
PropertyDescriptor類:
PropertyDescriptor類表示JavaBean類通過儲存器匯出一個屬性。主要方法:
1. getReadMethod(),獲得用於讀取屬性值的方法;
2. getWriteMethod(),獲得用於寫入屬性值的方法;
3. setReadMethod(Method readMethod),設定用於讀取屬性值的方法;
4. setWriteMethod(Method writeMethod),設定用於寫入屬性值的方法。

通過PropertyDescriptor與Introspector的比較可以看出,都是需要獲得PropertyDescriptor,只是方式不一樣:
PropertyDescriptor通過建立物件直接獲得,Introspector需要遍歷,
所以使用PropertyDescriptor類更加方便。

Introspector類,將JavaBean中的屬性封裝起來進行操作。
1.在程式中把一個類當做JavaBean來看,呼叫Introspector.getBeanInfo()方法,
得到的BeanInfo物件封裝了這個類的屬性資訊。
2.通過BeanInfo來獲取屬性的屬性描述器PropertyDescriptor 。

3.通過PropertyDescriptor獲取某個屬性對應的getter/setter方法,
然後通過反射機制來呼叫這些方法。

BeanInfo bi = Introspector.getBeanInfo(Student.class); 
PropertyDescriptor [] pds = bi.getPropertyDescriptors();

BeanUtils工具包
內省操作非常的繁瑣,所以所以Apache開發了一套簡單、易用的API來操作Bean的屬性,BeanUtils工具包。
beanutils內省框架(依賴commons-logging):apache
準備包:commons-beanutils.jar, commons-logging.jar
BeanUtils工具包:
下載:commons-beanutils.jar http://commons.apache.org/beanutils/ 
commons-logging.jar http://commons.apache.org/logging/

1.獲得屬性的值,例如,BeanUtils.getProperty(stu,”stuName”),返回字串
2.設定屬性的值,例如,BeanUtils.setProperty(stu,”age”,38),引數是字串或基本型別自動包裝。
設定屬性的值是字串,獲得的值也是字串,不是基本型別。   
3.BeanUtils的特點:
①對基本資料型別的屬性的操作:String<—–>基本型別 在WEB開發、使用中,錄入和顯示時,值會被轉換成字串,但底層運算用的是基本型別,這些型別轉到動作由BeanUtils自動完成。
②非基本型別的屬性的操作:String<—-> 其他型別
例如:

    public void test5 () throws Exception{
        Student s = new Student ();
        //給BeanUtils註冊轉換器,
        ConvertUtils.register(new Converter (){
            //type是目標型別, value是當前傳入的值
        public Object convert(Class type,  Object value) {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                  //字串轉換為Date
                  String v= (String) value;
                  try{
                    Date d = df.parse(v);
                    return d;
                  }catch (ParseException e){
                    throw new RuntimeException (e);
                  }
                 }
                }, Date.class);
        BeanUtils.setProperty(s, "birthday", "1990-08-25");
        System.out.println(s.getBirthday());        
    }
    /**
     * 給BeanUtils註冊轉換器,引數:converter 要註冊的轉換器
     * clazz 此轉換器執行的轉換的目標類
     */ 
public static void register(Converter converter, Class clazz);  
public interface Converter {
      /*
       *將特定輸入轉換成特定的輸出型別
       *引數:type   目標轉換型別,value  待轉換的輸入值  
       *返回值: 轉換的結果
       */  
    public Object convert(Class type, Object value);
}   

2. Java內省例項

JavaBean

package cn.edu;
import java.util.Date;
public class Student {
    private String stuName; 
    private int age;
    private Date birthday;
    public String getStuName() {
        return stuName;
    }
    public void setStuName(String stuName) {
        this.stuName = stuName;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    @Override
    public String toString() {
        return "Student [stuName=" + stuName + ", age=" + age + ", birthday="
                + birthday + "]";
    }
}
package cn.edu;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;

public class BeanInfoUtil {
    public static void main(String[] args) throws  Exception {
        Student stu = new Student();
        BeanInfoUtil.setProperty(stu, "stuName","Tom");
        BeanInfoUtil.getProperty(stu, "stuName");
        setPropertyByIntrospector(stu, "stuName","Ben");
        getPropertyByIntrospector(stu, "stuName");
        /*
         * 3.BeanUtils工具包操作JavaBean
         * */
        BeanUtils.setProperty(stu, "stuName", "Green");
        BeanUtils.setProperty(stu, "age", 18);
        System.out.println("get stuName:"+BeanUtils.getProperty(stu, "stuName"));
        System.out.println("get age:"+BeanUtils.getProperty(stu, "age"));    

        convertUtilsGetBirthday(stu, "1990-08-25");
        convertUtilsGetBirthday2(stu, "1993-08-25");        
    }   
    /** 
     *  1.直接通過 PropertyDescriptor類的操作Bean屬性
     * */   
    public static void setProperty(Student stu, String stuName, String value) throws Exception, IllegalArgumentException, InvocationTargetException{
         //1.獲取stuName屬性
         PropertyDescriptor propDesc=new PropertyDescriptor(stuName,Student.class);
         //2.得到setStuName()方法
         Method methodSetStuName=propDesc.getWriteMethod();
         //3.呼叫setStuName()方法
         methodSetStuName.invoke(stu, value);  
         System.out.println("set name:"+stu.getStuName());              
    }
    public static void getProperty(Student stu, String stuName) throws Exception{   
        PropertyDescriptor proDescriptor =new PropertyDescriptor(stuName,Student.class);
        Method methodGetStuName=proDescriptor.getReadMethod();
        Object objStuName=methodGetStuName.invoke(stu);
        System.out.println("get name:"+objStuName.toString());              
    }   
    /**
     *  2.通過Introspector類獲取BeanInfo物件,再通過BeanInfo獲取PropertyDescriptor,操作Bean屬性 
     * */   
     public static void setPropertyByIntrospector(Student stu,String stuName, String value)throws Exception{
            //1.獲取BeanInfo物件
            BeanInfo beanInfo=Introspector.getBeanInfo(Student.class);
            //2.通過BeanInfo物件獲取PropertyDescriptor
            PropertyDescriptor[] proDescrtptors=beanInfo.getPropertyDescriptors();
            //3.遍歷
            if(proDescrtptors !=null && proDescrtptors.length > 0){
                for(PropertyDescriptor propDesc : proDescrtptors){
                    if(propDesc.getName().equals(stuName)){              
                        Method methodSetUserName=propDesc.getWriteMethod();
                        methodSetUserName.invoke(stu, value);
                        System.out.println("set stuName:"+stu.getStuName());
                        break;
                    }
                }
            }
        }       
        public static void getPropertyByIntrospector(Student stu,String stuName)throws Exception{       
            BeanInfo beanInfo=Introspector.getBeanInfo(Student.class);
            PropertyDescriptor[] proDescrtptors=beanInfo.getPropertyDescriptors();        
            if(proDescrtptors !=null && proDescrtptors.length > 0){
                for(PropertyDescriptor propDesc : proDescrtptors){              
                    if(propDesc.getName().equals(stuName)){                 
                        Method methodStuUserName=propDesc.getReadMethod();
                        Object objStuName=methodStuUserName.invoke(stu);
                        System.out.println("get StuName:"+objStuName.toString());
                        break;
                    }
                }
            }
        }    
        /**
         *   給BeanUtils註冊時間日期轉換器 
         * */    
        public static void convertUtilsGetBirthday(Student stu, String date) throws Exception{          
            //給BeanUtils註冊轉換器, type是目標型別, value是當前傳入的值
            ConvertUtils.register(new Converter (){
              public Object convert(Class type, Object value) {
                  DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                  //字串轉換為Date
                  String v= (String) value;
                  try{
                    Date d = df.parse(v);
                    return d;
                  }catch (ParseException e){
                    throw new RuntimeException (e);
                  }
                 }
                }, Date.class);
            BeanUtils.setProperty(stu, "birthday", date);
            System.out.println(stu.getBirthday());          
        }   
        /**
         *   給BeanUtils註冊時間日期轉換器 
         * */
        public static void convertUtilsGetBirthday2(Student stu, String date) throws Exception{

            ConvertUtils.register(new DateLocaleConverter(), Date.class);   
            BeanUtils.setProperty(stu, "birthday", date);
            System.out.println(stu.getBirthday());              
        }       

}
/*
    set name:Tom
    get name:Tom
    set stuName:Ben
    get StuName:Ben
    get stuName:Green
    get age:18
    Sat Aug 25 00:00:00 CDT 1990
    Wed Aug 25 00:00:00 CST 1993
 * */

3.Java封裝客戶端請求引數至JavaBean

JavaBean
public class User {
    private String username;
    private String password[];
    private String gender;
    public String getUsername() {//讀屬性,屬性名稱username
        return username;
    }
    public void setUsername(String username) {//寫屬性,屬性名username
        this.username = username;
    }

    public String[] getPassword() {
        return password;
    }
    public void setPassword(String[] password) {
        this.password = password;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    @Override
    public String toString() {
        return "User [username=" + username + ", password="
                + Arrays.toString(password) + ", gender=" + gender + "]";
    }

}

封裝請求引數的幾種方案:

    /*1.使用Java內省,將請求引數的值封裝到JavaBean中。
      約定優於編碼:表單的輸入域的name取值和JavaBean中的屬性(getter和setter方法)保持一致
    */
    private void test1(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {  
        Enumeration<String> e = request.getParameterNames();//引數名
        User user = new User();
        while(e.hasMoreElements()){
            String paramName = e.nextElement();//即是JavaBean中的屬性名稱
            String paramValue = request.getParameter(paramName);
            //JavaBean的內省
            try {
                PropertyDescriptor pd = new PropertyDescriptor(paramName, User.class);
                Method m = pd.getWriteMethod();//setter方法
                m.invoke(user, paramValue);
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
    }       
    /*2.getParameterMap獲取引數*/
    private void test6(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //key:請求引數名 value:請求引數值陣列
        Map<String,String[]> map = request.getParameterMap();
        for(Map.Entry<String, String[]> me:map.entrySet()){
            System.out.println(me.getKey()+"="+Arrays.asList(me.getValue()));
        }
    }   

    /*
     3.getParameterMap獲取引數結合Java 內省,封裝到JavaBean中
    */
    private void test2(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //key:請求引數名 value:請求引數值陣列
        Map<String,String[]> map = request.getParameterMap();
        User user = new User();
        for(Map.Entry<String, String[]> me:map.entrySet()){
            String paramName = me.getKey();//引數名稱
            String paramValues[] = me.getValue();//引數值
            try {
                PropertyDescriptor pd = new PropertyDescriptor(paramName, User.class);
                Method m = pd.getWriteMethod();//setter方法
                if(paramValues.length > 1){
                    m.invoke(user, (Object)paramValues);
                }else{
                    m.invoke(user, paramValues);
                }
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
    }   
    /*3.藉助第三方工具包:藉助BeanUtil框架*/
    private void test8(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        User user = new User();
        try {
            BeanUtils.populate(user, request.getParameterMap());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

相關文章