#二、框架思路
获取数据库数据,反射获取类模型的字段,以及set方法,通过invoke我们的set方法,将数据set到类模型对象之中,将行数据作为对象返回出来,多条数据则返回对象集合
#三、工具类,辅助类编写
1.首先是封装类的对象,作用是将类的字段和方法都存储到两个数组之中,拆分模型类
packagecom.warrenwell.dao.util.bean;importjava.lang.reflect.Field;importjava.lang.reflect.Method;/*** 类的信息,用于封装类的结构
*@authorAdministrator
**/
public classClassInfo {//属性
privateField[] fields;//方法
privateMethod[] methods;publicField[] getFields() {returnfields;
}public voidsetFields(Field[] fields) {this.fields =fields;
}publicMethod[] getMethods() {returnmethods;
}public voidsetMethods(Method[] methods) {this.methods =methods;
}
}
2.有了模型类的封装类,自然就有数据库列的封装类,设定两个字段一个是列类型,一个是列名字,这样之后只要一个此类的数组就能表示一个表的结构
packagecom.warrenwell.dao.util.bean;/*** 列数据
*@authorAdministrator
**/
public classColumnData {privateString columnName;private intcolumnType;publicString getColumnName() {returncolumnName;
}public voidsetColumnName(String columnName) {this.columnName =columnName;
}public intgetColumnType() {returncolumnType;
}public void setColumnType(intcolumnType) {this.columnType =columnType;
}
}
3.接下来就是数据库的连接等工具类的编写,我把数据库的配置写在了配置文件,下面是我的DaoUtil中的数据库工具类的编写以及配置文件的书写方式,配置文件名字为DBConfig,在src路径下。获取连接等加锁是出于安全的考虑
private staticString driver;private staticString url;private staticString user;private staticString password;protected static intsize;private staticDataSource dataSource;/*** 加载配置文件*/
static{
ResourceBundle bundle= ResourceBundle.getBundle("DBConfig");
System.out.println("加载了配置文件");//解析配置文件中的数据
driver = bundle.getString("driver");
user= bundle.getString("user");
password= bundle.getString("password");
url= bundle.getString("url");try{
size= Integer.parseInt(bundle.getString("pageSize"));
}catch(NumberFormatException e) {//TODO Auto-generated catch block
e.printStackTrace();
System.out.println("size格式非法!");
}
}/*** 获取数据库连接
*@return
*/
public static synchronizedConnection getConnection(){
Connection con= null;try{//驱动加载
Class.forName(driver);//获取连接对象
con =DriverManager.getConnection(url,user,password);
}catch(ClassNotFoundException e) {//TODO Auto-generated catch block
e.printStackTrace();
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}returncon;
}/*** 关闭数据库对象
*@paramcon 连接
*@paramstmt 处理器
*@paramrs 结果集*/
public static synchronized voidclose(Connection con, Statement stmt, ResultSet rs){try{if(rs != null){
rs.close();//rs = null;
}if(stmt != null){
stmt.close();//stmt = null;
}if(con != null){//如果该connection对象是由数据池创建的,其close方法表示将连接放回连接池//如果该Connection对象是由数据库驱动提供的,close方法表示断开数据库连接,并清除开销的资源
con.close();//con = null;
}
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}
}
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.3.100:1521:orcl
user=system
password=niit
pageSize=4
4.我们从数据库查询到结果集就要被解析封装成列数据的数组了,相当于解析出结果集的结构
/*** 解析元数据
*@paramdata
*@return
*/
public staticColumnData[] parseResultSetMetaData(ResultSetMetaData data){
ColumnData[] columnData= null;if(data != null){try{
columnData= newColumnData[data.getColumnCount()];for(int i = 0; i < data.getColumnCount(); i++){
ColumnData column= newColumnData();//封装列的名称
column.setColumnName(data.getColumnName(i+1));//封装列的类型
column.setColumnType(data.getColumnType(i+1));
columnData[i]=column;
}
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}
}returncolumnData;
}
映射实体类也要被解析到类模型之中,说白了就是将实体类的字段和方法进行解析,以便之后使用,这里我们需要考虑到有的实体类可能是继承自父类的,我们这里需要反射的时候都获取到就可能出现重复的字段或者方法,所以我们选择set集合存储这些字段和方法,利用的就是set集合的自动去重复,之后再将set集合转为数组
/*** 解析类
*@paramclassObj
*@return
*/
public staticClassInfo parseClass(Class classObj){//存储所有属性的集合//方式一
Set setF = new HashSet();for(Field f : classObj.getDeclaredFields()){
setF.add(f);
}for(Field f : classObj.getFields()){
setF.add(f);
}//存储所有方法
Set setM = new HashSet();for(Method m : classObj.getDeclaredMethods()){
setM.add(m);
}for(Method m : classObj.getMethods()){
setM.add(m);
}//封装类的属性和方法
ClassInfo info = newClassInfo();
Field[] arrayF= newField[setF.size()];//将集合转换成数组
setF.toArray(arrayF);
Method[] arrayM= newMethod[setM.size()];
setM.toArray(arrayM);
info.setFields(arrayF);
info.setMethods(arrayM);returninfo;
}/*** 首字母大写转换
*@paramstr
*@return
*/
public staticString upperFirstWorld(String str){return str.substring(0,1).toUpperCase().concat(str.substring(1));
}
到了这里所有的辅助类和工具类就都完成了,我们就可以去编程我们的数据的增删改查的框架了
#四、核心框架代码编写
1.增删改的数据框架,没有什么需要反射的,主要是做到sql注入的时候,我们把参数都写到一个object数据,因为我们也不知道参数的个数和参数的类型
public static synchronized voidexecuteUpdate(String sql,Object[] params){
Connection con=DaoUtil.getConnection();
PreparedStatement pstmt= null;if(con != null){try{
pstmt=con.prepareStatement(sql);//注入参数
if(params != null){for(int i = 0; i < params.length; i++){if(params[i].getClass() == String.class){
pstmt.setString(i+1, params[i].toString());
}else if(params[i].getClass() == int.class || params[i].getClass() == Integer.class){
pstmt.setInt(i+1, (Integer)params[i]);
}//....else if() 判断各种事情类型情况
else{
pstmt.setObject(i+1, params[i]);//其实只要这句话上面的判断就不需要了
}
}//执行增删改
pstmt.executeUpdate();
}
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}finally{
DaoUtil.close(con, pstmt,null);
}
}
}
2.这也是重点来了,查询数据,我这里以查询多行数据为例,从而返回的应该是实体映射类对象的集合下图是我们数据库中表的大概结构
从而对应的实体类应为
packagecom.warrenwell.pojo;/*** 数据持久层
*@author123
*此处为用户类*/
public classUser {privateString userName;private intuserid;privateString tel;privateString birthday;privateString nation;privateString origin;privateString password;private intflag;privateString headimg;private intismarry;private intsex;public intgetIsmarry() {returnismarry;
}public void setIsmarry(intismarry) {this.ismarry =ismarry;
}public intgetSex() {returnsex;
}public void setSex(intsex) {this.sex =sex;
}publicString getHeadimg() {returnheadimg;
}public voidsetHeadimg(String headimg) {this.headimg =headimg;
}publicString getUserName() {returnuserName;
}public voidsetUserName(String userName) {this.userName =userName;
}public intgetUserid() {returnuserid;
}public void setUserid(intuserid) {this.userid =userid;
}publicString getTel() {returntel;
}public voidsetTel(String tel) {this.tel =tel;
}publicString getBirthday() {returnbirthday;
}public voidsetBirthday(String birthday) {this.birthday =birthday;
}publicString getNation() {returnnation;
}public voidsetNation(String nation) {this.nation =nation;
}publicString getOrigin() {returnorigin;
}public voidsetOrigin(String origin) {this.origin =origin;
}publicString getPassword() {returnpassword;
}public voidsetPassword(String password) {this.password =password;
}public intgetFlag() {returnflag;
}public void setFlag(intflag) {this.flag =flag;
}
}
我们需要获取到实体类所拥有的属性和set方法,再去解析结果集的结构,依次比较实体类中有的字段在数据库之中也有的,那么就是我们所需要的,从而invoke该实体类的set方法,将值set到实体类的对应字段之中。
/*** 通用的数据查询方法
*@return多行数据*/
public static synchronized List executeQueryForMultipl(String sql, Object[] params, ClassclassObj){
List list = new ArrayList();
T t= null;
Connection con=DaoUtil.getConnection();
PreparedStatement pstmt= null;
ResultSet rs= null;if(con != null){try{
pstmt=con.prepareStatement(sql);if(params != null){//循环注入参数
for(int i = 0; i < params.length; i++){
pstmt.setObject(i+1, params[i]);
}
}//执行查询
rs =pstmt.executeQuery();//解析结果集的数据结构
ColumnData[] data =DaoUtil.parseResultSetMetaData(rs.getMetaData());//解析映射类的结构
ClassInfo info =DaoUtil.parseClass(classObj);//读取结果集
while(rs.next()){//实例化
t =classObj.newInstance();//每列的值
Object value = null;//根据结果集的数据结构获取每个列的数据
for(int i = 0; i < data.length; i++){
ColumnData column=data[i];//判断映射类中是否存在对应的属性
for(Field f : info.getFields()){if(f.getName().equalsIgnoreCase(column.getColumnName())){//判断映射类是否存在该属性对应的setter方法
for(Method m : info.getMethods()){if(m.getName().equals("set"+DaoUtil.upperFirstWorld(f.getName()))){if(f.getType() == Integer.class || f.getType() == int.class){
value= rs.getInt(i+1);
}else if(f.getType() == Double.class || f.getType() == double.class){
value= rs.getDouble(i+1);
}else if(f.getType() == String.class){
value= rs.getString(i+1);
}else if(f.getType() == Timestamp.class){
value= rs.getTimestamp(i+1);
}//如果方法存在则invoke执行//System.out.println(m.getName()+"\t"+value);
m.invoke(t, value);break;
}
}break;
}
}
}//end-for
list.add(t);
}//end-while
} catch(IllegalArgumentException e) {//TODO Auto-generated catch block
e.printStackTrace();
}catch(SQLException e) {//TODO Auto-generated catch block
e.printStackTrace();
}catch(InstantiationException e) {//TODO Auto-generated catch block
e.printStackTrace();
}catch(IllegalAccessException e) {//TODO Auto-generated catch block
e.printStackTrace();
}catch(InvocationTargetException e) {//TODO Auto-generated catch block
e.printStackTrace();
}finally{
DaoUtil.close(con, pstmt, rs);
}
}returnlist;
}
以后我们在Dao之中只需要调用我们的核心方法即可,如下图:
public classUserDao {public User findUserById(intuserId){return DaoHandle.executeQueryForSingle("select * from users where userid=?", new Object[]{userId}, User.class);
}public voidsaveUser(User user){
DaoHandle.executeUpdate("insert into users values(userid.nextval,?,?,?,?,?)", newObject[]{user.getUserName(),user.getUserPwd(),user.getHead(),user.getRegTime(),user.getSex()});
}publicUser findUserByName(String userName){return DaoHandle.executeQueryForSingle("select * from users where username=?", new Object[]{userName}, User.class);
}
}
我们的数据层框架就会把结果依次的映射到对象中,并且返回出来。
单行和分页查询大家可以去试试,我这里只是提供了多行数据返回对象集合的代码。希望大家工作愉快,需要源码的dd我。拜拜!
#五、源代码地址