经过几天的业余开发,今天终于到ORM对业务api本身的实现了,首先实现第一个查询的api
因为Java的泛型不纯,所以无法用只带泛型的方式实现api,对查询类的api做了调整,第一个参数要求传入实体对象
首先补充基础方法
反射工具类,用来给实体设置属性值
package LIS.Core.Util;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.net.URL;
import java.net.URLClassLoader;
//反射工具类
public class ReflectUtil {
//设置对象指定属性名字的值
public static void SetObjValue(Object obj,String name,Object val)
{
try {
Class c = obj.getClass();
//得到列信息
Field declaredField = c.getDeclaredField(name);
//布尔的处理
if(declaredField.getType()==Boolean.class) {
if(val.toString()=="1")
{
val=Boolean.TRUE;
}
else if(val.toString()=="0")
{
val=Boolean.FALSE;
}
else
{
val=Boolean.TRUE;
}
}
//布尔的处理
else if(declaredField.getType()==boolean.class) {
if(val.toString()=="1")
{
val=true;
}
else if(val.toString()=="0")
{
val=false;
}
else
{
val=true;
}
}
//布尔的处理
else if(declaredField.getType()==int.class) {
if(val==null)
{
val=0;
}
}
declaredField.set(obj, val);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
///
/// 用类型全名和程序集全名获得类型
///
/// 类型全名
/// 程序集名
///
public static Class GetType(String typeName, String assemblyName)
{
try {
//得到根路径
Class<?> clazz = ReflectUtil.class;
ClassLoader classLoader = clazz.getClassLoader();
URL resourceURL1 = classLoader.getResource("");
String bashePath = resourceURL1.getFile();
//组装成jar包路径
String jarPath=bashePath+assemblyName+".jar";
File file = new File(jarPath);
if (!file.exists()) {
throw new Exception("未能找到"+jarPath+"的文件");
}
//反射得到类型
//自己生成jar包路径
URL url = file.toURI().toURL();
URL[] urls = new URL[]{url};
//加载程序集
URLClassLoader loader = new URLClassLoader(urls);
//加载类
Class c = loader.loadClass(typeName);
if(c!=null)
{
return c;
}
else
{
throw new Exception("未能构建类型"+typeName);
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
}
HashTable转参数列表工具类,把老的HashTable传参数转换为内部ParaDto
package LIS.Core.Util;
import LIS.Core.Dto.ParamDto;
import java.util.List;
import java.util.HashMap;
import java.util.*;
import java.util.Hashtable;
public class HashToParam {
//哈希表得到参数列表
public static List<ParamDto> GetParam(Hashtable hs)
{
List<ParamDto> retList=new ArrayList<ParamDto>();
Enumeration keys = hs.keys();
while(keys.hasMoreElements()) {
String str = (String) keys.nextElement();
ParamDto dto=new ParamDto();
dto.Key=str;
dto.Value=hs.get(str);
retList.add(dto);
}
return retList;
}
}
参数实体,传sql参数用
package LIS.Core.Dto;
//ORM参数对象
public class ParamDto {
///
/// 关键字段名称
///
public Object Key;
///
/// 关键字段值
///
public Object Value;
///构造函数
public ParamDto()
{
}
//构造函数
public ParamDto(Object key, Object value)
{
this.Key = key;
this.Value = value;
}
}
ORM的FindAll实现
package LIS.DAL.ORM.EntityManager;
import LIS.Core.Context.ObjectContainer;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.List;
import java.util.*;
import LIS.Core.Dto.*;
public class EntityManagerImpl implements LIS.DAL.ORM.EntityManager.IEntityManager {
///
/// 存会话信息
///
LIS.Model.Bussiness.Sessions Session=null;
///
/// 开启事务,该方法初始化一个新的事务
///
public void BeginTransaction()
{
}
///
/// 数据查询
///
/// 实体类型
/// 传入一个空的或者非空的实体对象
/// 参数哈希表,数据库列名称和值的键值对
/// 排序字段,如RowID ASC,Name DESC
/// 页面大小。为-1,无条件查询所有数据
/// 页码。为-1,无条件查询所有数据
/// 对象集合
public <T> List<T> FindAll(T model,Hashtable param, String orderField, int pageSize, int pageIndex)
{
List<T> retList = new ArrayList<T>();
//建立连接
Connection conn = null;
//command
PreparedStatement stmt = null;
try {
Class c = model.getClass();
//转换参数
List<ParamDto> para=LIS.Core.Util.HashToParam.GetParam(param);
//得到数据库驱动工厂
LIS.DAL.ORM.DBUtility.IDbFactory factory= LIS.Core.Context.ObjectContainer.GetTypeObject("LisMianDbFactory");
//得到表信息
LIS.DAL.ORM.Common.TableInfo tableInfo = LIS.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(model);
//得到sql语句
String sql = LIS.DAL.ORM.Common.ModelToSqlUtil.GetSelectSqlByTableInfo(factory, tableInfo, para, null, null, orderField, false);
//连接串,最后的是数据库名称
String url = factory.GetConnectionString();
//用户
String user = factory.GetUserName();
//密码
String password = factory.GetUserPass();
//加载驱动
factory.LoadDriver();
//数据库连接
conn = DriverManager.getConnection(url,user,password);
stmt = conn.prepareStatement(sql);
//设置数据参数
LIS.DAL.ORM.DBUtility.DBParaUtil.SetDBPara(stmt,para);
//执行sql得到结果集
ResultSet rs = stmt.executeQuery();
// 处理查询结果
while (rs.next()) {
//一行数据
T oneRow = (T) c.newInstance();
//循环读取列数据放入实体中
for(int j=0;j<tableInfo.ColList.size();j++)
{
String ColName=tableInfo.ColList.get(j).Name;
Object val=rs.getObject(ColName);
//设置属性值
LIS.Core.Util.ReflectUtil.SetObjValue(oneRow,ColName,val);
}
retList.add(oneRow);
}
// 关闭 ResultSet、Statement 和 Connection 对象
rs.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally {
// 关闭资源
try {
if (stmt != null)
{
stmt.close();
}
}
catch (Exception se2) {
}
try {
if (conn != null)
{
conn.close();
}
}
catch (Exception se2) {
}
}
return retList;
}
///
/// 查询测试
///
public void DBSelectTest()
{
LIS.DAL.ORM.DBUtility.IDbFactory factory= LIS.Core.Context.ObjectContainer.GetTypeObject("LisMianDbFactory");
//连接串,最后的是数据库名称
String url = factory.GetConnectionString();
//用户
String user = factory.GetUserName();
//密码
String password = factory.GetUserPass();
//建立连接
Connection conn = null;
//command
PreparedStatement stmt = null;
try {
//加载驱动
factory.LoadDriver();
conn = DriverManager.getConnection(url,user,password);
//编译和执行SQL语句,传输SQL参数查询1997-2000行
String sql = "SELECT * FROM dbo.SYS_Form where \"RowID\">? and \"RowID\";";
stmt = conn.prepareStatement(sql);
stmt.setInt(1,1997);
stmt.setInt(2,2000);
//结果集
ResultSet rs = stmt.executeQuery();
// 处理查询结果
while (rs.next()) {
//取列数据
int RowID = rs.getInt("RowID");
String CName = rs.getString("CName");
String Path = rs.getString("Path");
//输出
System.out.println(RowID + "\t" + CName + "\t" + Path);
}
// 关闭 ResultSet、Statement 和 Connection 对象
rs.close();
}
catch (Exception ex) {
// 处理 JDBC 异常
ex.printStackTrace();
}
finally {
// 关闭资源
try {
if (stmt != null)
{
stmt.close();
}
}
catch (Exception se2) {
}
try {
if (conn != null)
{
conn.close();
}
}
catch (Exception se2) {
}
}
}
/**
* Query data object by primary key ID, mainly used for writing business logic with SQL.
* The difference between this method and GetById is that it has an internal caching mechanism.
* @param Entity type
* @param id Object RowID
* @return Data object
*/
public <T> T dolerGet(Object id) {
T model=null;
model.getClass();
//Class> type = T.class;
//String typeName = type.getSimpleName();
//System.out.println(typeName);
return null;
}
///测试SQL生成
public <T> void InsertSqlTest1()
{
try {
T model=null;
Class c=model.getClass();
model=(T)c.newInstance();
LIS.DAL.ORM.Common.TableInfo tableInfo = LIS.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(model);
LIS.DAL.ORM.DBUtility.IDbFactory factory = LIS.Core.Context.ObjectContainer.GetTypeObject("LisMianDbFactory");
String sql = LIS.DAL.ORM.Common.ModelToSqlUtil.GetSelectSqlByTableInfo(factory, tableInfo, null, null, null, "", true);
System.out.println(sql);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
///测试SQL生成
public <T> void InsertSqlTest(T model)
{
try {
//Type type = EntityManagerImpl.class.getClass().getGenericSuperclass();
//Class c = type.getClass();
//System.out.println(c.getName());
//System.out.println(model.getClass().getName());
LIS.DAL.ORM.Common.TableInfo tableInfo = LIS.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(model);
LIS.DAL.ORM.DBUtility.IDbFactory factory = LIS.Core.Context.ObjectContainer.GetTypeObject("LisMianDbFactory");
String sql = LIS.DAL.ORM.Common.ModelToSqlUtil.GetSelectSqlByTableInfo(factory, tableInfo, null, null, null, "", true);
System.out.println(sql);
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
///
/// 保存对象
///
/// 实体类型
/// 实体对象
/// 影响行数
public <T> int Save(T entity)
{
return 0;
}
}
实体转Sql的工具类
package LIS.DAL.ORM.Common;
import LIS.Core.CustomAttributes.*;
import LIS.Core.Dto.*;
import LIS.Core.Dto.ParamDto;
import java.util.*;
import java.util.List;
import LIS.DAL.ORM.Common.TableInfo;
import LIS.DAL.ORM.DBUtility.IDbFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import LIS.DAL.ORM.Common.ColumnInfo;
import LIS.DAL.ORM.Common.TableInfo;
import LIS.Core.Util.ReflectUtil;
import LIS.Core.CustomAttributes.TableAttribute;
//通过实体类型得到SQL的工具类
public class ModelToSqlUtil {
//通过实体对象得到表信息
public static TableInfo GetTypeInfo(Object model) {
if (model == null) {
return null;
}
try {
//返回的对象
TableInfo tableInfo = new TableInfo();
Class c = model.getClass();
//得到表特性
Annotation[] annoList = c.getAnnotations();
if (annoList != null && annoList.length > 0) {
for (int i = 0; i < annoList.length; i++) {
//表特性
if (annoList[i] instanceof TableAttribute) {
tableInfo.TableInfo = (TableAttribute) annoList[i];
}
//唯一特性
else {
tableInfo.UniqueList.add((UniqueAttribute) annoList[i]);
}
}
}
//得到列信息
Field[] declaredFields = c.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
LIS.DAL.ORM.Common.ColumnInfo col = new LIS.DAL.ORM.Common.ColumnInfo();
FrekeyAttribute fk = declaredFields[i].getAnnotation(FrekeyAttribute.class);
col.FkInfo = fk;
col.Name = declaredFields[i].getName();
col.ColType = declaredFields[i].getType();
col.Value = declaredFields[i].get(model);
tableInfo.ColList.add(col);
}
return tableInfo;
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
//通过表信息和参数列表组装查询SQL
//factory:驱动工厂
//tableInfo:表信息
//para:参数
//operList:参数对应的操作符列表
//linkList:多个参数之间连接的操作符 and or这种
//orderBySql:Order By的SQL语句
//IsFk:是否组装外键查询的SQL
public static String GetSelectSqlByTableInfo(IDbFactory factory,TableInfo tableInfo, List<ParamDto> para,List<String> operList,List<String> linkList, String orderBySql,Boolean IsFk)
{
StringBuilder sb=new StringBuilder();
sb.append("select ");
//是否含有序号列
boolean HasSequence=false;
boolean HasSeqNum=false;
//组装查询列
for(int i=0;i<tableInfo.ColList.size();i++)
{
//存列名
String columnName = tableInfo.ColList.get(i).Name;
if(columnName=="Sequence")
{
HasSequence=true;
}
else if(columnName=="SeqNum")
{
HasSeqNum=true;
}
//组装查询列
if(i==0)
{
sb.append(factory.DealPropertyName(columnName));
}
else
{
sb.append(","+factory.DealPropertyName(columnName));
}
//组装外键查询信息
if(IsFk==true&&tableInfo.ColList.get(i).FkInfo!=null) {
FrekeyAttribute fkAttr=tableInfo.ColList.get(i).FkInfo;
String refTableName=factory.DealTableName(GetTableName(ReflectUtil.GetType("LIS.Model.Entity." + fkAttr.Name(), "LIS.Model")));
sb.append("," + "(select " + factory.DealPropertyName(fkAttr.AssociaField()) + " from " + refTableName + " where ti." + factory.DealPropertyName(columnName) + "=" + refTableName + "." + factory.DealPropertyName(fkAttr.RefColumnName()) + ") as " + factory.DealPropertyName(columnName + "_" + fkAttr.Name() + "_" + fkAttr.AssociaField()));
//如果有拉取字段1,查询拉取字段
if (fkAttr.AssociaField1() != "")
{
sb.append("," + "(select " + factory.DealPropertyName(fkAttr.AssociaField1()) + " from " + refTableName + " where ti." + factory.DealPropertyName(columnName) + "=" + refTableName + "." + factory.DealPropertyName(fkAttr.RefColumnName()) + ") as " + factory.DealPropertyName(columnName + "_" + fkAttr.Name() + "_" + fkAttr.AssociaField1()));
}
//如果有拉取字段2,查询拉取字段
if (fkAttr.AssociaField2() != "")
{
sb.append("," + "(select " + factory.DealPropertyName(fkAttr.AssociaField2()) + " from " + refTableName + " where ti." + factory.DealPropertyName(columnName) + "=" + refTableName + "." + factory.DealPropertyName(fkAttr.RefColumnName()) + ") as " + factory.DealPropertyName(columnName + "_" + fkAttr.Name() + "_" + fkAttr.AssociaField2()));
}
}
}
sb.append(" from " + factory.DealTableName(tableInfo.TableInfo.Name()) + " ti ");
//组装查询参数
if(para!=null&¶.size()>0)
{
sb.append(" where ");
for(int i=0;i<para.size();i++)
{
String oper="=";
if(operList!=null&&operList.size()>i)
{
oper=operList.get(i);
}
String link="and";
if(operList!=null&&operList.size()>i-1)
{
link=operList.get(i-1);
}
if(i==0) {
sb.append(factory.DealPropertyName(para.get(i).Key.toString()) + oper + factory.DealSqlPara(para.get(i).Key.toString()));
}
else
{
sb.append(" "+link+" "+factory.DealPropertyName(para.get(i).Key.toString()) + oper + factory.DealSqlPara(para.get(i).Key.toString()));
}
}
}
//存组装的排序sql
String strSort = "";
//如果传入了排序字段,组装排序语句
if (orderBySql != null && orderBySql.length() > 0)
{
//用来存处理的排序串
String dealStr = "";
//先分割多个排序条件
String[] strList = orderBySql.split(",");
for (int m = 0; m < strList.length; m++)
{
//分开多个排序条件
if (m > 0)
{
dealStr += ",";
}
//分开字段名称和升降序
String[] strSubList = strList[m].split(" ");
//处理字段名称
dealStr += factory.DealPropertyName(strSubList[0]);
//组装处理的串
for (int n = 1; n < strSubList.length; n++)
{
dealStr += " " + strSubList[n];
}
}
//组装排序串
strSort = " Order By " + dealStr;
}
else
{
if (HasSequence)
{
strSort = " Order By " + factory.DealPropertyName("Sequence") + " ASC";
}
else if (HasSeqNum)
{
strSort = " Order By " + factory.DealPropertyName("SeqNum") + " ASC";
}
else
{
strSort = "";
}
}
sb.append(strSort);
return sb.toString();
}
//通过实体类型得到实体表名称
private static String GetTableName(Class c)
{
//存表名
String strTableName = "";
//得到表特性
TableAttribute tableInfo = null;
//得到表特性
Annotation[] annoList = c.getAnnotations();
if (annoList != null && annoList.length > 0) {
for (int i = 0; i < annoList.length; i++) {
//表特性
if (annoList[i] instanceof TableAttribute) {
tableInfo = (TableAttribute) annoList[i];
strTableName=tableInfo.Name();
break;
}
}
}
return strTableName;
}
}
数据库驱动工厂,增加得到用户名和密码的方法接口
package LIS.DAL.ORM.DBUtility;
//数据驱动层接口,ORM基于此加载驱动和执行SQL
public interface IDbFactory {
//得到数据库类型
String GetStrDbType();
//得到数据库连接串
String GetConnectionString();
//得到数据库用户名
String GetUserName();
//得到数据库密码
String GetUserPass();
//得到返回查询的RowID的SQL语句
String GetReturnRowIDSql();
//处理表名称,用来适配不同数据库间的属性命名差异
String DealTableName(String tableName);
//处理属性名字
String DealPropertyName(String propertyName);
//DealSqlPara
String DealSqlPara(String propertyName);
//加载驱动
void LoadDriver();
}
调用测试,这里引入了阿里的对象转JSON库,fastjson
package com.company;
//import org.apache.commons.configuration.ConfigurationException;
//import org.apache.commons.configuration.PropertiesConfiguration;
import LIS.Model.Entity.SYSForm;
import LIS.Model.Entity.SYSUser;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
import java.net.URL;
import java.util.List;
import java.util.HashMap;
import java.util.*;
import com.alibaba.fastjson.*;
public class Main {
public static void main(String[] args) {
//用容器的配置xml初始化容器
LIS.Core.Context.ObjectContainer.InitIoc();
//ORM通过容器取数据库驱动工厂
LIS.DAL.ORM.EntityManager.EntityManagerImpl orm=new LIS.DAL.ORM.EntityManager.EntityManagerImpl();
//执行查询测试
orm.DBSelectTest();
//测试通过实体得到SQL语句
orm.InsertSqlTest(new SYSForm());
orm.InsertSqlTest(new SYSUser());
//调用ORM的FindAll测试
Hashtable hs=new Hashtable();
hs.put("Code","QC");
List<SYSForm> formList=orm.FindAll(new SYSForm(),hs,"RowID desc",-1,-1);
Object json=JSONObject.toJSON(formList);
System.out.println("查询的LIST数据:"+json.toString());
}
}
把依赖的不稳定搞定后就快多了,轻松加愉快,哈哈。不过发现泛型不如C#强,方法不支持默认参数,尤其是方法不支持默认参数这个真不像一个现代语言,总体使用语法特性方面和工程依赖方面和IDE体验和C#比差多了,末日黄花喽,官方闭源,语法古老