Beautils工具类实现的原理
关于内省机制和反射机制请看这一篇博客【还没写完,在草稿中】。
先说一下什么叫做 bean 属性,bean 属性指的是 get / set 方法后的名称,而不是类的属性:
比如:
private String username; //bean属性指的不是这里的属性
public String getUsername() {//而是指的这里get后面的名称
return username;
}
public void setUsername(String username) {//这里的set后面的Username就是bean属性
this.username = username;
}
Beanutils 工具它的底层是使用 java 内省(introspector)机制,而内省它的实现是依赖于 java 反射。
1、直接使用反射实现 Beanutils 的功能:
package online.msym.test; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; import org.junit.Test; import online.msym.bean.User; public class Demo { //使用反射来完成封装
@Test
public void fun1() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
//1.创建一个Map集合,模仿 request.getParameterMap() 获取的结果
Map<String,String[]> map=new HashMap<String, String[]>();
map.put("username", new String[]{"tom"});//注意,我这里put的是小写的username,虽然后面使用的是equalsIgnoreCase(),但是还是不妥,
map.put("password", new String[]{"123"}); //这个错误由博友【圳(zhèn)】[这个字不会读…]找出。
//2.创建一个User对象(User类中提供了get/set方法,toString方法)
User user=new User();
//3.将map集合中key的名称与user中bean属性一致的使用key对应的value封装到bean属性上。
//3.1得到map中所有的key的set集合
Set<String> keys=map.keySet();
//3.2得到User类中所有的方法
Method[] ms=user.getClass().getDeclaredMethods();
//3.3.判断所有方法名称是否与"set"+key的值相等(不区分大小写)
for(String key:keys){
String setMethodName="set"+key; //此时,遍历的第一个setMethodName = setusername,所以后面的equals()需要忽略大小写。
//3.4遍历所有的ms,并得到方法名称
for(Method m:ms){
String methodName=m.getName();
if(setMethodName.equalsIgnoreCase(methodName)){ //我在这里,equalsIgnoreCase()
//3.5.使用method对象调用invoke方法将key对应的value值进行赋值
m.invoke(user, map.get(key)[0]); // user.setXxx(map.get(xxx))
}
}
}
//4.输出
System.out.println(user);
}
}

2、使用内省(introspector)的方式完成:
package online.msym.test; import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; import org.junit.Test; import online.msym.bean.User; public class Demo {
// 使用内省来完成请求参数封装
@Test
public void fun2() throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
// 1.创建一个Map集合,模仿request.getParameterMap()获取的结果
Map<String, String[]> map = new HashMap<String, String[]>();
map.put("username", new String[] { "tom" });
map.put("password", new String[] { "123" });
// 2.创建一个User对象
User user = new User();
// 3.得到一个BeanInfo对象
BeanInfo bif = Introspector.getBeanInfo(User.class);
// 4.得到所有属性描述器
PropertyDescriptor[] pds = bif.getPropertyDescriptors();
// 5.通过属性描述器得到读写方法
for (PropertyDescriptor pd : pds) {
Method writeMethod = pd.getWriteMethod();
// 6.得到方法名称
if (writeMethod != null) {
//System.out.println(pd.getName()); //得到bean属性名称
//System.out.println(writeMethod.getName()); //得到所有的set方法名称
String name=pd.getName();
writeMethod.invoke(user, map.get(name)[0]);
}
}
System.out.println(user);
}
}
这个 Beanutils 工具类能实现大多数的 bean 数据的封装,但是也有不能被封装的,比如 Date 对象,当有 Date 类型的 bean 时,就需要自定义类型转换器了。
表单:

下面是一个自定义的类型转换器:(将表单中的生日文本转换为 Date 类型,封装到 javabean 中)
package online.msym.utils; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date; import org.apache.commons.beanutils.Converter; public class MyDateConverter implements Converter { // 这个方法就是真正进行类型转换的方法
public Object convert(Class type, Object value) {
// System.out.println(type); // class java.util.Date
// System.out.println(value); // 2018/11/11
String s = (String) value;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date = null;
try {
date = sdf.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
}
在封装 javabean 的 Servlet 中的 dopost() 方法中这样写:
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
User user = new User();
try {
// 对自定义的类型转换器进行注册
ConvertUtils.register(new MyDateConverter(), java.util.Date.class);
BeanUtils.populate(user, request.getParameterMap());
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println(user);//这里会打印出表单输入的数据,并将输入的Date字符串,转换为Date类型
}
打印输出:( User 类中重写了 toString()方法)

Beautils工具类实现的原理的更多相关文章
- 基于AQS实现的Java并发工具类
本文主要介绍一下基于AQS实现的Java并发工具类的作用,然后简单谈一下该工具类的实现原理.其实都是AQS的相关知识,只不过在AQS上包装了一下而已.本文也是基于您在有AQS的相关知识基础上,进行讲解 ...
- 一个强大的json解析工具类
该工具类利用递归原理,能够将任意结构的json字符串进行解析.当然,如果需要解析为对应的实体对象时,就不能用了 package com.wot.cloudsensing.carrotfarm.util ...
- 【重学Java】多线程进阶(线程池、原子性、并发工具类)
线程池 线程状态介绍 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.线程对象在不同的时期有不同的状态.那么Java中的线程存在哪几种状态呢?Java中的线程 状态被定 ...
- 并发编程学习笔记(10)----并发工具类CyclicBarrier、Semaphore和Exchanger类的使用和原理
在jdk中,为并发编程提供了CyclicBarrier(栅栏),CountDownLatch(闭锁),Semaphore(信号量),Exchanger(数据交换)等工具类,我们在前面的学习中已经学习并 ...
- 线程并发工具类之CountDownLatch的使用及原理分析
原文链接:http://www.studyshare.cn/blog/details/1149/1 java开发工具下载地址及安装教程大全,点这里.更多技术文章,在这里. 一.定义 CountDown ...
- java并发编程系列原理篇--JDK中的通信工具类Semaphore
前言 java多线程之间进行通信时,JDK主要提供了以下几种通信工具类.主要有Semaphore.CountDownLatch.CyclicBarrier.exchanger.Phaser这几个通讯类 ...
- 分享自研实现的多数据源(支持同DB不同表、跨DB表、内存数据、外部系统数据等)分页查询工具类实现原理及使用
思考: 提起分页查询,想必任何一个开发人员(不论是新手还是老手)都能快速编码实现,实现原理再简单不过,无非就是写一条SELECT查询的SQL语句,ORDER BY分页排序的字段, 再结合limit ( ...
- [转]Java常用工具类集合
转自:http://blog.csdn.net/justdb/article/details/8653166 数据库连接工具类——仅仅获得连接对象 ConnDB.java package com.ut ...
- 全文检索解决方案(lucene工具类以及sphinx相关资料)
介绍两种全文检索的技术. 1. lucene+ 中文分词(IK) 关于lucene的原理,在这里可以得到很好的学习. http://www.blogjava.net/zhyiwww/archive/ ...
随机推荐
- ubuntu下安装pdo和pdo_mysql扩展
ubuntu下安装好LAMP后默认情况没有安装mysql_pdo扩展,以下是安装步聚 1 安装pdo sudo pecl install pdo 出现以下错误是说明pdo已经加入了php的默认安装,不 ...
- Picasso 修改缓存路径
Picasso 是 Square 公司开源的一个非常友好的图片加载框架,使用范围也比较广泛.具体的使用这里就不做介绍了,文章主要讲讲如何修改图片的缓存路径.Picasso默认的缓存路径位于data/d ...
- FTPS (FTP over SSL) vs. SFTP (SSH 文件传输协议): 我们如何做出选择
第一个RFC的FTP协议发布通过网络使用FTP协议(由RFC 959或更高版本)的文件传输始于1980年,FTP提供上传,下载和删除文件,创建和删除目录,读取目录内容的功能.虽然FTP是非常受欢迎的, ...
- c++ STL常用算法使用方法
#include <string> #include <vector> #include <functional> #include <iostream> ...
- SQL SERVER的检查点checkpoint
1 什么是检查点 数据修改操作 都是在 内存中的数据页进行修改,每次修改后并没有立即把这些页面写入磁盘,而是等到一定时期,数据库引擎对数据库发起 检查点命令,这时,该命令就会创建一个已知的正常点,把当 ...
- 过程 : 概念 : 结构 jobbox jobPost
概念是employer创建jobPost时,可以publish或unpublish. sort expired后,会通过server tast 去更新成history.所有的publish和unpub ...
- STL_deque双端队列
deque:元素数据采用分块的线性结构存储.若干线性存储块成为deque块.一般大小为512字节,元素的数据类型所占用的字节数,决定了每个deque块可容纳的元素个数. 所有的deque块使用一个Ma ...
- Filebeat issue 排查--single.go:140: ERR Connecting error publishing events (retrying): dial tcp ****:5044: i/o timeout
我个人用docker搭建了一套日志分析平台:ELK+Filebeat 在正常跑了半个多月之后,Kibana刷新日志时突然发现日志不在更新了,停在某个时刻,就再也没有新log. 首先我查看了elk,lo ...
- ARZhu的数论初步
数论 2017年3月4日02:11:35 gcd 1. 原理: gcd( a, b ) = gcd( b, a - b ) -> gcd( a, b ) = gcd( b, b % a ) 2. ...
- Unbutu14.04 切换ROOT用户后无法启用音频
系统环境: Ubuntu14.04 x64 问题描述: 今天安装了Ubuntu14.04的64位系统,启用root用户登录后,观看视频时出现没有声音的现象. 问题原因: Ubuntu安装后默认root ...
]找出。