MyBatis3 通用CRUD的研究[二]

本文介绍了一种利用MyBatis实现的通用CRUD接口设计方法,通过定义基类简化了实体类和Mapper接口的开发过程。该方案支持Insert、Update、Delete等基本操作,并提供了基于泛型的SELECT方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这次把代码贴全吧

首先是Mapper接口的基类

package org.sol.util.mybatis;

import java.util.List;

import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;

/**
 * MyBatis CRUD基接口
 * @author ALLEN.HU
 *
 * @param <T> 处理的POJO对象
 */
public interface BaseMapper<T extends MyBatisPojo> {
	
	/**
	 * 基于泛型的SELECT的返回类型,无法达到运行时改变对象签名
	 * 目前无解 
	 * @param obj
	 * @return
	 */
	public List<T> select(T obj);
	
	public List<T> selectByPage(T obj);
	
	//@SelectProvider(type = SelectTemplate.class,method = "count")
	//public int count(T obj);
	
	/**
	 * Insert语句从CUDTemplate类中生成
	 * @param obj
	 */
	@InsertProvider(type = CUDTemplate.class,method = "insert")
	public void insert(T obj);
	
	/**
	 * Update语句从CUDTemplate类中生成
	 * @param obj
	 */
	@UpdateProvider(type = CUDTemplate.class,method = "update")
	public void update(T obj);
	
	/**
	 * Delete语句从CUDTemplate类中生成
	 * @param obj
	 */
	@DeleteProvider(type = CUDTemplate.class,method = "delete")
	public void delete(T obj);

}


然后是POJO的基类

package org.sol.util.mybatis;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import org.json.JSONObject;
import org.sol.util.mybatis.exception.PojoStructureException;

/**
 * MyBatis用POJO基类
 * @author Allen.Hu
 *
 */
public class MyBatisPojo implements Serializable{

	private static final long serialVersionUID = 1L;

	/**
	 * 获取POJO对应的表名
	 * 需要POJO中的属性定义@Table(name)
	 * @return
	 */
	public String tablename() {
		Table table = this.getClass().getAnnotation(Table.class);
		if(table != null)
			return table.name();
		else
			throw new PojoStructureException("undefine POJO @Table, need Tablename(@Table(name))");
	}
	
	/**
	 * 获取POJO中的主键字段名
	 * 需要定义@Id
	 * @return
	 */
	public String id() {
		for(Field field : this.getClass().getDeclaredFields()) {
			if(field.isAnnotationPresent(Id.class))
				return field.getName();
		}
		
		throw new RuntimeException("undefine POJO @Id");
	}

	/**
	 * 用于存放POJO的列信息
	 */
	private transient static Map<Class<? extends MyBatisPojo>,List<String>> columnMap = new HashMap<Class<? extends MyBatisPojo>, List<String>>();
	
	private boolean isNull(String fieldname) {
		try {
			Field field = this.getClass().getDeclaredField(fieldname);
			return isNull(field);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}
		
		return false;
	}
	
	private boolean isNull(Field field) {
		try {
			field.setAccessible(true);
			return field.get(this) == null;
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
		return false;
	}
	
	/**
	 * 用于计算类定义
	 * 需要POJO中的属性定义@Column(name)
	 */
	public void caculationColumnList() {
		if(columnMap.containsKey(this.getClass()))
			return;
		
		Field[] fields = this.getClass().getDeclaredFields();
		List<String> columnList = new ArrayList<String>(fields.length);
		
		for(Field field : fields) {
			if(field.isAnnotationPresent(Column.class))
				columnList.add(field.getName());
		}
		
		columnMap.put(this.getClass(), columnList);
	}
	
	/**
	 * 获取用于WHERE的 有值字段表
	 * @return
	 */
	public List<WhereColumn> returnWhereColumnsName() {
		Field[] fields = this.getClass().getDeclaredFields();
		List<WhereColumn> columnList = new ArrayList<WhereColumn>(fields.length);
		
		for(Field field : fields) {
			if(field.isAnnotationPresent(Column.class) && !isNull(field)) 
				columnList.add(new WhereColumn(field.getName(), field.getGenericType().equals(String.class)));
		}
		
		return columnList;
	}
	
	/**
	 * Where条件信息
	 * @author HUYAO
	 *
	 */
	public class WhereColumn {
		public String name;
		public boolean isString;
		
		public WhereColumn(String name,boolean isString) {
			this.name = name;
			this.isString = isString;
		}
	}
	
	/**
	 * 用于获取Insert的字段累加
	 * @return
	 */
	public String returnInsertColumnsName() {
		StringBuilder sb = new StringBuilder();
		
		List<String> list = columnMap.get(this.getClass());
		int i = 0;
		for(String column : list) {
			if(isNull(column))
				continue;
			
			if(i++ != 0)
				sb.append(',');
			sb.append(column);
		}
		return sb.toString();
	}
	
	/**
	 * 用于获取Insert的字段映射累加
	 * @return
	 */
	public String returnInsertColumnsDefine() {
		StringBuilder sb = new StringBuilder();
		
		List<String> list = columnMap.get(this.getClass());
		int i = 0;
		for(String column : list) {
			if(isNull(column))
				continue;
			
			if(i++ != 0)
				sb.append(',');
			sb.append("#{").append(column).append('}');
		}
		return sb.toString();
	}
	
	/**
	 * 用于获取Update Set的字段累加
	 * @return
	 */
	public String returnUpdateSet() {
		StringBuilder sb = new StringBuilder();
		
		List<String> list = columnMap.get(this.getClass());
		int i = 0;
		for(String column : list) {
			if(isNull(column))
				continue;
			
			if(i++ != 0)
				sb.append(',');
			sb.append(column).append("=#{").append(column).append('}');
		}
		return sb.toString();
	}
	

	public Integer getId(){return 0;}

	/**
	 * 转化POJO为JSON格式
	 * 需要org.json包支持,可以在json官网下载源码,或自己实现json编码
	 * @return
	 */
	public String toJSONString() {
		JSONObject json = new JSONObject(this);
		return json.toString();
	}
	
	/**
	 * 打印类字段信息
	 */
	@Override
	public String toString() {
		Field[] fields = this.getClass().getDeclaredFields();
		StringBuilder sb = new StringBuilder();
		sb.append('[');
		for(Field f : fields) {
			if(Modifier.isStatic(f.getModifiers()) || Modifier.isFinal(f.getModifiers()))
				continue;
			Object value = null;
			try {
				f.setAccessible(true);
				value = f.get(this);
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
			if(value != null)
				sb.append(f.getName()).append('=').append(value).append(',');
		}
		sb.append(']');
		
		return sb.toString();
	}
	
	/**
	 * 以下为一些分页信息,如不需要可以删除
	 */
	private int page;
	private int pageSize;

	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}
}


其中用到的Exception定义

package org.sol.util.mybatis.exception;

public class PojoStructureException extends RuntimeException{

	private static final long serialVersionUID = 1L;

	public PojoStructureException(String msg) {
		super(msg);
	}
	
	public PojoStructureException(String msg,Throwable e) {
		super(msg,e);
	}
}


最后是用于构建SQL的模板

package org.sol.util.mybatis;

import static org.apache.ibatis.jdbc.SqlBuilder.*;

public class CUDTemplate<T extends MyBatisPojo> {
	public String insert(T obj) {
		BEGIN();
		
		INSERT_INTO(obj.tablename());
		obj.caculationColumnList();
		VALUES(obj.returnInsertColumnsName(), obj.returnInsertColumnsDefine());

		return SQL();
	}
	
	public String update(T obj) {
		String idname = obj.id();
		
		BEGIN();
		
		UPDATE(obj.tablename());
		obj.caculationColumnList();
		SET(obj.returnUpdateSet());
		WHERE(idname + "=#{" + idname + "}");
		
		return SQL();
	}
	
	public String delete(T obj) {
		String idname = obj.id();
		
		BEGIN();
		
		DELETE_FROM(obj.tablename());
		WHERE(idname + "=#{" + idname + "}");
		
		return SQL();
	}
}


 

实际使用时,只需要构建一个继承MyBatisPOJO的实体对象,和一个继承BaseMapper的映射器就可以了

例子:

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;

import org.sol.util.mybatis.MyBatisPojo;

@Table(name = "testTable")
public class TestTable extends MyBatisPojo{

	private static final long serialVersionUID = 1L;

// 一个很简单的示例表,仅有2列,主键列id,和一个Varchar列name

	// 以@Id标识的字段,表示这个字段是主键
	@Id
	private Integer id;
	// 以@Column标识的字段,表示这个字段是一般列
	@Column
	private String name;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

}

对应的Mapper

// 只需要继承BaseMapper,就可以直接实现根据主键的Update,Insert,Delete操作
// 如果需要其他附加动作,也可以增加xml文件,完全没有冲突
public interface InfoShopMapper extends BaseMapper<TestTable>{
}

 

其他操作与MyBatis原始操作一样

 

另外,希望有高人能提供生成通用Select的办法

 

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值