Dao设计模式(Data Access Object)

目    录(本篇字数:1858)

介绍

通用Dao

一、Dao泛型接口

二、JavaBean

三、Dao接口实现类

四、单元测试

五、反射工具类


  • 介绍

    Dao设计模式(Data Access Object),称为数据访问对象。它是对于数据库操作的一种设计方式,把Dao设计为一个通用接口,提供对数据库进行增、删、改、查的一系列操作数据库的抽象方法。

    面向对象编程的核心就是类、对象。数据库中每一张Table可以看作一个Class,而列就可以看作类中的一些属性。这是面向对象的基本思想,通过这种思想我们需要提供的Class就相当于Table的数量。而每次对数据库的操作时,根据查询的Table不同,就会得到不同的Class。

    又因为每个Class中操作增、删、改、查的方法都大相近庭,这就造成的代码的冗余、所以就出现Dao的设计思想。利用Dao接口提供的抽象方法对数据库进行操作就大大的降低代码重复,间接地可以提高程序的效率、性能等。

  • 通用Dao

    下面我们来编写一个通用的Dao,虽然有许多第三方的开源框架,其内部实现也是万变不离其中。其中用到数据库连接池(c3p0、dbcp)与DBUtils工具包,如果对这几个包的使用不是很清楚的话,推荐我写的上篇文章:数据库连接池(dbcp、c3p0)与DBUtils工具包的使用

一、Dao泛型接口

    下面是我们的Dao接口代码,提供了几种最基本的增、删、改、查的抽象方法。该接口传入一个泛型的实体类(如:UserBean)。

public interface Dao<T> {

	// 提供查询一个 bean
	T query(Connection conn, String sql, Object... args) throws SQLException;

	// 提供查询一个列表,如 beanList
	List<T> queryAll(Connection conn, String sql, Object... args) throws SQLException;

	// 提供查询单个值
	Object queryValue(Connection conn, String sql, Object... args) throws SQLException;

	// 提供增、删、改的操作
	void update(Connection conn, String sql, Object... args) throws SQLException;
}

二、JavaBean

    UserBean类,该类作为数据库映射到类的基础。

package com.xww;

public class User {

	public String userName;
	public String password;
	public String registerTime;
	public String sex;
	public String userRole;
	public String idCard;
	
	public User() {
		super();
	}

	public User(String userName, String password, String registerTime, 
			String sex, String userRole, String idCard) {
		super();
		this.userName = userName;
		this.sex = sex;
		this.userRole = userRole;
		this.password = password;
		this.idCard = idCard;
		this.registerTime = registerTime;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public String getUserRole() {
		return userRole;
	}

	public void setUserRole(String userRole) {
		this.userRole = userRole;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getIdCard() {
		return idCard;
	}

	public void setIdCard(String idCard) {
		this.idCard = idCard;
	}

	public String getRegisterTime() {
		return registerTime;
	}

	public void setRegisterTime(String registerTime) {
		this.registerTime = registerTime;
	}

	@Override
	public String toString() {
		return "User [userName=" + userName + ", password=" + password + ", registerTime=" + registerTime + ", sex="
				+ sex + ", userRole=" + userRole + ", idCard=" + idCard + "]\n";
	}
}

三、Dao接口实现类

    接着,我们有了Dao接口和JavaBean就应该编写Dao接口的实现类。

package com.xww;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

public class DaoImpl<T> implements Dao<T> {

	QueryRunner queryRunner = null;
	Class<T> type = null;

	public DaoImpl() {
		queryRunner = new QueryRunner();
		System.out.println(this.getClass());
		type = ReflectionUtils.getSuperGenericType(getClass());
	}

	@Override
	public T query(Connection conn, String sql, Object... args) throws SQLException {
		return queryRunner.query(conn, sql, new BeanHandler<T>(type), args);
	}

	@Override
	public List<T> queryAll(Connection conn, String sql, Object... args) throws SQLException {
		return queryRunner.query(conn, sql, new BeanListHandler<T>(type), args);
	}

	@Override
	public Object queryValue(Connection conn, String sql, Object... args) throws SQLException {
		return queryRunner.query(conn, sql, new ScalarHandler<T>(), args);
	}

	@Override
	public void update(Connection conn, String sql, Object... args) throws SQLException {
		queryRunner.update(conn, sql, args);
	}

}

    该类有一个Class<T> type 类型的变量,那么这个type类型就是我们传入的JavaBean(本例子中就是:User类)。这里涉及到利用Java反射来获取运行时中类的父类中传入的泛型 T 。如果对反射不懂的可以看这篇文章:Java反射机制(Reflection)获取运行时类的结构

    还有一个类是UserDao,它继承了DaoImpl类,拥有了父类的方法,同时在需求更改的情况下,可以进行对UserDao的拓展,在本例子中,并没有什么需要拓展的,就可以写为这样,传入一个类型为User的泛型即可。

package com.xww;

public class UserDao extends DaoImpl<User> {

}

四、单元测试

    再接着,是我们的单元测试类,提供对Dao接口设计的测试,在实际运用中也是如此使用。

package com.xww;

import static org.junit.Assert.*;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import org.junit.Test;

public class UserDaoTest {

	UserDao userDao = new UserDao();

	@Test
	public void testQuery() {
		Connection conn = null;
		String sql = "select username,password,registertime,sex,userrole,idcard from user where username=?";
		conn = JdbcUtils.getConnectionForC3P0();
		try {
			User user = (User) userDao.query(conn, sql, "小王");
			System.out.println(user);
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(null, conn, null);
		}
	}

	@Test
	public void testQueryAll() {
		Connection conn = null;
		String sql = "select username,password,registertime,sex,userrole,idcard from user";
		conn = JdbcUtils.getConnectionForC3P0();
		try {
			List<User> users = (List<User>) userDao.queryAll(conn, sql);
			System.out.println(users);
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(null, conn, null);
		}
	}

	@Test
	public void testQueryValue() {
		Connection conn = null;
		String sql = "select userrole from user where username=?";
		conn = JdbcUtils.getConnectionForC3P0();
		try {
			Object val = userDao.queryValue(conn, sql, "小王");
			System.out.println(val);
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(null, conn, null);
		}
	}

	@Test
	public void testUpdate() {
		Connection conn = null;
		String sql = "update user set userrole=? where username=?";
		conn = JdbcUtils.getConnectionForC3P0();
		try {
			userDao.update(conn, sql, "普通用户", "小王");
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JdbcUtils.release(null, conn, null);
		}
	}
}

    这里要注意一下:我们的UserDao继承自UserImpl,所以我们new的一个对象是UserDao的,即在UserImpl中获取的getClass()对象便是UserDao的对象,这里得区别清楚,否则获取父类的泛型会有一个坑。

五、反射工具类

    最后,是我们的获取父类的泛型的一个工具类:

package com.xww;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public class ReflectionUtils {

	@SuppressWarnings("unchecked")
	public static Class getSuperClassGenricType(Class clazz, int index) {
		Type genType = clazz.getGenericSuperclass();
		System.out.println(genType);

		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			return Object.class;
		}

		if (!(params[index] instanceof Class)) {
			return Object.class;
		}
		return (Class) params[index];
	}

	@SuppressWarnings("unchecked")
	public static <T> Class<T> getSuperGenericType(Class clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes) {

		for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				// superClass.getMethod(methodName, parameterTypes);
				return superClass.getDeclaredMethod(methodName, parameterTypes);
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			}
		}

		return null;
	}

	public static void makeAccessible(Field field) {
		if (!Modifier.isPublic(field.getModifiers())) {
			field.setAccessible(true);
		}
	}

	public static Field getDeclaredField(Object object, String filedName) {

		for (Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass
				.getSuperclass()) {
			try {
				return superClass.getDeclaredField(filedName);
			} catch (NoSuchFieldException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	public static Object invokeMethod(Object object, String methodName, Class<?>[] parameterTypes, Object[] parameters)
			throws InvocationTargetException {

		Method method = getDeclaredMethod(object, methodName, parameterTypes);

		if (method == null) {
			throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
		}

		method.setAccessible(true);

		try {
			return method.invoke(object, parameters);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static void setFieldValue(Object object, String fieldName, Object value) {
		Field field = getDeclaredField(object, fieldName);

		if (field == null)
			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");

		makeAccessible(field);

		try {
			field.set(object, value);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public static Object getFieldValue(Object object, String fieldName) {
		Field field = getDeclaredField(object, fieldName);

		if (field == null)
			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");

		makeAccessible(field);

		Object result = null;

		try {
			result = field.get(object);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return result;
	}
}

    数据库User Table:

©原文链接:https://blog.csdn.net/smile_Running/article/details/86767924

@作者博客:_Xu2WeI

@更多博文:查看作者的更多博文

posted @ 2019-02-06 13:37  爱写Bug的程序猿  阅读(3125)  评论(0编辑  收藏  举报