• 基于JavaBean编辑器读取peroperties文件


    引言

    最近在重读《精通Spring+4.x++企业应用开发实战》这本书,看到了有关JavaBean编辑器的部分,了解到PropertyEditor和BeanInfo的使用。不得不说,BeanInfo是一个很强大的东西,Java中的内省也与之有一点点小关联。

    JavaBean、PropertyEditor与BeanInfo

    JavaBean简单介绍

    JavaBean是一种Java写成的可重用组件,本质上还是一个Java类,但是与一般的Java类不同,JavaBean必须有一个无参的构造函数,其字段必须私有化,并提供set、get方法供外界使用。根据书中所介绍,Sun所制定的JavaBean规范很大程度山是为了IDE准备的--它让IDE能够以可视化的方式设置JavaBean的属性。

    PropertyEditor接口

    PropertyEditor是属性编辑器的接口,其作用是将一个String类型的值转换为JavaBean的属性。Java为PropertyEditor提供了一个默认的实现类PropertyEditorSupport。

    BeanInfo接口

    BeanInfo用于描述JavaBean哪些属性可以编辑及对应属性编辑器。Java为BeanInfo也提供了一个默认实现--SimpleBeanInfo。

    其他

    更多有关JavaBean以及这两个接口的知识,可以购买这本书《精通Spring+4.x++企业应用开发实战》,或者看我的Copy

    一个小例子

    在《精通Spring+4.x++企业应用开发实战》中使用的例子是根据《Core Java II》的一个例子改变而成,但是有一个小缺点,该例子使用到了Swing,演示时需要将代码打成JAR包,使用IDE组件扩展管理功能注册到IDE中,不太方便,因此我特意尝试用JavaBean编辑器读取properties文件作为一个小例子。

    定义一个JavaBean

    我们先定义一个Person类,用作JavaBean

    /**
     * 一个简单的JavaBean
     * @author aming
     *
     */
    public class Person implements Serializable {
     
    	private static final long serialVersionUID = 6366021085463785872L;
    
    	/**
    	 * 姓名
    	 */
    	private String name;
    	/**
    	 * 年龄
    	 */
    	private int age;
    	/**
    	 * 性别
    	 */
    	private Gender gender;
    	/**
    	 * 生日
    	 */
    	private Date birthday;
    	/**
    	 * 是否结婚
    	 */
    	private boolean married;
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public int getAge() {
    		return age;
    	}
    	public void setAge(int age) {
    		this.age = age;
    	}
    	public Gender getGender() {
    		return gender;
    	}
    	public void setGender(Gender gender) {
    		this.gender = gender;
    	}
    	public Date getBirthday() {
    		return birthday;
    	}
    	public void setBirthday(Date birthday) {
    		this.birthday = birthday;
    	}
    	public boolean isMarried() {
    		return married;
    	}
    	public void setMarried(boolean married) {
    		this.married = married;
    	}
    	
    	public Person() {
    		super();
    	}
    	
    	@Override
    	public String toString() {
    		return "Person [name=" + name + ", age=" + age + ", gender=" + gender + ", birthday=" + birthday + ", married="
    				+ married + "]";
    	}
    }
    

    其中Gender是我自定义的枚举,其代码如下:

    /**
     * 表示性别的枚举类
     * @author aming
     *
     */
    public enum Gender {
    	M(1,"男"),F(2,"女");
    	private int id;
    	private String genderName;
    	
    	public String getGenderName() {
    		return genderName;
    	}
    	
    	Gender(int id,String genderName){
    		this.id = id;
    		this.genderName = genderName;
    	}
    	
    	public static Gender getGender(int id) {
    		for(Gender gender:values()) {
    			if(gender.id == id) {
    				return gender;
    			}
    		}
    		return M;
    	}
    	
    	public static Gender getGender(String genderName) {
    		for(Gender gender:values()) {
    			if(gender.genderName == genderName) {
    				return gender;
    			}
    		}
    		return M;
    	}
    }
    

    实现PropertyEditor

    Person类中有5个字段,分别使用String、int、Gender、Date和boolean这5中类型,其中对String类型变量name我们使用PropertyEditorSupport这个默认实现就可以了,其他的类型我们需要自定义去实现PropertyEditor接口--int对应IntegerPropertyEditor、Gender对应GenderPropertyEditor、Date对应DatePropertyEditor以及boolean对应BooleanPropertyEditor。

    IntegerPropertyEditor

    IntegerPropertyEditor类继承了PropertyEditorSupport类和实现PropertyEditor接口(个人习惯实现接口的时候同时继承一个默认实现,这样我可以只关心我所需要实现的方法,当然,这个默认实现最好是一个抽象类),重写了getAsText()方法和setAsText(String text),其代码如下:

    @Override
    public String getAsText() {
    	return String.valueOf((int)getValue());
    }
    
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
    	try {
    		setValue(Integer.parseInt(text));
    	} catch(NumberFormatException e) {
    			throw new IllegalArgumentException(e);
    	}
    }
    

    GenderPropertyEditor

    GenderPropertyEditor主要是将外部获得到的字符串去转换为Gender,其实现思路是,先尝试将该字符串转换为Integer类型,如果转换成功则将转换得到Integer值通过Gender枚举的静态方法getGender(int id)获取Gender类型的变量;如果转换失败,则将该字符串看作genderName,再去获取Gender。至于Gender到字符串,直接返回genderName就可以了。主要代码如下:

    @Override
    public String getAsText() {
    	Gender value =  (Gender)getValue();
    	return value.getGenderName();
    }
    
    @Override
    public void setAsText(String value) throws IllegalArgumentException {
    	try {
    		setValue(Gender.getGender(Integer.valueOf(value)));
    	}catch(NumberFormatException ex) {
    		setValue(Gender.getGender(value));
    	}		
    }
    

    DatePropertyEditor

    DatePropertyEditor的思路和GenderPropertyEditor相似,其核心代码献上:

    private DateFormat df;
    	
    @Override
    public String getAsText() {
    	Date date = (Date)getValue();
    	return df.format(date);
    }
    
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
    	try {
    		setValue(df.parse(text));
    	} catch (ParseException e) {
    		throw new IllegalArgumentException(e);		
    	}
    }
    	
    public DatePropertyEditor() {
    	super();
    	this.df = new SimpleDateFormat("yyyy-MM-dd");
    }
    

    BooleanPropertyEditor

    BooleanPropertyEditor与IntegerPropertyEditor一样,实现非常类似:

    @Override
    public String getAsText() {
    	return String.valueOf((boolean)getValue());
    }
    
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
    	setValue(Boolean.valueOf(text));
    }
    

    自定义BeanInfo

    定义PersonBeanInfo类,用于描述Person属性和相对应的PropertyEditor。代码如下:

    public class PersonBeanInfo extends SimpleBeanInfo implements BeanInfo {
    
    	@Override
    	public PropertyDescriptor[] getPropertyDescriptors() {
    		List<PropertyDescriptor> list = new ArrayList<>();
    		try {
                // 将Person中name与PropertyEditorSupport绑定
    			PropertyDescriptor namePropertyDescriptor = new PropertyDescriptor("name",Person.class);
    			namePropertyDescriptor.setPropertyEditorClass(PropertyEditorSupport.class);
                // 将Person中age与IntegerPropertyEditor绑定
    			PropertyDescriptor agePropertyDescriptor = new PropertyDescriptor("age",Person.class);
    			agePropertyDescriptor.setPropertyEditorClass(IntegerPropertyEditor.class);
                // 将Person中gender与GenderPropertyEditor绑定
    			PropertyDescriptor genderPropertyDescriptor = new PropertyDescriptor("gender", Person.class);
    			genderPropertyDescriptor.setPropertyEditorClass(GenderPropertyEditor.class);
                // 将Person中birthday与DatePropertyEditor绑定
    			PropertyDescriptor birthdayPropertyDescriptor = new PropertyDescriptor("birthday",Person.class);
    			birthdayPropertyDescriptor.setPropertyEditorClass(DatePropertyEditor.class);
                // 将Person中married与BooleanPropertyEditor绑定
    			PropertyDescriptor marriedPropertyDescriptor = new PropertyDescriptor("married",Person.class);
    			marriedPropertyDescriptor.setPropertyEditorClass(BooleanPropertyEditor.class);
    			
    			list.add(namePropertyDescriptor);
    			list.add(agePropertyDescriptor);
    			list.add(genderPropertyDescriptor);
    			list.add(birthdayPropertyDescriptor);
    			list.add(marriedPropertyDescriptor);
    			
    			return list.toArray(new PropertyDescriptor[list.size()]);
    		} catch (IntrospectionException ex) {
    			ex.printStackTrace();
    		}
    		return null;
    	}
    }
    

    创建配置文件

    因为我创建的是一个普通的Java项目,因此我选择在src目录下创建person.properites文件,文件内容如下:

    name=arthurming
    age=18
    gender=1
    birthday=2017-10-24
    married=true
    

    测试

    测试代码

        @Test
    	public void test() throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
    		Properties p = new Properties();
    		InputStream is =this.getClass().getClassLoader().getResourceAsStream("person.properties");
    		p.load(is);
    		BeanInfo beanInfo = new PersonBeanInfo();
    		PropertyDescriptor[] propertyDescriptoies = beanInfo.getPropertyDescriptors();
    		Person person = new Person();
    		for(PropertyDescriptor propertyDescriptor : propertyDescriptoies) {
    			String key  = propertyDescriptor.getName();
    			String value = p.getProperty(key);
    			Method method = propertyDescriptor.getWriteMethod();
    			PropertyEditor pe = (PropertyEditor) propertyDescriptor.getPropertyEditorClass().newInstance();
    			if(pe.getClass() == PropertyEditorSupport.class) { //①
    				pe.setValue(value);
    			} else {
    				pe.setAsText(value);			
    			}
    			method.invoke(person,pe.getValue());
    		}
    		System.out.println(person);
    	}
    

    说明:代码①表示当pe类型是PropertyEditorSupport,而不是我所定义PropertyEdtior,应该使用setValue方法而不是setAsText方法。
    因为在PropertyEditorSupport中,其setAsText()方法为:

    public void setAsText(String text) throws java.lang.IllegalArgumentException {
        if (value instanceof String) {
            setValue(text);
            return;
        }
        throw new java.lang.IllegalArgumentException(text);
    }
    

    如果使用setAsText()方法,那么由于value不是String类型,将会抛出IllegalArgumentException。不过很遗憾我搞明白value到底实际上什么类型......

    测试结果

    Person [name=arthurming, age=18, gender=M, birthday=Tue Oct 24 00:00:00 CST 2017, married=true]
    

    小结

    感觉您能容忍我拙劣的文笔看到现在,也希望你在读《精通Spring+4.x++企业应用开发实战》这本书时,看到有关JavaBean编辑器的知识,我的这个例子可以对你有所帮助。

    补充

    1024,节日快乐

  • 相关阅读:
    C#序列化效率对比
    将聚合记录集逆时针和顺时针旋转90度(行列互换)
    Sql的行列转换
    log4net配置
    input框添加阴影效果
    WCF自定义地址路由映射(不用svc文件)
    Jquery对当前日期的操作(格式化当前日期)
    用JQuery获取输入框中的光标位置
    sublime text3安装后html:5+Tab不能快速生成html头部信息的解决办法
    js获取url传递参数,js获取url?号后面的参数
  • 原文地址:https://www.cnblogs.com/xiao2/p/7726239.html
Copyright © 2020-2023  润新知