Marco's Java 之【JDBC辅助类封装】

ORM基本思想

当我们接触到数据库和Java连接的内容时,不得不提到的一点就是ORM(Object Relational Mapping)思想,翻译过来就是对象关系映射,简单来说就是表结构中的字段和类中的属性对应映射,实现一条数据库记录对应一个JavaBean对象

添加數據的封装

现在我们封装一个方法,使得我们传入一个对象实参之后,对应的数据库可以对应的增加一条数据
假设,我们有一个Trolley购物车类和AddUtil类

public class Trolley {
	private int productID;
	private int quantity;
	
	public Trolley(int productID, int quantity) {
		super();
		this.productID = productID;
		this.quantity = quantity;
	}
	public int getProductID() {
		return productID;
	}
	public void setProductID(int productID) {
		this.productID = productID;
	}
	public int getQuantity() {
		return quantity;
	}
	public void setQuantity(int quantity) {
		this.quantity = quantity;
	}
}
public class AddUtil {
	//过滤方法为methodName的方法并放入List容器
	private static List<Method> getMatchedMethods(Object obj, String methodName) {
		Method[] methods = obj.getClass().getDeclaredMethods();
		List <Method> list = new ArrayList<>();
		for (int index = 0; index < methods.length; index++) {
			if (methods[index].getName().indexOf(methodName) != -1) {
				//Class returnType = methods[index].getReturnType();
				list.add(methods[index]);			
			}
		}
		return list;
	}
	public static  <T> void addData(T obj) {
		Connection conn = JDBCUtil.getConnection();
		//假设现在需要插入String sql = "insert into trolley(md_mid,trolley_quantity) values (..,..,..)";
		Map<String, Object> map = new HashMap<>();
	    Set<String> methodName = new HashSet<>();//用于存储方法的名称
		Class clz = obj.getClass();
		StringBuffer sql = new StringBuffer("insert into ");
		sql.append(clz.getSimpleName().toLowerCase());
		sql.append("(");
		List<Method> methodList = getMatchedMethods(obj, "get");
		Iterator<Method> it = methodList.iterator();
		while(it.hasNext()) {
			Method method = it.next();
			String attribute = method.getName().substring(3).toLowerCase();//从方法中获取属性名称
			try {
				System.out.println(method.getName());
				Object value = method.invoke(obj);
				System.out.println(value);
				map.put(attribute,value);
			} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
				e.printStackTrace();
			}
			sql.append(attribute);
			sql.append(",");
		}
		sql.setCharAt(sql.lastIndexOf(","), ')');//实现了这一部分insert into trolley(md_mid,trolley_quantity)
		sql.append("values(");
		
		List<Method> methodList2 = getMatchedMethods(obj, "get");
		Iterator<Method> it2 = methodList2.iterator();
		while(it2.hasNext()) {
			Method method = it2.next();
			String attribute = method.getName().substring(3).toLowerCase();//从方法中获取属性名称
			Object value = map.get(attribute);		
			sql.append(value);
			sql.append(",");
		}
		sql.setCharAt(sql.lastIndexOf(","), ')');	
		try {
			PreparedStatement ps = conn.prepareStatement(sql.toString());	
			System.out.println(sql.toString());
			ps.executeUpdate();
			JDBCUtil.realse(conn, ps);
		} catch (SQLException e) {
			e.printStackTrace();
		}	
	}
	
	public static void main(String[] args) {
		Trolley t = new Trolley(1100, 500);
		addData(t);
	}
}
	

但是细心的朋友发现,以上通过反射获取对象的get方法,并拆解get方法的全称,得到字段名(例如setProductID拆解之后可以获取ProductID字段),然后通过get方法获取属性的属性值也就是对应的数据库里面的字段值。
最后通过SQL语句将数据传输到数据库中。
但是上述方法有一个缺陷,就是我们的数据库的字段名称和Javabean类的属性值要一一对应才能实现对象到数据库的添加。当然我们也有相应的应对措施,例如约定一个规范,打个比方,类中的属性可以叫做 ProductID,
那么数据库中的字段名称可以命名为trolley_productid,或者product_id,这样我们可以新建一个方法,将类的属性名转为数据库的字段名称来进行调用。

但是!!最终极的方法是采用我们的==注解==方式,我们可以先定义一个注解来对这个Trolley类的属性做约束,并命名(类似于数据库的起别名)。(友情提示:如果对注解还不太熟的小伙伴可以先看我的另一篇讲解注解的文章 Marco’s Java 之【Annotation注解】)

@Target(value=ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
	String value() default "";
}

其次,我们可以将该注解放到我们需要注解的属性上方并命名

public class Trolley {
	@Column(value="md_mid")
	private int productID;
	@Column(value="trolley_quantity")
	private int quantity;
	
	public Trolley(int productID, int quantity) {
		super();
		this.productID = productID;
		this.quantity = quantity;
	}
	public int getProductID() {
		return productID;
	}
	public void setProductID(int productID) {
		this.productID = productID;
	}
	public int getQuantity() {
		return quantity;
	}
	public void setQuantity(int quantity) {
		this.quantity = quantity;
	}
}

最后还是建一个AddUtil类封装相应的Add方法,将内容进行大换血!

public class AddUtil {
	//通过该方法获取该对象的注解value,以及这个属性的值
	private static Map<String,Object> getAnnotations(Object obj) {
		Map<String,Object> map = new HashMap<>();	
		Field[] declaredFields = obj.getClass().getDeclaredFields();
		for (Field field : declaredFields) {
			Column anno = field.getAnnotation(Column.class);
			if(anno!=null){
				String attribute = anno.value();
				try {
					field.setAccessible(true);
					Object value = field.get(obj);
					map.put(attribute, value);
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}			
			}		
		}
		return map;
	}
	public static  <T> void addData(T obj) {
		Connection conn = JDBCUtil.getConnection();
		Map<String, Object> map = getAnnotations(obj);
		StringBuffer sql = new StringBuffer("insert into ");
		Class clz = obj.getClass();
		sql.append(clz.getSimpleName().toLowerCase());
		sql.append("(");
		Set entryset = map.entrySet();
		Iterator<Entry<String,Object>> it = entryset.iterator();
		while(it.hasNext()) {
			Entry<String,Object> entry = it.next();
			String attribute = entry.getKey();
			sql.append(attribute);
			sql.append(",");
		}
		sql.setCharAt(sql.lastIndexOf(","), ')');//实现了这一部分insert into trolley(md_mid,trolley_quantity)
		sql.append("values(");
		Set entryset2 = map.entrySet();
		Iterator<Entry<String,Object>> it2 = entryset2.iterator();
		while(it2.hasNext()) {
			Entry<String,Object> entry = it2.next();
			Object value = entry.getValue();
			sql.append(value);
			sql.append(",");
		}
		sql.setCharAt(sql.lastIndexOf(","), ')');//实现了这一部分insert into trolley(md_mid,trolley_quantity)	
		try {
			PreparedStatement ps = conn.prepareStatement(sql.toString());	
			ps.executeUpdate();
			JDBCUtil.realse(conn, ps);
		} catch (SQLException e) {
			e.printStackTrace();
		}
	public static void main(String[] args) {
		Trolley t = new Trolley(1100, 500);
		addData(t);
	}
}

查詢數據的封装

实际开发中,我们可能会需要查询这一个数据库中的多个表,并且将表中的数据导出来==。
那么我们可以通过将查询的内容进行封装,在Java中创建一个实体类让类中的属性和数据库中的字段映射起来

public class ResultMetaTest{
	public static <T> List<T>  queryData(Class<T> clz, String sql, Object...param) {
		Connection conn = JDBCUtil.getConnection();//创建连接对象
		
		try {
			PreparedStatement ps = conn.prepareStatement(sql);//创建操作数据库对象
			//设置条件判断中的值
			for(int i = 0; i < param.length; i++) {
				ps.setObject(i+1, param[i]);
			}
			ResultSet rs = ps.executeQuery();//获取结果集对象
			ResultSetMetaData meta = rs.getMetaData();//获取数据集元信息
			int column = meta.getColumnCount();//获取所搜寻的字段个数或者列数
			List<T> list = new ArrayList<>();//创建用于储存构建出来的对象的容器
			while(rs.next()) {
				Map<String,Object> map = new HashMap<>();//创建用于储存保存类的属性的map集合
				for(int i = 0; i < column; i++) {
					String columnName = meta.getColumnLabel(i+1);//得到每一列的或者每一个字段的名称
					Object obj = rs.getObject(columnName);//根据字段名称获取每一行对应的字段值
					map.put(columnName, obj);
				}
				if(!map.isEmpty()) {	
					T obj = clz.newInstance();//通过传入的类的Class对象创建这个类的对象
					Set <Entry <String,Object>> entryset = map.entrySet();
					for (Entry<String, Object> entry : entryset) {
						String atribute = entry.getKey();//提取这个类中的属性名称
						Object value = entry.getValue();//提取这个类中属性的值
						Field attribute = clz.getDeclaredField(atribute);
						attribute.setAccessible(true);//注意要设置权限为开放
						attribute.set(obj, value);//通过反射给对象赋值
					}
					list.add(obj);//将赋值完成的对象放入ArrayList容器中
				}				
			}
			JDBCUtil.realse(conn, ps, rs);//释放资源
			return list;
		} catch (SQLException | InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static void main(String[] args) throws Exception {
		String sql = "select u_uname as userName,u_pwd as password,"
				+ "u_tele as telePhone,u_realname as realName from userinfo where u_id = ?";
		List<User> list = queryData(User.class,sql,1);
		System.out.println(list);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值