使用註解和反射構建通用資料庫框架
下面我們寫一個操作資料庫框架的示例,從而熟悉註解,反射,泛型的使用。
通過實體類建立和刪除操作,因為操作資料庫中的表不同,那麼對應的實體類也不同,我們需要使用泛型來指定操作的實體類。使用註解使實體類和資料庫表列一一對應。
DbHelper.java
public class DbHelper extends SQLiteOpenHelper { private static String NAME = "db.db"; private static int VERSION = 1; public DbHelper(Context context) { super(context, NAME, null, VERSION); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
Dao.java
public interface Dao<T> { /** * 插入資料 * * @param t */ public long insert(T t); /** * 通過id刪除資料 * * @param id */ public int delete(Serializable id); /** * 通過id更新資料 * * @param t */ public int update(T t); /** * 查詢資料中所有資料 * * @return */ public List<T> finadAll(); /** * 建立表 */ public void createTable(); }
在其實現類DaoImp.java
其部分程式碼
在建立表的時候,如果此表已經存在,那麼就不需要建立,否則就建立此表public abstract class DaoImp<T> implements Dao<T> { private SQLiteDatabase db; public DaoImp(DbHelper helper) { super(); db = helper.getWritableDatabase(); } @Override public long insert(T t) { if (!isTableExists()) { return -1; } ContentValues values = new ContentValues(); fillContentValues(t, values);// 第一個引數標示資料的來源;第二個引數設定給誰 // 此處省略n行程式碼 return db.insert(getTableName(), null, values); } @Override public int delete(Serializable id) { if (!isTableExists()) { return -1; } return db.delete(getTableName(), getIdName(null) + "=?", new String[] { id.toString() }); } @Override public int update(T t) { if (!isTableExists()) { return -1; } ContentValues values = new ContentValues(); fillContentValues(t, values); return db.update(getTableName(), values, getIdName(t) + "=?", new String[] { getId(t) }); }
public boolean isTableExists() {
String sql = "select count(*) as c from sqlite_master where type ='table' and name ='"
+ getTableName() + "';";
Cursor cursor = db.rawQuery(sql, null);
if (cursor.moveToNext()) {
int count = cursor.getInt(0);
if (count > 0) {
return true;
}
}
return false;
}
這是查詢資料庫中所有的表,看指定的表是否存在。
通過bean建立表,使用的註解使實體類和表中列一一對應起來。
指定表名的註解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
String value();
}
指定表主鍵id註解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableId {
String value();
boolean isAutoIncrease();
}
指定列註解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
下面以一個Book.java實體類為示例,看看這些自定義註解的使用。
@TableName("book")
public class Book {
@TableId(value = "serialnum", isAutoIncrease = true)
@Column("serialnum")
private int serialNum;
@Column("name")
private String name;
@Column("des")
private String des;
public Book() {
super();
}
public Book(String name, String des) {
super();
this.name = name;
this.des = des;
}
public Book(int serialNum, String name, String des) {
super();
this.serialNum = serialNum;
this.name = name;
this.des = des;
}
public int getSerialNum() {
return serialNum;
}
public void setSerialNum(int serialNum) {
this.serialNum = serialNum;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
@Override
public String toString() {
return "Book [serialNum=" + serialNum + ", name=" + name + ", des="
+ des + "]";
}
}
在DaoImpl.java中建立表
@Override
public void createTable() {
String tableName = getTableName();
if (TextUtils.isEmpty(tableName)) {
return;
}
if (isTableExists()) {
return;
}
Map<String, String> columns = columnNames();
StringBuffer sb = new StringBuffer();
sb.append("CREATE TABLE ");
sb.append(tableName);
sb.append("(");
boolean flag = true;
if (columns != null) {
Set<String> keySet = columns.keySet();
Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext()) {
String name = iterator.next();
String type = columns.get(name);
if (flag) {
sb.append(name).append(" ").append(type);
flag = false;
} else {
sb.append(",").append(name).append(" ").append(type);
}
}
}
sb.append(")");
db.execSQL(sb.toString());
}
獲取列明和列型別map。
public Map<String, String> columnNames() {
Map<String, String> columns = null;
T t = getInstance();
Field[] fields = t.getClass().getDeclaredFields();
columns = new HashMap<String, String>();
for (Field field : fields) {
field.setAccessible(true);
Column columAn = field.getAnnotation(Column.class);
if (columAn != null) {
TableId idAn = field.getAnnotation(TableId.class);
if (idAn != null) {
if (idAn.isAutoIncrease()) {
columns.put(idAn.value(),
"integer primary key autoincrement");
} else {
columns.put(idAn.value(), "varchar(50)");
}
} else {
columns.put(columAn.value(), "varchar(50)");
}
}
}
return columns;
}
通過獲取實體類中註解的型別,通過field.getAnnotation(Column.class);獲取欄位上的註解,如果是Column是列,獲取其值,就是列名稱。如果是TableId表示表的主鍵,其值就是是否自定增長。
獲取表名
/**
* 獲取表名字
*
* @return
*/
public String getTableName() {
T t = getInstance();
TableName tableName = t.getClass().getAnnotation(TableName.class);
if (tableName != null) {
return tableName.value();
}
return null;
}
獲取TableName註解。來獲取表名。
建立實體類物件。
/**
* 建立實體的物件
*
* @return
*/
public T getInstance() {
Class clazz = getClass();// 正在執行
Type genericSuperclass = clazz.getGenericSuperclass();// 獲取支援泛型的父類
if (genericSuperclass instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass)
.getActualTypeArguments();
Class target = (Class) actualTypeArguments[0];
try {
return (T) target.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
在插入資料時候,通過傳入bean物件,然後向對應的列中插入資料。
private void fillContentValues(T m, ContentValues values) {
Field[] fields = m.getClass().getDeclaredFields();
for (Field item : fields) {
item.setAccessible(true);// 施暴
Column column = item.getAnnotation(Column.class);
if (column != null) {
TableId id = item.getAnnotation(TableId.class);
if (id != null) {
// 主鍵+自增
if (id.isAutoIncrease()) {
// 不需要設定資料到ContentValues
} else {
String key = column.value();
try {
String value = item.get(m).toString();// m.field
values.put(key, value);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
} else {
String key = column.value();
try {
String value = item.get(m).toString();// m.field
values.put(key, value);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
獲取bean的欄位陣列,先進行暴力反射,反正欄位是私有欄位,先判斷欄位上是否有Column註解,如果有,表示此欄位是和列對應,其註解對應的值就是表示的列名,然後通過field.get(m)獲取物件其欄位對應的值,然後條件到ContentValues物件中,values.put(key, value);key是註解Column對應的值,value是通過反射獲取物件的值。
在這裡還判斷是主鍵註解TableId,如果是自增,那麼不需要新增到values中,否則就向正常的列一樣,也要新增到values中。
private void fillFields(Cursor cursor, T m) {
Field[] fields = m.getClass().getDeclaredFields();
for (Field item : fields) {
item.setAccessible(true);
Column column = item.getAnnotation(Column.class);
if (column != null) {
String columnName = column.value();
int columnIndex = cursor.getColumnIndex(columnName);
String value = cursor.getString(columnIndex);
// 主鍵+自增:int long
if (item.getType() == int.class) {
try {
item.set(m, Integer.parseInt(value));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else if (item.getType() == long.class) {
try {
item.set(m, Long.parseLong(value));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} else {
try {
item.set(m, value);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
將遊標中的查詢出來的值,封裝到bean中,即實體類中。
獲取bean中的Column註解,然後獲取其值(類名),通過columnvalue=cursor.getColumnIndex(columnName)獲取此列在遊標中的值,然後通過field.set(bean,columnvalue),設定給傳進來的bean物件欄位值。
private String getId(T t) {
if (t == null) {
t = getInstance();
}
Field[] fields = t.getClass().getDeclaredFields();
for (Field item : fields) {
item.setAccessible(true);
TableId id = item.getAnnotation(TableId.class);
if (id != null) {
try {
return item.get(t).toString();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return null;
}
獲取主鍵的對應的列名,如果前面看通了,那麼這個方法自然也就明白。其實就是再次判斷bean類欄位上的註解。如果是TableId,那麼就獲取其值,就是表中列對應的列名。
下面介紹一個使用步驟:
BookImpl.java
public class BookImpl extends DaoImp<Book> {
public BookImpl(DbHelper helper) {
super(helper);
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/create_table"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="建立表" />
<Button
android:id="@+id/find_all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="查詢" />
<Button
android:id="@+id/insert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="插入" />
<Button
android:id="@+id/update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="修改" />
<Button
android:id="@+id/delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="刪除" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity implements OnClickListener {
private DaoImp<Book> bookDao;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
DbHelper helper = new DbHelper(MainActivity.this);
bookDao = new BookImpl(helper);
}
private void initView() {
Button create_table = (Button) findViewById(R.id.create_table);
create_table.setOnClickListener(this);
Button delete = (Button) findViewById(R.id.delete);
delete.setOnClickListener(this);
Button update = (Button) findViewById(R.id.update);
update.setOnClickListener(this);
Button insert = (Button) findViewById(R.id.insert);
insert.setOnClickListener(this);
Button find_all = (Button) findViewById(R.id.find_all);
tv = (TextView) findViewById(R.id.tv);
find_all.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.create_table:
createTable();
break;
case R.id.find_all:
findAll();
break;
case R.id.insert:
insert();
break;
case R.id.delete:
delete();
break;
case R.id.update:
update();
break;
default:
break;
}
}
private void update() {
bookDao.update(new Book(1, "updateName", "updateDes"));
}
private void delete() {
bookDao.delete(2);
}
private void insert() {
Book b1 = new Book("第一本", "第一本描述");
Book b2 = new Book("第二本", "第二本描述");
Book b3 = new Book("第三本", "第三本描述");
bookDao.insert(b1);
bookDao.insert(b2);
bookDao.insert(b3);
}
private void findAll() {
List<Book> finadAll = bookDao.finadAll();
StringBuffer sb = new StringBuffer();
tv.setText("");
if (finadAll != null) {
for (Book book : finadAll) {
sb.append(book.toString()).append(" \n ");
}
tv.setText(sb.toString());
}
}
private void createTable() {
bookDao.createTable();
}
}
DaoImp<Book> bookDao = new BookImpl(helper);獲取book表操作類
bookDao.createTable();建立表
bookDao.insert(b3);插入一條記錄
bookDao.delete(2);刪除id為2的記錄
bookDao.update(new Book(1, "updateName", "updateDes"));更新id為1的記錄。
效果圖:
相關推薦
使用註解和反射構建通用資料庫框架
下面我們寫一個操作資料庫框架的示例,從而熟悉註解,反射,泛型的使用。 通過實體類建立和刪除操作,因為操作資料庫中的表不同,那麼對應的實體類也不同,我們需要使用泛型來指定操作的實體類。使用註解使實體類和資料庫表列一一對應。 DbHelper.java public
java註解和反射的結合使用
分享 spa tac over ace 註解 [] sys string 首先反射註解,那麽保留策略必須是Runtime,[email protected]/* */(RetentionPolicy.RUNTIME) ①定義一個註解類 @Retention(R
使用自定義註解和反射 ,自動生成查詢語句
runt entity forname == rop ava stat pri string 1.自定義表名註解 package com.lf.annotation; import java.lang.annotation.ElementType; import jav
JAVA 註解和反射
his get jvm ava tom instance SM 通過 調用 通過反射來獲取類 Class MyTest{ private String name; public String showName{ System.out.prin
註解和反射操作註解
什麼是註解? • Annotation是從JDK5.0開始引入的新技術。 • Annotation的作用: – 不是程式本身,可以對程式作出解釋。(這一點,跟註釋沒什麼區別) – 可以被其他程式(比如:編譯器等)讀取。(註解資訊處理流程,是註解和註釋的重大區別 。如果沒有註解資訊處理流程,則註解毫無
註解和反射
一、註解 英文:Annotation 1.1 註解的概念 &
理解Web框架,和如何構建一個CSS框架
“大量重置”瀏覽器預設風格,比如,設定所有元素的margin和padding為0,去掉框架(framesets)和圖片(images)的border,等等。 以基線對齊。這包括諸如設定塊級元素的margins相同的(或多個)基準行高,如段落(paragraph)、頭(header)、以及列表(list)
通過泛型和反射構建一個簡單的集合操作工具類
平時在操作集合物件的時候(比如List);我想一次新增大於一個數據的時候,往往需要通過一個集合物件呼叫兩次add方法,比如: List<Person> personList=new ArrayList<>(); Person p1=n
110_註解和反射
[toc][https://www.bilibili.com/video/BV1p4411P7V3](https://www.bilibili.com/video/BV1p4411P7V3) # 註解 java.lang.annotation ## 什麼是註解 1. Annotation是從JDK5.0
net 和Mono 構建的HTTP服務框架
ots .config app pac spn 請求方法 park 找不到 get Nancy是一個基於.net 和Mono 構建的HTTP服務框架,是一個非常輕量級的web框架。 設計用於處理 DELETE, GET, HEAD, OPTIONS, POST,
Android開發——資料庫框架Suger遇到的大坑(Gson和Suger的複用Bean請見“大坑三”)
Android開發——資料庫框架Suger遇到的大坑(Gson和Suger的複用Bean請見“大坑三”) 大坑一 自己寫了一個Demo按照官網以及GitHub上Suger的使用步驟完整走下來,Demo閃退,以插入資料為例 User user = new User("liao",
教你如何構建非同步伺服器和客戶端的 Kotlin 框架 Ktor
Ktor 是一個使用 Kotlin 以最小的成本快速建立 Web 應用程式的框架。 Ktor 是一個用於在連線系統(connected systems)中構建非同步伺服器和客戶端的 Kotlin 框架。它由 Kotlin 團隊建立,因此,它充分利用了 Kotlin 的語言特性,為開發者提供出色的體驗和執
反射、註解和動態代理
反射是指計算機程式在執行時訪問、檢測和修改它本身狀態或行為的一種能力,是一種超程式設計語言特性,有很多語言都提供了對反射機制的支援,它使程式能夠編寫程式。Java的反射機制使得Java能夠動態的獲取類的資訊和呼叫物件的方法。 一、Java反射機制及基本用法 在Java中,Class(類型別)是反射程式設計的起
greenDao 資料庫框架簡單使用和Fresco 簡單載入圖片
首先 在專案下 -----------在repositories的括號里加入倉庫---- mavenCentral() ------------- 在dependencies的括號里加入外掛--------- classpath ‘org.greenrobot:
應用SuperIO(SIO)和開源跨平臺物聯網框架ServerSuperIO(SSIO)構建系統的整體方案
SSIO的更新 在SSIO上增加了UDP通訊方式,可以到Github上下載原始碼。在原來的專案中,遠端的裝置與中心站的資料互動並沒有使用過UDP方式。這種短連線的通訊鏈路,不容易維護,主要體現在:(1)持續的資料互動能力。(2)對現場裝置進行長時間的維護和校準。(3)SSIO要協調裝置、
《物聯網框架ServerSuperIO教程》- 23.動態資料介面增加快取,提高資料輸出到OPCServer和(實時)資料庫的效率
22.1 概述及要解決的問題 裝置驅動有DeviceDynamic介面,可以繼承並增加新的實時資料屬性,每次通訊完成後更新這些屬性資料。原來是通過DeviceDynamic介面實體類反射的方式獲得最新的實時資料,並輸出到關係資料庫、實時資料庫和OPC Server等介面。 但是
java泛型詳解和反射泛型通用BaseDao實現
一 泛型的基本概念 1.1什麼是泛型? 泛型,即“引數化型別”。一提到引數,最熟悉的就是定義方法時有形參,然後呼叫此方法時傳遞實參。那麼引數化型別怎麼理解呢?顧名思義,就是將型別由原來的具體的型別引數化,類似於方法中的變數引數,此時型別也定義成引數形式(可以
java語言基礎--列舉,註解,正則和反射
註解 @Retention(RetentionPolicy.RUNTIME)//註解保留策略 public @interface MyAnno { String str(); int val(); } @MyAnno(str = "測試註解",val = 100)
java語言基礎--枚舉,註解,正則和反射
ota 獲取 -- tty ide 並不是 system ret 測試 註解 @Retention(RetentionPolicy.RUNTIME)//註解保留策略 public @interface MyAnno { String str(); int
通用匯入工具類,通過poi和反射實現
將檔案從前端上傳到後端,就不說了,我的文章裡面有上傳的,剛開始寫,如果有問題歡迎批評指正首先,先說一下用法,因為之前每增加一個匯入模板就要單獨開發,比較浪費時間,所以單獨搞了個通用類,引數有待解析檔案,輸出的類,欄位陣列,開始行數,然後返回一個List1.我們已經獲取到這個檔