JavaBean组件

在软件开发时,一些数据和功能需要在很多地方使用,为了方便将他们进行“移植”,Sun公司提出一种JavaBean技术,使用JavaBean可以对这些数据和功能进行封装,做到“一次编写,到处运行”。本章将针对JavaBean、发射、内省、JSP标签访问JavaBean及BeanUtils工具。

初始JavaBean

什么是JavaBean
JavaBean是Java开发语言中一个可以重复使用的软件组件,它本质就是一个Java类,为了规范JavaBean的规范,Sun公司发布了JavaBean的规范,它要求一个标准的JavaBean组件需要遵循一定的编码规范,
1、他必须具有一个公共的无参的构造方法,这个方法可以编译器自动产生的默认构造方法。
2、它提供公共的setter方法和getter方法让外部程序设置和获取JavaBean的属性。
例:Book.java

package JavaBean;

public class Book {
	private double price;
	public double getPrice(){
		return price;
	}
	public void setPrice(double price){
		this.price=price;
	}
}

访问JavaBean的属性
在讲解面向对象时,经常会使用类的属性,类的属性指的是类的成员变量。在JavaBean中同样也有属性,但是他和成员变量不是一个概念,它是以方法的形式出现的,这些方法必须遵循一定的命名规范,例如,在JavaBean中包含一个String类型的属性name,那么在JavaBean中必须至少包含getName()和setName()方法中的一个,这两个方法的声明如下所示:

public String getName();
public void setName(String name);

1、getName()方法:称为getter方法或者属性访问器,该方法以小写的get前缀开始,后跟属性名,属性名的第一个字母要大写。
2、setName()方法:称为setter方法或者属性修改器,该方法必须以小写set前缀开始,后跟属性名,属性名的第一个字母要大写。
如果一个属性只有getter方法,则该属性为只读属性,如果一个属性只有setter方法,则该属性为只读属性,如果一个属性既有getter方法,又有setter方法,则该属性为读写属性。通常来说,在开发时,其属性都定义为读写属性。
需要注意的是,对于JavaBean属性的命名方式有一个例外情况,如果属性的类型为boolean,他的命名方式应该使用is/get而不是set/get。例如,有一个boolean类型的属性married,该属性所对应的方法:

public boolean isMarried();
public void setMarried(boolean married);

setter方法命名方式没有变化,而getter方法变成了isMarried。

反射

在Java中反射式极其重要的知识,在后期接触的大量框架的底层都运用了发射技术,因此掌握反射技术将帮助我们更好地理解这些框架地底层原理,以便灵活地掌握框架地使用。
认识Class类
Java反射地源头是class类,若想完成反射操作,首先必须认识Class类。一般情况下,需要现有一个类地完整路径引入之后,才可以按照固定地格式产生实例化对象,但是在Java中允许通过一个实例化对象找到一个类的完整信息,这就是Class类的功能。
GetClassNameDemo.java

package JavaBean;
class X{}
public class GetClassNameDemo {
	public static void main(String[] args){
		X x=new X();
		System.out.println(x.getClass().getName());
	}
}

javaswing组件介绍 java 组件_实例化


可以看到命令行输出了完整的包名。

例中,对象引用x调用了getClass()方法,该方法是从Object类中继承而来的。

public final Class<?>getClass()

从上述定义可以看出,该方法返回值的类型是Class类。这是因为Java中Object类是所有类的父类,所以,任何类的对象都可以通过调用getClass()方法转变为Class类型来表示。需要注意的是,在定义Class类时使用了泛型声明,若想避免程序出现警告信息,可以在泛型中指定操作的具体类型。
Class类表示一个类的本身,通过Class可以完整地得到一个类中的结构,包括此类中的方法定义、属性定义等。

方法声明

功能描述

static Class<?>forName(String className)

返回与带有给定字符串名的类或接口相关联的Class对象

Constructor<?>[]getConstructors()

返回一个包含某些Constructor对象的数组,这些对象反映此Class对象所表示类的所有公共构造方法

Field[] getDeclaredField(String name)

返回包括某些Field对象的数组,这些对象反映此Class对象所表示的类或接口所声明的所有字段。包括公共、保护、默认访问和私有字段,但不包括继承的字段

Field[] getFields()

返回一个包含某些Fields对象的数组,这些对象反映此Class对象所表示的类或接口的所有可访问公共字段,包括继承的公共字段

Method[] getMethods()

返回一个包含某些Method对象的数组,这些对象反映此Class对象所表示的类或接口的公共成员方法。

Method[] getMethod(String name,Class<?>…parameterTypes)

返回一个Method对象,反映此Class对象所表示的类或接口的指定公共成员方法

Class<?>[]getInterfaces()

返回该类所实现的接口的一个数组。确定此对象所表示的类或接口实现的接口

String getName()

以String的形式返回此Class对象所表示的实体名称

Package getPackage()

获取此类的包

Class <?super T> getSuperclass()

返回此Class所表示的实体的超类的Class

T newInstancs()

创建此Class对象所表示类的一个新实例

boolean isArray()

判定此Class对象是否表示一个数组类

在Class类中本身没有定义非私有的构造方法,因此不能通过new直接创建Class类的实例。
1、通过“对象.getClass()”方法获取该对象的Class实例。
2、通过Class类的静态方法forName(),用类的全路径名获取一个Class实例
3、通过"类名.class"的方式来获取Class实例,对于基本数据类型的封装类,还可以采用,TYPE来获取相对应的基本数据类型的Class实例。
需要注意的是,通过Class类的forName()方法相比其他两种方法更灵活,其他两种方法都需要明确一个类,如果一个类操作不确定时,使用起来可能会受一些限制。但是forName()方法只需以字符串的方式传入即可。

通过反射创建对象

当使用构造方法创建对象时,构造方法可以是有参的也可以是无参的。同样,通过反射创建对象的方式也有两种,就是调用有参和无参的构造方法。
1、通过无参构造方法实例化对象
如果想通过Class类本身实例化其他对象就可以使用newInstance()方法,但是必须要保证被实例化的类中存在一个无参构造方法。
ReflectDemo01.java

package JavaBean;

class Person{
	private String name;
	private int age;
	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 String toString(){
		return "姓名:"+this.name+" 年龄:"+this.age;
	}
}

public class ReflectDemo01 {
	public static void main(String[] args)throws Exception{
		Class clazz=Class.forName("JavaBean.Person");
		Person p=(Person)clazz.newInstance();
		p.setName("李芳");
		p.setAge(18);
		System.out.println(p);
	}
}

javaswing组件介绍 java 组件_构造方法_02

2、通过有参构造方法实例化对象
当通过有参构造方法实例化对象时,需要分为三个步骤完成
1、通过Class类的getConstructors()方法取得本类中的全部构造方法。
2、向构造方法中传递一个对象数组进去,里面包含构造方法中所需的各个参数。
3、通过Constructor类实例化对象。
需要注意的是,Constructor类表示的是构造方法,该类有很多常用的方法

方法声明

功能描述

int getModifiers()

获取构造方法的修饰符

String getName()

获取构造方法的名称

Class<?>[]getParameterTypes()

获取构造方法中参数的类型

T newInstance(Object…initargs)

向构造方法中传递参数,实例化对象

ReflectDemo01.java

package JavaBean;

import java.lang.reflect.Constructor;

class Person{
	private String name;
	private int age;
	public Person(String name,int age){
		this.name=name;
		this.age=age;
	}
	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 String toString(){
		return "姓名:"+this.name+" 年龄:"+this.age;
	}
}

public class ReflectDemo01 {
	public static void main(String[] args)throws Exception{
		Class clazz=Class.forName("JavaBean.Person");
		Constructor cons[]=clazz.getConstructors();
		Person p=(Person)cons[0].newInstance("李芳",30);
		System.out.println(p);
	}
}

javaswing组件介绍 java 组件_构造方法_03


通过反射访问属性

通过反射不仅可以创建对象,还可以访问属性。在反射机制中,属性的操作是通过Filed类实现的,它提供的set()和get()方法分别用于设置和获取属性。需要注意的是,如果访问的属性是私有的,则需要在使用set()或get()方法前,使用Firld类中的setAccessible()方法将需要操作的属性设置成可以被外界访问的。

ReflectDemo01.java

package JavaBean;

import java.lang.reflect.Field;

class Person{
	private String name;
	private int age;
	public String toString(){
		return "姓名:"+this.name+" 年龄:"+this.age;
	}
}

public class ReflectDemo01 {
	public static void main(String[] args)throws Exception{
		Class clazz=Class.forName("JavaBean.Person");
		Object p=clazz.newInstance();
		Field nameField=clazz.getDeclaredField("name");
		nameField.setAccessible(true);
		nameField.set(p, "李四");
		Field ageField=clazz.getDeclaredField("age");
		ageField.setAccessible(true);
		ageField.set(p, 20);
		System.out.println(p);
	}
}

javaswing组件介绍 java 组件_javaswing组件介绍_04


通过反射调用方法

当获得某个类对应的Class对象后,就可以通过Class对象的getMethods()方法或getMethod()方法获取全部方法或者指定方法,getMethod()方法和getMethods()这两个方法的返回值,分别是Method对象和Method对象数组。每个Method对象都对应一个方法,程序可以通过获取Method对象来调用对应的方法。在Method里包含一个invoke()方法

public Object invoke(Object obj,Object...args)

在上述方法定义中,参数obj是该方法最主要的参数,他后面的参数args是一个相当于数组的可变参数,用来接收传入的实参。
ReflectDemo01.java

package JavaBean;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

class Person{
	private String name;
	private int age;
	public String sayHello(String name,int age){
		return "大家好,我是"+name+",今年"+age+"岁!";
	}
}

public class ReflectDemo01 {
	public static void main(String[] args)throws Exception{
		Class clazz=Class.forName("JavaBean.Person");
		Method md=clazz.getMethod("sayHello", String.class,int.class);
		String result=(String)md.invoke(clazz.newInstance(), "张三",35);
		System.out.println(result);
	}
}

javaswing组件介绍 java 组件_实例化_05


getMethod()方法用于返回sayHello()方法所对应的Method()对象,由于sayHello()方法本身要接受两个参数,因此在使用Class实例的getMethod()方法时,除了要指定方法名称外,也需要指定方法的参数类型。通过Method对象的invoke()方法实现sayHello()方法的调用,并接收sayHello()方法所传入的实参。

内省

JDK中提供了一套API专门用于操作Java对象的属性,它比反射技术操作更加简便,这就是内省。
什么是内省
内省是Java语言对JavaBean类属性、事件和方法的一种标准处理方式,它的出现有利于操作对象属性,并且可以有效的减少代码量
内省访问JavaBean有两种方法
1、先通过java.beans包下的Introspector类获得JavaBean对象的BeanInfo信息,再通过BeanInfo来获取属性的描述器,然后通过这个属性描述器就可以获取某一属性对应的getter和setter方法,最后通过反射机制来调用这些方法。
2、直接通过java.beans包下的PropertyDescriptor类来操作Bean对象。

Person.java

package JavaBean;

public class Person{
	private String name;
	private int age;
	
	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 String toString(){
		return "姓名:"+this.name+",年龄:"+this.age;
	}
}

Introspector01.java

package JavaBean;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;

public class Introspector01{
	public static void main(String args[])throws Exception{
		Person beanObj=new Person();
		BeanInfo bInfoObject=Introspector.getBeanInfo(beanObj.getClass(),beanObj.getClass().getSuperclass());
		String str="内省成员属性:\n";
		PropertyDescriptor[] mPropertyArray=bInfoObject.getPropertyDescriptors();
		for(int i=0;i<mPropertyArray.length;i++){
			String propertyName=mPropertyArray[i].getName();
			Class propertyType=mPropertyArray[i].getPropertyType();
			str+=propertyName+"("+propertyType.getName()+")\n";
		}
		System.out.println(str);
	}
}

javaswing组件介绍 java 组件_构造方法_06


修改JavaBean的属性

Introspector02.java

package JavaBean;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

public class Introspector02 {
	public static void main(String[] args)throws Exception{
		Person p=new Person();
		PropertyDescriptor pd=new PropertyDescriptor("name",p.getClass());
		Method methodName=pd.getWriteMethod();
		methodName.invoke(p, "小明");
		String val="20";
		pd=new PropertyDescriptor("age",p.getClass());
		Method methodAge=pd.getWriteMethod();
		Class clazz=pd.getPropertyType();
		if(clazz.equals(int.class)){
			methodAge.invoke(p, Integer.valueOf(val));
		}else{
			methodAge.invoke(p, val);
		}
		System.out.println(p);
	}
}

javaswing组件介绍 java 组件_javaswing组件介绍_07


需要注意的是,使用内省设置属性时,必须要设置对应数据类型的数据,否则程序会出错。

读取JavaBean的属性

使用PropertyDescriptor类的getWriteMethod()方法就可以获取属性对应的setter方法。在JavaBean中,属性的getter和setter方法是成对出现的,因此Java的内省也提供了读取JavaBean属性的方法,只需要使用PropertyDescriptor类的getReadMethod()方法就可以获取属性对应的getter方法。

Introspector03.java

package JavaBean;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

public class Introspector03 {
	public static void main(String[] args)throws Exception{
		Person p=new Person();
		p.setName("李芳");
		p.setAge(18);
		PropertyDescriptor pd=new PropertyDescriptor("name",p.getClass());
		Method methodName=pd.getReadMethod();
		Object o=methodName.invoke(p);
		System.out.println("姓名:"+o);
		pd=new PropertyDescriptor("age",p.getClass());
		Method methodAge=pd.getReadMethod();
		o=methodAge.invoke(p);
		System.out.println("年龄:"+o);
	}
}

javaswing组件介绍 java 组件_javaswing组件介绍_08

JSP标签访问JavaBean

为了在JSP页面中简单快捷地访问JavaBean,并且充分地利用JavaBean地特性,JSP规范专门定义了三个JSP标签<jsp:useBean>,<jsp:setProperty>,<jsp:getProperty>。
<jsp:useBean>标签
<jsp:useBean>标签用于在某个指定的域范围中查找一个指定名称的JavaBean对象,如果存在则直接返回该JavaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它按指定的名称存储在指定的域范围中。

<jsp:useBean id="beanInstanceName" [scope="{page|request|session|application}"]
{
	class="package.class"|
	type="package.class"|
	class="pageckage.class" type="package.class"|
	beanName="{package.class|<%=expression%>}"type="package.class"
}/>

标签中有5个属性
1、id:用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称。
2、scope:用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session和application4个中的一个,其默认值是page
3、type:用于指定JavaBean实例对象的引用变量类型,它必须是JavaBean对象的类名称、父类名称或JavaBean实现的接口名称。type属性的默认值为class属性的设置值,当JSP容器将<jsp:useBean>标签翻译成Servlet程序时,他将使用type属性值作为JavaBean对象引用变量的类型
4、class:用于指定JavaBean的完整类名,JSP容器将使用这个类名来创建JavaBean的实例对象或作为查找到JavaBean对象的类型
5、beanName:用于指定JavaBean的名称,它的值也是a.b.c的形式,这既可以代表一个类的完整名称,也可以代表a/b/c.ser这样的资源文件。beanName属性值将被作为参数传递给java.beans.Beans类的instantiate方法,创建出JavaBean实例对象。需要注意的是,beanName属性值也可以为一个脚本表达式。
在使用<jsp:useBean>标签时,id属性必须指定,scope属性可以不用指定,没有没有指定scope属性,则会使用他的默认值page。而对于class、type、beanName这三个属性,它们的使用方式有4种。
1、单独使用class属性
由于<jsp:useBean>标签会用到JavaBean组件,因此在使用标签之前,首先创建两个JavaBean类Employee和Manager,Manager类继承自Employee类
Employee.java

package JavaBean;

public class Employee {
	private String company;
	public String getCompany(){
		return company;
	}
	public void setCompany(String company){
		this.company=company;
	}
}

Manager.java

package JavaBean;

public class Manager extends Employee{
	private double bonus;
	public double getBonus(){
		return bonus;
	}
	public void setBonus(double bonus){
		this.bonus=bonus;
	}
}

useBean.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<jsp:useBean id="manager" scope="page" class="JavaBean.Manager"/>
</body>
</html>

可以查看此jsp翻译的servlet

javaswing组件介绍 java 组件_构造方法_09


从上面的代码可以看到,JSP容器首先定义一个引用变量manager,manager为class属性指定的类型,然后在scope属性指定的域范围中查找以manager为名称的JavaBean对象,如果该域范围中不存在指定JavaBean对象,JSP容器会创建class属性指定类型的JavaBean实例对象,并用变量manager引用。

需要注意的时,翻译成的Servlet代码,用于引用JavaBean实例对象的变量名和JavaBean存储在域中的名称均为id属性设置的值manager。

2、单独使用type属性

将上面<jsp:useBean>标签中的class属性改为type属性。

<jsp:useBean id="manager" scope="page" type="Javabean.Manager"/>

再次访问会发生500异常

javaswing组件介绍 java 组件_构造方法_10


再看jsp翻译的Servlet

javaswing组件介绍 java 组件_javaswing组件介绍_11


可以看到如果只设置了type属性值时,JSP容器会在指定的域范围中查找以id属性值为名称的JavaBean对象,如果对象不存在,JSP容器不会创建新的JavaBean对象,而会抛出异常。

为了解决这个问题,在标签前加入一段JSP脚本片段,为pageContext域增加一个属性,属性名为"manager",值为Manger对象

<%
		pageContext.setAttribute("manager",new JavaBean.Manager());
	%>

再次访问,没有异常了。
需要注意的是,<jsp:useBean>标签的type属性值还可以指定为JavaBean的父类或者由JavaBean实现的接口。
3、class属性和type属性结合使用
由于type属性的默认值为class属性的设置值,也就是说在<jsp:useBean>标签中只要设置了class属性,相当于设置了type属性的默认值,因此与第一种相同。
4、beanName属性和type属性的结合使用
将useBean.jsp页面中的JSP脚本片段去掉,并对<jsp:useBean>标签进行修改,使用id、beanName、type属性

<jsp:useBean id="manager" scope="page" beanName="JavaBean.Manager" type="JavaBean.Manager"/>

javaswing组件介绍 java 组件_实例化_12


从上面的代码中可以看到,JSP容器会在scope属性指定的域范围中查找以id属性值为名称的JavaBean对象,如果该域范围中不存在指定JavaBean对象,JSP容器会将加载当前类的对象和beanName属性值作为参数传递给java.beans.Beans类的instantiate()方法,去创建新的JavaBean实例对象,如果创建成功,JSP容器会将该对象以id属性值为名称存储到scope属性指定的域范围中。注意:带标签体的<jsp:useBean>标签,标签内的内容只有在<jsp:useBean>标签创建JavaBean的实例对象时才执行,如果在<jsp:useBean>标签的scope属性指定的域范围中存在以id属性值为名称JavaBean对象,<JavaBean>标签的标签体Body将被忽略。

javaswing组件介绍 java 组件_构造方法_13

javaswing组件介绍 java 组件_javaswing组件介绍_14


<jsp:setProperty>标签

要想为JavaBean对象设置属性,还需要通过<jsp:setProperty>标签来实现

<jsp:setProperty name="beanInstanceName"
{
	property="propertyName" value="{string |<%=expression%>}"|
	property="propertyName" param="parameterName"|
	property="propertyName |*"
}/>

1、name:用于指定JavaBean实例对象的名称,其值应该和<jsp:useBean>标签的id属性值相同。
2、property:用于指定JavaBean实例对象的属性名。
3、param:用于指定请求消息中参数的名字。在设置JavaBean的属性时,如果请求参数的名字和JavaBean属性的名字不同,可以使用param属性,将其指定的参数的值设置给JavaBean的属性。如果当前请求消息中没有param属性所指定的请求参数,那么<jsp:setProperty>标签什么事情也不做,他不会将null值赋给JavaBean属性,所设置的JavaBean属性仍将等于原来的初始值。
4、value:用于指定为JavaBean实例对象的某个属性设置的值。其值可以是一个字符串,也可以是一个JSP表达式。如果value属性的设置值是字符串是字符串,那么它将被自动转换成所要设置的JavaBean属性的类型。
1、property属性单独使用
在单独使用property属性时,property的属性值可以设置为JavaBean的一个属性名,也可以设置为一个星号(*)通配符。
1)property的属性值为JavaBean的属性
当property属性值为JavaBean的一个属性名时,JSP容器会将请求消息中与property属性值同名的参数的值赋值给JavaBean对应的属性。

<jsp:useBean id="manager" scope="page" beanName="JavaBean.Manager" type="JavaBean.Manager"/>
	<jsp:setProperty property="bonus" name="manager"/>
	<%
		manager=(Manager)pageContext.getAttribute("manager");
		out.write("bonus属性的值为:"+manager.getBonus());
	%>

javaswing组件介绍 java 组件_实例化_15


可以看到请求中bonus的值赋给了JavaBean。

如果请求中没有bonus属性,bonus属性值为空字符串,那么JavaBean的值不会被改变。

2)property的属性值为星号通配符
当property属性的值为星号通配符时,JSP容器会在请求消息中查找所有的请求参数,如果有参数的名字和JavaBean对象的属性名相同,JSP容器会将参数的值设置为JavaBean对象属性的值。

<jsp:useBean id="manager" scope="page" beanName="JavaBean.Manager" type="JavaBean.Manager"/>
	<jsp:setProperty property="*" name="manager"/>
	<%
		manager=(Manager)pageContext.getAttribute("manager");
		out.write("bonus属性的值为:"+manager.getBonus()+"<br/>");
		out.write("company属性的值为:"+manager.getCompany()+"<br/>");
	%>

javaswing组件介绍 java 组件_构造方法_16


2、property属性和param属性配合使用

在实际开发中,很多时候服务器需要使用表单传递的数据为JavaBean对象的属性赋值,但是如果表单中表单项name属性的值和JavaBean中属性名不能对应,就需要在<jsp:setProperty>标签中使用param属性,JSP容器会将param属性指定的参数的值赋值给JavaBean的属性。

<jsp:useBean id="manager" scope="page" beanName="JavaBean.Manager" type="JavaBean.Manager"/>
	<jsp:setProperty property="bonus" param="aaa" name="manager"/>
	<jsp:setProperty property="company" param="bbb" name="manager"/>
	<%
		manager=(Manager)pageContext.getAttribute("manager");
		out.write("bonus属性的值为:"+manager.getBonus()+"<br/>");
		out.write("company属性的值为:"+manager.getCompany()+"<br/>");
	%>

javaswing组件介绍 java 组件_构造方法_17


3、property属性和value属性配合使用

JSP容器会使用value属性的值为JavaBean的属性赋值,即使在访问是传入了JavaBean属性对应的参数,JSP容器也会忽略它。

value属性的值还可以通过JSP动态元素来指定,如果要为JavaBean对象中引用类型成员变量赋值,例如,为Manager类中Date类型的成员变量birthday赋值。

Manager.java

package JavaBean;

import java.util.Date;

public class Manager extends Employee{
	private double bonus=500;
	private Date birthday;
	public double getBonus(){
		return bonus;
	}
	public void setBonus(double bonus){
		this.bonus=bonus;
	}
	public Date getBirthday(){
		return birthday;
	}
	public void setBirthday(Date birthday){
		this.birthday=birthday;
	}
}

setProperty.jsp

<%@page import="JavaBean.Manager,java.util.Date,java.text.SimpleDateFormat"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<%
		Date date=new Date();
		pageContext.setAttribute("date",date);
	%>
	<jsp:useBean id="manager" scope="page" beanName="JavaBean.Manager" type="JavaBean.Manager"/>
	<jsp:setProperty property="birthday" value="${date}" name="manager"/>
	<%
		manager=(Manager)pageContext.getAttribute("manager");
		String formatDate=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(manager.getBirthday());
		out.write("birthday属性的值为:"+formatDate);
	%>
</body>
</html>

javaswing组件介绍 java 组件_java_18


<jsp:getProperty>标签

为了获取JavaBean的属性值,JSP规范提供了<jsp:getProperty>标签,它可以访问JavaBean的属性,并把属性的值转化成一个字符串发送到响应输出流中。如果JavaBean的属性值是一个引用数据类型的对象,<jsp:getProperty>标签会调用该对象的toString()方法,如果JavaBean的属性值为null,会输出字符串"null"

<jsp:getProperty name="beanInstanceName" property="PropertyName"/>

1、name:用于指定JavaBean实例对象的名称,其值应该和<jsp:useBean>标签的id属性值相同。
2、property:用于指定JavaBean实例对象的属性名。

BeanUtils工具

大多数Java程序开发人员过去习惯于创建JavaBean然后通过调用JavaBean属性对应的getXxx和setXxx方法来访问属性。但是由于各种Java工具和框架层出不穷,并不能保证属性对应的getXxx和setXxx方法总能被调用,因此动态访问Java对象的属性是必要的,尽管Java

语言提供了反射和内省的API,但是这些API相当复杂且操作繁琐。为此Apache软件基金会提供了一套简单、易用的API-BeanUtils工具。

https://commons.apache.org/proper/commons-beanutils/download_beanutils.cgi

javaswing组件介绍 java 组件_javaswing组件介绍_19


将commons-beanutils-1.9.4.jar解压至tomcat安装目录下的lib下

javaswing组件介绍 java 组件_实例化_20


BeanUtils工具中封装了许多类,其中最核心的是org.apache.commons.beanutils包下的BeanUtils类。

需要注意的是BeanUtils依赖一个logging包,我们需要引入https://commons.apache.org/proper/commons-logging/download_logging.cgi

javaswing组件介绍 java 组件_java_21

方法声明

功能描述

static String getMappedProperty(Object bean,String name)

返回指定bean中指定索引属性的值,返回类型是String类型(进行了类型转换)

static String getMappedProperty(Object bean,String name,String key)

返回指定bean中指定索引属性的值的指定键的值,返回类型是String类型

static String getProperty(Object bean,String name)

返回指定bean指定属性的值,返回类型为String类型

static void populate(Object bean,Map<String,? extends Object>properties)

根据指定的名称/值对为相应的JavaBean属性设置值

static void setProperty(Object bean,String name,Object value)

设置指定的属性值,传入的类型要求能转化成相应属性的类型

BeanUtilsDemo01.java

package JavaBean;

import org.apache.commons.beanutils.BeanUtils;

public class BeanUtilsDemo01 {
	public static void main(String[] args)throws Exception{
		Person p=new Person();
		BeanUtils.setProperty(p, "name", "Jack");
		BeanUtils.setProperty(p, "age", 10);
		String name=BeanUtils.getProperty(p, "name");
		String age=BeanUtils.getProperty(p, "age");
		System.out.println("我的名字是"+name+",我今年"+age+"岁了!");
	}
}

javaswing组件介绍 java 组件_实例化_22


注意的是:BeanUtils调用的类必须是public类型的,否则会报错

BeanUtils工具访问JavaBean的属性

package JavaBean;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;

public class BeanUtilsDemo01 {
	public static void main(String[] args)throws Exception{
		Class clazz=Class.forName("JavaBean.Person");
		Person p=(Person)clazz.newInstance();
		Map<String,Object>map=new HashMap<String,Object>();
		map.put("name", "张三");
		map.put("age", 10);
		BeanUtils.populate(p, map);
		System.out.println(p);
	}
}

javaswing组件介绍 java 组件_构造方法_23


populate()方法一次性为多个属性赋值。