花了幾天的時間研究了一下mybatis的源代碼,以爲這個框架仍是很不錯的。可是有一些缺陷的地方。java
先來講說它和別的框架比起來我認爲的好處:spring
(1)sql外置,把sql文件寫在配置文件中加上強大的動態sql支持。sql
(2)利用cjk動態代理,實現配置文件映射接口。數據庫
這樣咱們在使用這套orm框架的時候就能夠再也不寫那個拼接sql語句的dao實現類(dao-impl class),把dao實現類的工做都移交給那些*mapper.xml文件,若是數據庫查詢業務須要修改sql的話,那麼只須要修改xml文件中的sql語句。apache
須要擴展的地方:微信
(1)沒有內置物理分頁的實現。session
咱們通常的習慣都是返回咱們本身的分頁實現類,網上大多的mybatis分頁實現都是先返回分頁列表,再查下返回總頁數,而後處理成咱們本身的分頁類。我本身也寫了一個分頁,把這部分工做交給mybatis來處理,之後會把代碼貼出來。antd
(2)公用範型接口daomybatis
公用範型接口dao類幾乎成爲咱們開發中最長使用的,把一些長操做的方法封裝一下,供咱們的業務dao調用,可是在mybatis中,我如今不想再寫dao的實現類,只有接口類,取締他的是mapper-xml文件,這樣如何才能封裝咱們的公用方法呢。app
幸虧mybatis提供了插件攔截器,咱們能夠在不修改mybatis源碼的基礎上來擴展它的功能。
好忙啊,花了些時間寫了一個範型接口dao,尚未通過驗證,先貼上代碼。
使用方法很簡單,只要你使用MappInterceptor這個攔截器,在你的Mapper接口中繼承這個IGenericDao這樣 公用的方法就可使用了,這樣的好處是在通常業務的類中不用再寫Dao的實現,直接使用 IGenericDao中提供的方法就ok
公用dao,你的接口只要繼承這個dao就可使用裏面的方法。
package org.cf.guott.mybatis; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import org.cf.guott.mybatis.pagination.PageMyBatis; public interface IGenericDao<T,PK> { @Select("MapperGD.find.entityById") public T findEntityById(PK id); @Select("MapperGD.find.entitys") public List<T> findEntity(Object... obj); @Select("MapperGD.find.ListByLike") public List<T> findLikeEntity(Object... obj); @Insert("MapperGD.insert.entity") public void insertEntity(T t); @Update("MapperGD.update.entity") public void updateEntityById(T entity); @Delete("MapperGD.delete.id") public void deleteById(PK id); @Delete("MapperGD.delete.condition") public void deleteByCondition(Object param); @Select("MapperGD.find.entity.queryByVo") public PageMyBatis<T> queryByVo(int i,int c,Object... obj); @Select("MapperGD.find.entity.queryByVoLike") public PageMyBatis<T> LikequeryByVo(int i,int c,Object... obj); }
這個一個攔截器,來處理你的公用dao中的方法
package org.cf.guott.mybatis.dbmapper.interceptor; import java.util.Map; import java.util.Properties; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.cf.guott.mybatis.helpers.MapperSqlHelper; import org.cf.guott.mybatis.pagination.MappedStatmentHelper; @Intercepts({ @Signature( type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}) ,@Signature( type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}) }) public class MappInterceptor implements Interceptor{ private final static String _sql_regex = ".*MapperGD.*"; @SuppressWarnings("unchecked") private void processIntercept(final Object[] queryArgs) { final MappedStatement ms = (MappedStatement) queryArgs[0]; final Object parameter = queryArgs[1]; String mapperSQL = ms.getBoundSql(parameter).getSql(); BoundSql boundSQL = ms.getBoundSql(parameter); Class<?> entityclazz = MappedStatmentHelper.getEntityClazz(ms.getResource()); queryArgs[0] = MappedStatmentHelper.setMSReturnSetMap(ms, entityclazz); boolean interceptor = mapperSQL.matches(_sql_regex); if(!interceptor){ return; } if(entityclazz == null){ throw new RuntimeException("使用公共dao必須給mapper接口的@MyBatisRepository(User.class) 註解設置值."); } String new_sql = MapperSqlHelper.getExecuSQL(entityclazz,mapperSQL,parameter); BoundSql newBoundSql = MappedStatmentHelper.copyFromBoundSql(ms, boundSQL, new_sql); MappedStatement newMs = MappedStatmentHelper .copyFromMappedStatement(ms, newBoundSql); queryArgs[0] = newMs; } public Object intercept(Invocation invocation) throws Throwable { processIntercept(invocation.getArgs()); return invocation.proceed(); } public Object plugin(Object o) { return Plugin.wrap(o, this); } public void setProperties(Properties arg0) { } }這個類來處理你的sql語句
package org.cf.guott.mybatis.helpers; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collection; import java.util.Map; import org.apache.commons.lang3.reflect.FieldUtils; import org.cf.guott.mybatis.annotation.MyBatisColumn; import org.cf.guott.mybatis.annotation.MyBatisRepository; import org.cf.guott.mybatis.annotation.MybatisID; import org.cf.guott.mybatis.annotation.MybatisTable; import org.cf.guott.mybatis.entity.User; public class MapperSqlHelper{ public static final Class<? extends Annotation> MYBATISREPOSITORY = MyBatisRepository.class; public static final Class<? extends Annotation> MYBATISTABLE = MybatisTable.class; public static final Class<? extends Annotation> MYBATISCOLUMN = MyBatisColumn.class; public static final Class<? extends Annotation> MYBATISID = MybatisID.class; public String getUpdateSQL(){ return null; } /** * 傳入mapper接口class * @param mapperclazz * @return */ private String insertEntity(Class<?> clazz){ StringBuilder sql = new StringBuilder(); StringBuilder intosql = new StringBuilder(); StringBuilder valuessql = new StringBuilder(); if(!clazz.isAnnotationPresent(MYBATISTABLE)){ sql.append("INSERT INTO "+clazz.getName()); }else{ MybatisTable antable = (MybatisTable)clazz.getAnnotation(MYBATISTABLE); if(antable.value() == ""){ sql.append("INSERT INTO "+clazz.getName()); }else{ sql.append("INSERT INTO "+antable.value()); } } Field[] files = clazz.getDeclaredFields(); intosql.append("("); for(Field file : files){ file.setAccessible(true); if(file.isAnnotationPresent(MYBATISCOLUMN)){ MyBatisColumn anColumn = (MyBatisColumn)file.getAnnotation(MYBATISCOLUMN); if(!anColumn.isAutoKey()){ if(anColumn.value().equals("")){ intosql.append(file.getName()+","); }else{ intosql.append(anColumn.value()+","); } } }else{ intosql.append(file.getName()+","); } } valuessql.append(" values ("); for(Field file : files){ file.setAccessible(true); if(file.isAnnotationPresent(MYBATISCOLUMN)){ MyBatisColumn anColumn = (MyBatisColumn)file.getAnnotation(MYBATISCOLUMN); if(!anColumn.isAutoKey()){ if(anColumn.value().equals("")){ valuessql.append("#{"+file.getName()+"},"); }else{ valuessql.append("#{"+file.getName()+"},"); } } }else{ valuessql.append("#{"+file.getName()+"},"); } } return sql.append(intosql.substring(0, intosql.length()-1)).append(") ").append(valuessql.substring(0, valuessql.length()-1)).append(")").toString(); } /** * 傳入mapper接口class * @param mapperclazz * @return */ private String updateEntityById(Class<?> clazz){ StringBuilder sql = new StringBuilder(); StringBuilder set = new StringBuilder(); StringBuilder wheresql = new StringBuilder(); if(!clazz.isAnnotationPresent(MYBATISTABLE)){ sql.append("UPDATE "+clazz.getName()); }else{ MybatisTable antable = (MybatisTable)clazz.getAnnotation(MYBATISTABLE); if(antable.value() == ""){ sql.append("UPDATE "+clazz.getName()); }else{ sql.append("UPDATE "+antable.value()); } } Field[] files = clazz.getDeclaredFields(); set.append(" set "); wheresql.append(" where 1=1 "); for(Field file : files){ file.setAccessible(true); if(file.isAnnotationPresent(MYBATISCOLUMN)){ MyBatisColumn anColumn = (MyBatisColumn)file.getAnnotation(MYBATISCOLUMN); if(!anColumn.isID()){//判斷字段不爲主鍵 if(anColumn.value().equals("")){ set.append(file.getName()+" = #{"+file.getName()+"} ,"); }else{ set.append(anColumn.value()+" = #{"+file.getName()+"} ,"); } }else{ if(anColumn.value().equals("")){ wheresql.append(" and "+file.getName()+" = #{"+file.getName()+"},"); }else{ wheresql.append(" and "+anColumn.value()+" = #{"+anColumn.value()+"},"); } } }else{ set.append(file.getName()+" = #{"+file.getName()+"} ,"); } } if(wheresql.equals(" where 1=1 ")){ throw new RuntimeException("實體變量沒有設置ID字段值"); } sql.append(set.substring(0, set.length()-1)).append(wheresql.substring(0, wheresql.length()-1)); return sql.toString(); } private String findEntityAll(Class<?> clazz,Object args,boolean islike){ StringBuilder sql = new StringBuilder(); StringBuilder whereSQL = new StringBuilder(" where 1=1 "); StringBuffer orderby = new StringBuffer(); if(!clazz.isAnnotationPresent(MYBATISTABLE)){ sql.append("select * from "+clazz.getName()); }else{ MybatisTable antable = (MybatisTable)clazz.getAnnotation(MYBATISTABLE); if(antable.value() == ""){ sql.append("select * from "+clazz.getSimpleName()); }else{ sql.append("select * from "+antable.value()); } } Object[] paramObjs = (Object[]) ((Map)args).get("array"); if(paramObjs != null && paramObjs.length>0){ Object param = paramObjs[0]; if(param != null ){ if(param instanceof Map){ Map<String,Object> map = (Map)param; if(map.containsKey("orderby")){ orderby.append(" order by "+map.get("orderby")); } if(map.containsKey("sortby")){ orderby.append(" "+map.get("sortby")+" "); } for(String key : map.keySet()) { if(islike) whereSQL.append(" and "+key + " like '%" + map.get(key)+"%',"); else whereSQL.append(" and "+key + " = '" + map.get(key)+"',"); } sql.append(whereSQL.subSequence(0,whereSQL.length()-1)).append(orderby); }else if(param instanceof Conditions){ Conditions<String,Object> map = (Conditions)param; if(map.containsKey("orderby")){ orderby.append(" order by "+map.get("orderby")); } if(map.containsKey("sortby")){ orderby.append(" "+map.get("sortby")+" "); } for(String key : map.keySet()) { if(key.equals("orderby") || key.equals("sortby")){ continue; } if(islike) whereSQL.append(" and "+key + " like '%" + map.get(key)+"%',"); else whereSQL.append(" and "+key + " = '" + map.get(key)+"',"); } sql.append(whereSQL.subSequence(0,whereSQL.length()-1)).append(orderby); } } } return sql.toString(); } private String findEntityById(Class<?> clazz){ StringBuilder sql = new StringBuilder(); if(!clazz.isAnnotationPresent(MYBATISTABLE)){ sql.append("select * from "+clazz.getName()); }else{ MybatisTable antable = (MybatisTable)clazz.getAnnotation(MYBATISTABLE); if(antable.value() == ""){ sql.append("select * from "+clazz.getSimpleName()); }else{ sql.append("select * from "+antable.value()); } } sql.append(" where 1=1 "); Field[] files = clazz.getDeclaredFields(); boolean falg = false; for(Field file : files){ file.setAccessible(true); if(file.isAnnotationPresent(MyBatisColumn.class)){ MyBatisColumn anColumn = (MyBatisColumn)file.getAnnotation(MYBATISCOLUMN); if(anColumn.isID()){//判斷字段不爲主鍵 falg = true; if(anColumn.value().equals("")){ sql.append(" and "+file.getName()+" = #{"+file.getName()+"},"); }else{ sql.append(" and "+file.getName()+" = #{"+file.getName()+"},"); } } } } if(!falg){ throw new RuntimeException("不能通過id查詢實體,實體中沒有定義@mybatisID"); } return sql.subSequence(0, sql.length()-1).toString(); } public String deleteById(Class<?> clazz){ StringBuilder sql = new StringBuilder(); StringBuilder wheresql = new StringBuilder(" where 1=1 "); if(!clazz.isAnnotationPresent(MYBATISTABLE)){ sql.append("delete "+clazz.getName()); }else{ MybatisTable antable = (MybatisTable)clazz.getAnnotation(MYBATISTABLE); if(antable.value() == ""){ sql.append("delete "+clazz.getName()); }else{ sql.append("delete "+antable.value()); } } Field[] files = clazz.getDeclaredFields(); for(Field file : files){ file.setAccessible(true); if(file.isAnnotationPresent(MYBATISCOLUMN)){ MyBatisColumn anColumn = (MyBatisColumn)file.getAnnotation(MYBATISCOLUMN); if(anColumn.isID()){//判斷字段不爲主鍵 if(anColumn.value().equals("")){ wheresql.append(" and "+file.getName()+" = #{"+file.getName()+"},"); }else{ wheresql.append(" and "+anColumn.value()+" = #{"+anColumn.value()+"},"); } } } } if(wheresql.equals(" where 1=1 ")){ throw new RuntimeException("實體變量沒有設置ID字段值"); } sql.append(wheresql.substring(0,wheresql.length()-1)); return sql.toString(); } public String queryByVo(Class<?> clazz,Object args,boolean islike){ StringBuilder sql = new StringBuilder(); StringBuilder whereSQL = new StringBuilder(" where 1=1 "); StringBuilder orderbySQL = new StringBuilder(""); if(!clazz.isAnnotationPresent(MYBATISTABLE)){ sql.append("select * from "+clazz.getName()); }else{ MybatisTable antable = (MybatisTable)clazz.getAnnotation(MYBATISTABLE); if(antable.value() == ""){ sql.append("select * from "+clazz.getName()); }else{ sql.append("select * from "+antable.value()); } } if(args instanceof Map){ Map map = (Map)args; Object[] arr = (Object[])map.get("param3"); if(arr.length>0){ Map<String,Object> params = (Map)arr[0]; if(params.containsKey("orderby")){ orderbySQL.append(" order by "+params.get("orderby")); } if(params.containsKey("sortby")){ orderbySQL.append(" "+params.get("sortby")+" "); } for(String key:params.keySet()){ if(key.equals("orderby") || key.equals("sortby")){ continue; } if(islike) whereSQL.append(" and "+key + " like '%" + params.get(key)+"%',"); else whereSQL.append(" and "+key + " = '" + params.get(key)+"',"); } } } return sql.append(whereSQL.substring(0, whereSQL.length()-1)).append(orderbySQL).toString(); } public String count(Class<?> clazz,Object args){ StringBuilder sql = new StringBuilder(); StringBuilder whereSQL = new StringBuilder(" where 1=1 "); if(!clazz.isAnnotationPresent(MYBATISTABLE)){ sql.append("select count(*) from "+clazz.getName()); }else{ MybatisTable antable = (MybatisTable)clazz.getAnnotation(MYBATISTABLE); if(antable.value() == ""){ sql.append("select count(*) from "+clazz.getName()); }else{ sql.append("select count(*) from "+antable.value()); } } Object[] paramObjs = (Object[]) ((Map)args).get("array"); if(paramObjs != null && paramObjs.length>0){ Object param = paramObjs[0]; if(param != null ){ if(param instanceof Map){ Map<String,Object> map = (Map)param; for(String key : map.keySet()) { whereSQL.append(" and "+key + " = '" + map.get(key)+"',"); } sql.append(whereSQL.subSequence(0,whereSQL.length()-1)); }else if(param instanceof Conditions){ Conditions<String,Object> map = (Conditions)param; for(String key : map.keySet()) { whereSQL.append(" and "+key + " = '" + map.get(key)+"',"); } sql.append(whereSQL.subSequence(0,whereSQL.length()-1)); } } } return sql.toString(); } public String deleteByCondition(Class<?> clazz,Object param){ StringBuilder sql = new StringBuilder(); StringBuilder whereSQL = new StringBuilder(" where 1=1 "); if(!clazz.isAnnotationPresent(MYBATISTABLE)){ sql.append("delete "+clazz.getName()); }else{ MybatisTable antable = (MybatisTable)clazz.getAnnotation(MYBATISTABLE); if(antable.value() == ""){ sql.append("delete "+clazz.getName()); }else{ sql.append("delete "+antable.value()); } } if(param != null ){ if(param instanceof Map){ Map<String,Object> map = (Map)param; for(String key : map.keySet()) { whereSQL.append(" and "+key + " = '" + map.get(key)+"',"); } sql.append(whereSQL.subSequence(0,whereSQL.length()-1)); }else if(param instanceof Conditions){ Conditions<String,Object> map = (Conditions)param; for(String key : map.keySet()) { whereSQL.append(" and "+key + " = '" + map.get(key)+"',"); } sql.append(whereSQL.subSequence(0,whereSQL.length()-1)); } } if(whereSQL.equals(" where 1=1 ")){ throw new RuntimeException("實體變量沒有設置ID字段值"); } return sql.toString(); } private static MapperSqlHelper App(){ return new MapperSqlHelper(); } public static String getExecuSQL(Class<?> clazz, String mapperDBsql,Object param) { if(mapperDBsql.equals("MapperGD.find.entitys")){ return MapperSqlHelper.App().findEntityAll(clazz,param,false);//條件查詢實體列表 }else if(mapperDBsql.equals("MapperGD.find.entityById")){ return MapperSqlHelper.App().findEntityById(clazz);//id查詢實體 }else if(mapperDBsql.equals("MapperGD.find.ListByLike")){ return MapperSqlHelper.App().findEntityAll(clazz,param,true);//條件查詢實體列表 }else if(mapperDBsql.equals("MapperGD.insert.entity")){ return MapperSqlHelper.App().insertEntity(clazz);//保存單一實體 }else if(mapperDBsql.equals("MapperGD.update.entity")){ return MapperSqlHelper.App().updateEntityById(clazz);//保存單一實體 }else if(mapperDBsql.equals("MapperGD.update.entity.condistion")){ return mapperDBsql; }else if(mapperDBsql.equals("MapperGD.delete.id")){ return MapperSqlHelper.App().deleteById(clazz); }else if(mapperDBsql.equals("MapperGD.delete.condition")){ return MapperSqlHelper.App().deleteByCondition(clazz,param); }else if(mapperDBsql.equals("MapperGD.count.condition")){ return MapperSqlHelper.App().count(clazz,param); }else if(mapperDBsql.equals("MapperGD.find.entity.queryByVo")){ return MapperSqlHelper.App().queryByVo(clazz,param,false); }else if(mapperDBsql.equals("MapperGD.find.entity.queryByVoLike")){ return MapperSqlHelper.App().queryByVo(clazz,param,true); } return null; } //預留接口 private String updateEntityByConditions(Class<?> clazz,Object param){ return null; } public void getParam(Object param){ StringBuffer bf = new StringBuffer(); if (isPrimitiveType(param.getClass())) { bf.append(param); } else if (param instanceof Map) { Map<String,Object> map = (Map)param; } } public static boolean isPrimitiveType(Class clazz) { return clazz != null && (clazz.isPrimitive() || clazz.equals(Long.class) || clazz.equals(Integer.class) || clazz.equals(Short.class) || clazz.equals(Byte.class) || clazz.equals(Double.class) || clazz.equals(Float.class) || clazz.equals(Boolean.class) || clazz.equals(Character.class) || clazz.equals(String.class)); } public static void main(String[] args) { // Object object = null; // if (isPrimitiveType(object.getClass())) { // } else if (object instanceof Map) { // } Field[] files = User.class.getDeclaredFields(); User u = new User(); try { System.out.println(FieldUtils.readDeclaredField(u, "id",true)); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }測試用例:
業務dao,這個接口繼承自 IGenericDao
package org.cf.guott.mybatis.mapper; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.Select; import org.cf.guott.mybatis.ITestGDAO; import org.cf.guott.mybatis.annotation.MyBatisRepository; import org.cf.guott.mybatis.entity.User; import org.cf.guott.mybatis.pagination.PageMyBatis; @MyBatisRepository(User.class) public interface UserMapper extends IGenericDao<User,Integer>{ }main運行方法
package org.cf.guott.mybatis.main; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ibatis.session.RowBounds; import org.cf.guott.mybatis.entity.User; import org.cf.guott.mybatis.helpers.Conditions; import org.cf.guott.mybatis.mapper.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Component; @Component public class Main { @Autowired UserMapper userMapper; public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-mybatis.xml"); Main main = context.getBean(Main.class); Map map = new HashMap(); map.put("name", "ccc"); List<User> users = main.userMapper.LikequeryByVo(0,2,new Conditions<String, Object>().add("name", "guotiantdddian").addOrderBy("id").setSortByDesc()); System.out.println(users.size()); } }