通過反射實現Mybatis註解開發@Select

在mybatis中,可以通過註解@Select(sql語句)對接口進行註釋,並且實現開發,那麼,如何自己實現呢?

首先需要對註解和反射機制具有一定的瞭解。這些屬於基礎知識,這裏不贅述。

一、測試項目目錄結構

使用的測試數據庫是Oracle數據庫,使用的表是scott用戶下的dept表。(這裏使用什麼數據庫並沒有什麼意義)

Dept.java:

這是用來保存實體數據的類,查詢的數據最終會返回成一個Dept實體類的對象列表

JDBCUtil.java:

這裏封裝了JDBC,並且使用反射機制對sql的返回結果進行處理,從而生成實體類。

MapperTest.java:

相當於mybatis中的mapper接口

@param.java:

註解,用於註釋方法參數,這裏並沒有使用到

@Select.java

註解,用於註解mapper接口,代表一個sql查詢語句

conf.properties:

保存數據庫的連接信息。

 

二、JDBC的封裝

1)封裝jdbc連接

1.加載驅動和連接屬性

    private static Properties pro = new Properties();
	private static Connection conn;
	//在靜態代碼塊中加載jdbc驅動包,因爲這件事情在程序的運行過程中只需要執行一次
    //加載Properties文件,用於讀取
	static {
		try {
			pro.load(new FileInputStream("src/conf.properties"));
			Class.forName("oracle.jdbc.OracleDriver");
		} catch (ClassNotFoundException e) {
			System.out.println("驅動文件錯誤");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

2.獲取一個連接

//獲取連接對象
	public static Connection getConnection() {
		try {
//爲了高可用,只有當連接還未連接,或者連接已經關閉了,才重新創建連接
			if (conn == null || conn.isClosed()) {
				conn = DriverManager.getConnection(pro.getProperty("url"),
						pro.getProperty("user"), pro.getProperty("password"));
			} else
				;
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}

3.封裝查詢

    // 查詢結果並且返回一個對象數組
	public static List<Object> QueryResultBySQL(Class<?> T, String sql,
			Object... params) {
		List<Object> list = new ArrayList<Object>();
		PreparedStatement prsm = null;
		try {
			prsm = getConnection().prepareStatement(sql);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
//這裏爲了省事,封裝了一個方法用來給預編譯sql的?賦值
		setValues(prsm, params);
		try {
			prsm.executeQuery();
			ResultSet rs = prsm.getResultSet();
			Method[] methods = T.getDeclaredMethods();
			while (rs.next()) {
                //處理查詢結果,這裏寫的比較粗糙,但是能用
				Object obj = T.getConstructors()[0].newInstance();
				list.add(obj);
				for (Method method : methods) {
					if ("set"
							.equalsIgnoreCase(method.getName().substring(0, 3))) {
						Object o = rs.getObject(method.getName().substring(3));
						if (o instanceof java.math.BigDecimal) {
							BigDecimal number = (BigDecimal) o;
							method.invoke(obj, number.intValue());
						} else {
							method.invoke(obj, o);
						}
					}
				}
			}
			return list;
		} 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 (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
//用於給預編譯sql語句賦值
public static void setValues(PreparedStatement ps, Object[] objs) {
		if(objs!=null)
		for (int i = 0; i < objs.length; i++) {
			try {
				ps.setObject(i + 1, objs[i]);
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

 

 

2)編寫註解

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

//只有元註解Retention的值是Runtime註解才能在運行時被加載
@Retention(RUNTIME)
//Target的值是Method表示這個註解只能用來修飾方法
@Target(METHOD)
public @interface Select {
	String value();
}

3)編寫自己的Mapper

public interface MapperTest {
	
	@Select("select * from dept where deptno = ${deptno}  and dname = #{dename}") 
	public Dept selectEmpById(@param String deptno,@param String dname);
	

}

4)Dept實體類

public class Dept {
	private int deptno;
	private String dname;
	private String loc;
	@Override
	public String toString() {
		return "Dept [deptno=" + deptno + ", dname=" + dname + ", loc=" + loc
				+ "]";
	}
	public int getDeptno() {
		return deptno;
	}
	public void setDeptno(int deptno) {
		this.deptno = deptno;
	}
	public String getDname() {
		return dname;
	}
	public void setDname(String dname) {
		this.dname = dname;
	}
	public String getLoc() {
		return loc;
	}
	public void setLoc(String loc) {
		this.loc = loc;
	}

}

5)編寫測試類,使用反射機制來運行Mapper

package com.mybatis.demo1;

import java.lang.reflect.Method;
import java.util.List;

public class Test {

	public static void main(String[] args) throws ClassNotFoundException {
		// 獲取mapper類對象 ,異常拋出,不處理
		Class mapper = Class.forName("com.mybatis.demo1.MapperTest");
		// Map<Method,String> methodMap = new HashMap<Method,String>();

		// 獲取mapper的方法
		Method[] methods = mapper.getMethods();
		// 遍歷方法
		for (Method method : methods) {
			// 取出被select修飾的方法
			if (method.isAnnotationPresent(Select.class)) {
				// 獲取註解的內容
				String sql = method.getAnnotation(Select.class).value();

				// 假定兩個值
				String deptno = "10";
				String dname = "ACCOUNTING";
				// 現在把${}修飾的改成 ?,把#{} 修飾的改成常量
				for (int index = 0; index < sql.length(); index++) {
					if (sql.charAt(index) == '$') {
						if (sql.charAt(index + 1) == '{') {
							for (int i = index; i < sql.length(); i++) {
								if (sql.charAt(i) == '}') {
									// 修改成?
									String param = sql.substring(index, i+1);
									System.out.println("修改"+param+"改成?");
									sql = sql.substring(0, index) + "?" + sql.substring(i+1);
									System.out.println(sql);
									break;
								}
							}
						}

					} else if (sql.charAt(index) == '#') {
						if (sql.charAt(index + 1) == '{') {
							for (int i = index; i < sql.length(); i++) {
								if (sql.charAt(i) == '}') {
									// 修改成常量
									String param = sql.substring(index, i+1);
									System.out.println("修改"+param+"改成'常量值'");
									sql = sql.substring(0, index) +" '" +dname +"'"+ sql.substring(i+1);
									System.out.println(sql);
									break;
								}
							}
						}

					}
				}
				System.out.println("最終的SQL語句:\n"+sql);
				// 執行sql語句並且打印結果
				List l = JDBCUtil.QueryResultBySQL(com.mybatis.demo1.Dept.class, sql, deptno);
				System.out.println("查詢的結果:");
				for (Object o : l) {
					System.out.println(o);
				}
			}
		}

	}

}

 

三、最後的運行結果:

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章