javabean的内省技术和BeanUtils的使用
一、关于javabean
javabean是固定写法的java类
书写格式为:
1)必须有无参构造函数
2)属性必须私有, 我们称为字段
3)提供标准的getter和setter
例: name 字段 的getter: String getName() settter: void setName(String name)
javabean例子:
//快捷键是shift+alt+s public class User { 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; } @Override //为了方便打印,添加一个toString方法 public String toString() { return "User [age=" + age + ", name=" + name + "]"; } }
二、关于 内省
内省是什么?: 通过反射的方式访问javabean的技术
Jdk中的api : PropertyDescriptor类操作Bean的属性
内省的作用:我们可以去实现一种通用性
1.传统的方式去访问javabean
public class Demo1 { public static void main(String[] args) { User user=new User(); user.setName("zhangsan"); user.setAge(19); System.out.println(user); } }
2.使用内省的方式来访问javabean
public class Demo1 { public static void main(String[] args) throws Exception { User user=new User(); //创建属性描述器 PropertyDescriptor descriptor=new PropertyDescriptor("name",User.class); //获得写方法 Method writeMethod=descriptor.getWriteMethod(); //调用写方法 writeMethod.invoke(user, "lisi"); System.out.println(user); } }
3.简化书写,实现通用性。这里写一个通用的方法,让属性名称为一个变量,假如属性名很多的话,得到属性名后,就可以遍历,然后给他们一一的赋值,这就是内省的魅力。
如果不用反射,那么传统的方式是不可能实现通用的。
下面代码实现能够为任何的javabean赋任何的值,只有用内省的方法才可以做的到:
import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import cn.itcast.day08.domain.User; public class Demo2 { /** * @param args * @throws IntrospectionException * @throws InvocationTargetException * @throws IllegalAccessException * @throws IllegalArgumentException */ public static void main(String[] args) throws Exception { // 内省 User user = new User(); setProperty(user, "name", "wangwu"); setProperty(user, "age", 11); System.out.println(user); } // 实现一个通用的方法 为任意的一个javabean的任意属性赋任意值 public static void setProperty(Object bean, String fieldName, Object value) throws Exception { // 创建属性描述器 PropertyDescriptor descriptor = new PropertyDescriptor(fieldName, bean.getClass()); // 获得 写方法 Method writeMethod = descriptor.getWriteMethod(); // 调用 写方法 writeMethod.invoke(bean, value); } }
由于内省用起来特别麻烦,Apache组织开发了一套用于操作JavaBean的API,如下详讲:
三、BeanUtils工具包
Apache组织开发了一套用于操作JavaBean的API(内省)
核心类 BeanUtils
setProperty(bean, name, value)
copyProperties(target, source);
可以支持String到8中基本数据类型转换
其他引用数据类型都需要注册转换器 ConvertUtils.register(Converter, Class)
注意:1、要想使用beanutils需要导入外部的jar包:commons-beanutils-1.8.0.jar这个jar包到lib目录里面
2、BeanUtils要想使用,还需要导入一个log的jar包:commons-logging.jar
下面我们来看看BeanUtils的魅力:
使用BeanUtils来格式化日期
1.javabean
package cn.itcast.day08.domain; import java.util.Date; // 一个javabean 是否有name属性取决于是否getter或setter方法 public class User { private String name; // 字段 private int age; private Date birthday; 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 Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "User [name=" + name + ", age=" + age + "]"; } }
2.beanutils
package cn.itcast.day08.introspector; import java.lang.reflect.InvocationTargetException; 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.converters.DateConverter; import org.apache.commons.beanutils.locale.converters.DateLocaleConverter; import cn.itcast.day08.domain.User; public class Demo3 { public static void main(String[] args) throws Exception { User user = new User(); String name = "zhangsan"; String age = "19"; String birthday = "19801122"; // 11/22/1980 1980 11 22 // 注册一个转换器 /* 使用匿名内部类来注册转换器 ConvertUtils.register(new Converter() { public Object convert(Class beanClass, Object value) { // String -- Date String birthday = (String) value; SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); try { return sdf.parse(birthday); } catch (ParseException e) { return null; } } }, Date.class); */ DateConverter converter = new DateConverter(); converter.setPatterns(new String[]{"yyyy-MM-dd","yyyyMMdd","MM/dd/yyyy"}); ConvertUtils.register(converter, Date.class); String fieldName = "name"; BeanUtils.setProperty(user, fieldName, name); BeanUtils.setProperty(user, "age", age); BeanUtils.setProperty(user, "birthday", birthday); System.out.println(user); System.out.println(user.getBirthday().toLocaleString()); } }
四. WebUtils 工具类
实现任何request提交的表单封装到对应的javabean
1.用户注册jsp页面:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>用户注册表单</title> </head> <body style="text-align: center;"> <form action="/myday08/servlet2" method="post" > <table border="1" width="600px"> <tr> <td>用户名</td> <td> <input type="text" name="name" /> </td> </tr> <tr> <td>年龄</td> <td> <input type="text" name="age" /> </td> </tr> <tr> <td>出生日期</td> <td> <input type="text" name="birthday" /> </td> </tr> <tr> <td> <input type="reset" value="重置" /> </td> <td> <input type="submit" value="用户注册" /> </td> </tr> </table> </form> </body> </html>
2.写一个工具类,把request里面所有的参数全部封装到javabean中去:
package cn.itcast.day08.util; import java.lang.reflect.InvocationTargetException; import java.sql.Date; import java.util.Enumeration; import javax.servlet.http.HttpServletRequest; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.ConvertUtils; import org.apache.commons.beanutils.converters.DateConverter; public class WebUtils { private WebUtils(){} //定义一个通用工具方法,将请求参数封装到javabean public static Object request2bean(HttpServletRequest request,Class beanClass){ try{ Object bean=beanClass.newInstance(); // 获得所有请求参数名 Enumeration names = request.getParameterNames(); //注册日期转换器 DateConverter converter=new DateConverter(); converter.setPattern("yyyy-MM-dd"); ConvertUtils.register(converter, Date.class); //遍历 while(names.hasMoreElements()){ // 获得一个参数名 String name = (String)names.nextElement(); // 获得参数名对应的参数值 String value = request.getParameter(name); //将参数名作为属性名 将参数值作为属性值,通过beanutils工具实现属性的封装 BeanUtils.setProperty(bean, name, value); } return bean; }catch (Exception e) { throw new RuntimeException(e); }//异常要抓下来,不能抛给servlet,把编译时异常包装称运行时异常 } }
3.写一个servlet页面,注意查看导入的包名称!分清关系
package cn.itcast.day08.web.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.itcast.day08.domain.User; import cn.itcast.day08.util.WebUtils; public class Servlet2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 表单提交的参数封装到javabean User bean = WebUtils.request2Bean(request, User.class); System.out.println(bean); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }