入职新公司 选定了mybatis作为orm框架,mybatis的好处简单明了直接写sql语句就行,但是对于已经习惯了hibernate的我来说mybatis每个单表查询都要新建接口和xml映射文件就有点麻烦了,我在想能不能和hibernate一样直接调用save(),update(),query()方法就直接能执行dml语句呢,于是尝试封装mybatis做一个基础的mapper。
在这里使用mybatis java api的 provider动态执行sql
basemapper接口
import java.util.Map;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;
import com.github.pagehelper.Page;
/**
* 通用mapper
* @author zwt
*
*/
public interface MybaseMapper {
@InsertProvider(method = "saveEntity", type = com.huadi.xcx.dao.provider.MybaseProvider.class)
public int saveEntity(String tableName,T t);
@UpdateProvider(method = "updateEntity", type = com.huadi.xcx.dao.provider.MybaseProvider.class)
public int updateEntity(String tableName,T t,Map params);
@SelectProvider(method = "queryAllByParams", type = com.huadi.xcx.dao.provider.MybaseProvider.class)
public List
mapper对应的provider
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.ibatis.jdbc.SQL;
import com.huadi.xcx.common.util.FieldUtils;
/**
* 通用provider
* @author zwt
*
*/
public class MybaseProvider{
public String saveEntity(String tableName,T t) throws Exception {
Field[] fields =t.getClass().getDeclaredFields();
return new SQL(){
{
INSERT_INTO(tableName);
for(Field f:fields) {
f.setAccessible(true);
String key=f.getName();
Object value =f.get(t);
if(value!=null) {
VALUES(f.getName(), "#{t."+key+"}");
}
}
}
}.toString();
}
public String updateEntity(String tableName,T t,Map params) throws Exception {
if(params==null || params.keySet().size()<1)
{
throw new Exception("updateEntity 方法必须有条件参数");
}
Field[] fields =t.getClass().getDeclaredFields();
return new SQL(){
{
UPDATE(tableName);
for(Field f:fields) {
f.setAccessible(true);
String key=f.getName();
Object value =f.get(t);
if(value!=null) {
SET(f.getName()+" = #{t."+key+"}");
}
}
if(params !=null )
{
Set keys=params.keySet();
Iterator it=keys.iterator();
while(it.hasNext()) {
String key= it.next();
String filedName=FieldUtils.UnderlineToHump(key);
for(Field f:fields) {
if(filedName.equals(f.getName()))
{
if(String.class.toString().equals(f.getGenericType().toString()))
{
WHERE("to_char("+key+") = #{params."+key+"}");
}else
{
WHERE(key+" = #{params."+key+"}");
}
break;
}
}
}
}
}
}.toString();
}
public String queryAllByParams(Class> cls,String tableName,Map params) {
return queryPageByParams(cls,tableName,params);
}
public String queryPageByParams(Class> cls,String tableName,Map params) {
Field[] fields =cls.getDeclaredFields();
return new SQL() {
{
SELECT("*");
FROM(tableName);
if(params !=null )
{
Set keys=params.keySet();
Iterator it=keys.iterator();
while(it.hasNext()) {
String key= it.next();
String filedName=FieldUtils.UnderlineToHump(key);
for(Field f:fields) {
if(filedName.equals(f.getName()))
{
if(String.class.toString().equals(f.getGenericType().toString()))
{
WHERE("to_char("+key+") = #{params."+key+"}");
}else
{
WHERE(key+" = #{params."+key+"}");
}
break;
}
}
}
}
}
}.toString();
}
}
此时baseMapper 相当于传统意义的baseDao,但是由于查询出来的是resultSet 集合并不能直接使用,如果要使用对象还需要手动转型,十分麻烦,如何才能和hibernate一样查出来的直接是java对象呢
此时便定义一个baseService提供基础增删该查功能
需要注意的是数据库类型与javabean类型不同需要转型 此处暂时只转了BigDecimal与CLOB型
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.huadi.xcx.common.util.FieldUtils;
import com.huadi.xcx.dao.MybaseMapper;
import oracle.sql.CLOB;
/**
* 通用增删改查方法
* @author zwt
*
*/
@Service("MyBaseService")
public class MyBaseService {
@Autowired
private MybaseMapper mybaseDao;
//保存暂时还不支持带出自增主键 有需求可以以后添加
public void saveEntity(String tableName,T t) {
int row=mybaseDao.saveEntity(tableName, t);
}
public void updateEntity(String tableName,T t,Map params) {
int row=mybaseDao.updateEntity(tableName, t, params);
}
@SuppressWarnings("unchecked")
public List queryAllByParams(Class> cls,String tableName,Map params) {
List> queryResult=mybaseDao.queryAllByParams(cls, tableName, params);
List backResult = new ArrayList<>();
Field[] fields = cls.getDeclaredFields();
T nt;
for(int i=0;i map =queryResult.get(i);
StringBuffer sb = new StringBuffer();
Set keys=map.keySet();
Iterator it =keys.iterator();
while(it.hasNext()) {
String key=it.next();
String fieldName=FieldUtils.UnderlineToHump(key);
Object value =map.get(key);
for(Field f:fields) {
if(fieldName.equals(f.getName())) {
f.setAccessible(true);
//需要转型
if(BigDecimal.class.toString().equals(value.getClass().toString())) {
Type type=f.getGenericType();
Class fieldClass =Class.forName(type.getTypeName());
Method method=fieldClass.getMethod("valueOf",String.class);
value=method.invoke(value, value.toString());
f.set(nt, value);
}else if(CLOB.class.toString().equals(value.getClass().toString())) {
f.set(nt, FieldUtils.ClobToString((CLOB)value));
}
else {
f.set(nt, value);
}
break;
}
}
}
backResult.add(nt);
} catch (Exception e) {
e.printStackTrace();
}
}
return backResult;
}
@SuppressWarnings("unchecked")
public PageInfo queryPageByParams(Class> cls,String tableName,Map params,int pageNum,int pageSize) {
PageHelper.startPage(pageNum, pageSize);
Page> queryPage=mybaseDao.queryPageByParams(cls, tableName, params);
PageInfo pageinfo =new PageInfo(queryPage);
List> queryResult = pageinfo.getList();
List resultList = new ArrayList<>();
Field[] fields = cls.getDeclaredFields();
T nt;
for(int i=0;i map =queryResult.get(i);
StringBuffer sb = new StringBuffer();
Set keys=map.keySet();
Iterator it =keys.iterator();
while(it.hasNext()) {
String key=it.next();
String fieldName=FieldUtils.UnderlineToHump(key);
Object value =map.get(key);
for(Field f:fields) {
if(fieldName.equals(f.getName())) {
f.setAccessible(true);
//需要转型
if(BigDecimal.class.toString().equals(value.getClass().toString())) {
Type type=f.getGenericType();
Class fieldClass =Class.forName(type.getTypeName());
Method method=fieldClass.getMethod("valueOf",String.class);
value=method.invoke(value, value.toString());
f.set(nt, value);
}else if(CLOB.class.toString().equals(value.getClass().toString())) {
f.set(nt, FieldUtils.ClobToString((CLOB)value));
}
else {
f.set(nt, value);
}
break;
}
}
}
resultList.add(nt);
} catch (Exception e) {
e.printStackTrace();
}
}
pageinfo.setList(resultList);
return pageinfo;
}
@SuppressWarnings("unchecked")
public T selectOne(Class> cls,String tableName,Map params) {
PageHelper.startPage(1, 1);
Page> queryPage=mybaseDao.queryPageByParams(cls, tableName, params);
PageInfo pageinfo =new PageInfo(queryPage);
List> queryResult = pageinfo.getList();
List resultList = new ArrayList<>();
Field[] fields = cls.getDeclaredFields();
T nt;
for(int i=0;i map =queryResult.get(i);
StringBuffer sb = new StringBuffer();
Set keys=map.keySet();
Iterator it =keys.iterator();
while(it.hasNext()) {
String key=it.next();
String fieldName=FieldUtils.UnderlineToHump(key);
Object value =map.get(key);
for(Field f:fields) {
if(fieldName.equals(f.getName())) {
f.setAccessible(true);
//需要转型
if(BigDecimal.class.toString().equals(value.getClass().toString())) {
Type type=f.getGenericType();
Class fieldClass =Class.forName(type.getTypeName());
Method method=fieldClass.getMethod("valueOf",String.class);
value=method.invoke(value, value.toString());
f.set(nt, value);
}else if(CLOB.class.toString().equals(value.getClass().toString())) {
f.set(nt, FieldUtils.ClobToString((CLOB)value));
}
else {
f.set(nt, value);
}
break;
}
}
}
return nt;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
有了这个baseService 便可以和hibernate一样查询出来直接是想要的对象了
思考:由于大量使用反射会不会造成性能问题,而且是基于mybatis的二次封装相当于多了一倍的结果对象,会消耗一倍的内存。
根据POJO类生成数据库表也可以写一套简易的,以后有空再写。