mybaties封装
一、 流程图
二、 好处
- 方便接口功能扩展
- 减少开发代码写sql语句的麻烦
- 代码整洁清晰且易于维护
三、 案例(已一个复杂的查询为案例,代码只给出所需要的代码)
3.1 代码入口
package com.apiserver.producer.system;
import com.apiserver.data.mybatis.util.SortConstants;
import com.apiserver.model.system.entity.SUsers;
import com.apiserver.producer.system.service.UsersService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.*;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ProducerSystemApplicationTests {
@Autowired
public UsersService usersService;
@Test
public void selectAllByOtherKey(){
//一般查询的sql
SUsers sUser = SUsers.builder()
.id(252405769423826944L)
.chineseName("露西")
.build();
//排序
LinkedHashMap<String,String> sortrMap=new LinkedHashMap<>();
sortrMap.put("chineseName", SortConstants.DESC);
sortrMap.put("id", SortConstants.ASC);
//like 查询
Map<String,Object> likeQueryMap=new HashMap<>();
likeQueryMap.put("pwd","11111");
likeQueryMap.put("email","324234@qq.com");
//一个字段多个值的查询
Map<String,List<Object>> arrayQueryMap=new HashMap<>();
List<Object> list1=new ArrayList<>();
list1.add(111);
list1.add(222);
arrayQueryMap.put("education",list1);
List<Object> list2=new ArrayList<>();
list2.add(333);
list2.add(444);
arrayQueryMap.put("age",list2);
List<SUsers> sUsers =usersService.selectAllByOtherKey(sUser,likeQueryMap,arrayQueryMap,sortrMap);
System.out.println(sUsers);
}
}
3.2 上面通过注解加载UsersService类,那么加载UsersService类做了什么呢?
public interface UsersService extends BaseService<SUsers> {
}
@Repository
public class UsersServiceImpl extends BaseServiceImpl<UsersMapper,SUsers> implements UsersService {
}
3.3 上面我们看到UsersService继承BaseService,UsersServiceImpl继承BaseServiceImpl,那么BaseService和BaseServiceImpl做了什么?
/**
* @Author feizhou
* @Description 基本方法封装
* @Date 下午 10:18 2019/10/10 0010
* @Param
* @return
**/
public interface BaseService<M> {
/**
* @Author feizhou
* @Description 返回排序列表,支持模糊查询,支持1属性多个值的查询
* @Date 下午 11:22 2019/10/11 0011
* @Param [m, sortMap, likePropertyNameList, arrayQueryMap]
* @return java.util.List<M>
**/
List<M> selectAllByOtherKey(M m,Map<String,Object> likeQueryMap,Map<String,List<Object>> arrayQueryMap,LinkedHashMap<String,String> sortMap);
}
/**
* @Author feizhou
* @Description 基本方法封装
* @Date 下午 10:19 2019/10/10 0010
* @Param
* @return
**/
@Slf4j
public abstract class BaseServiceImpl<D extends BaseMapper<M>, M> implements BaseService<M> {
protected D dao;
@Autowired
public void setDao(D dao) {
this.dao = dao;
}
private Class<M> entityClass;
@SuppressWarnings("unchecked")
@PostConstruct//构造完成执行的方法
public void init() {
entityClass = (Class<M>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[1];
}
@Override
public List<M> selectAllByOtherKey(M m, Map<String, Object> likeQueryMap, Map<String, List<Object>> arrayQueryMap, LinkedHashMap<String, String> sortMap) {
return dao.selectAllByOtherKey(m, likeQueryMap, arrayQueryMap, sortMap);
}
}
BaseServiceImpl
-
我们可以看到,该类提供protected D(BaseMapper) dao, 子类通过继承可以使用该dao,也就是说UsersServiceImpl可以使用该dao。
-
该dao使用注解的方式注入
-
@PostConstruct注解修饰init(),表示构造完成后执行init方法,init方法是为了获取当前类的类对象。
public void init() { entityClass = (Class<M>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[1]; } 代码分解如下------- //当前对象的直接超类的 Type Type superclass =getClass().getGenericSuperclass(); //参数化类型 ParameterizedType parameterizedType=(ParameterizedType)superclass; //返回表示此类型实际类型参数的 Type 对象的数组的第一个元素 Type type=parameterizedType.getGenericSuperclass()).getActualTypeArguments()[1]; //转换类对象 (Class<M>) entityClass = (Class<M>)type
-
通过3可以获取到,UsersServiceImpl还有一个entityClass(SUsers.class),也就是说,每一个业务实现类,都有一个自己的类对象。
3.4 通过上面,我们已经将访问service的类和类构造讲完了。
3.5 现在我们介绍下 usersService.selectAllByOtherKey(sUser,likeQueryMap,arrayQueryMap,sortrMap)代码流程
-
selectAllByOtherKey实际如下截图
-
通过1我们知道,selectAllByOtherKey实际调用的是SelProvider类的selectAllByOtherKey方法
/**
* @author hs
* @description 生成mybatis动态sql
* @date 2016年12月30日下午4:59:00
*/
@Slf4j
public class SelProvider extends Provider {/** * @return java.lang.String * @Author feizhou * @Description 返回排序列表,支持模糊查询,支持一属性,多个值的查询 * @Date 下午 10:33 2019/10/10 0010 * @Param [t] **/ public <M> String selectAllByOtherKey(Map<String, Object> param) { M m = (M) param.get("m"); LinkedHashMap<String, String> sortMap = (LinkedHashMap<String, String>) param.get("sortMap"); Map<String, Object> likeQueryMap = (Map<String, Object>) param.get("likeQueryMap"); Map<String, List<Object>> arrayQueryMap = (Map<String, List<Object>>) param.get("arrayQueryMap"); EntityTable entity = EntityUtil.getEntityTable(m); SQL sql = new SQL() .SELECT(entity.getSqlColumns()) .FROM(entity.getTableName()) .WHERE("1 = 1"); getWhere(m, sql, entity); getLikeWhere(likeQueryMap, sql, entity); getWhereForIn(arrayQueryMap, sql, entity); getOrderSql(sortMap, sql, entity); return sql.toString(); } }
3.6 selectAllByOtherKey代码解析
EntityUtil.getEntityTable(m)
/**
* 获取表对象
*
* @return
*/
public static EntityTable getEntityTable(Object obj) {
EntityTable entityTable = getEntityTableWithoutParams(obj);
return entityTable;
}
-----获取表对象
/**
* @Author feizhou
* @Description 获取实体的信息
* @Date 下午 4:45 2019/10/8 0008
* @Param [obj]
* @return com.apiserver.data.mybatis.model.EntityTable
**/
public static EntityTable getEntityTableWithoutParams(Object obj) {
//obj 就是传入的泛型M,也就是SUsers的类对象
//获取类对象
Class<?> entityClass = obj.getClass();
//获取当前类对象的实体表信息
EntityTable entityTable = entityTableMap.get(entityClass);
if (entityTable == null){//没有获取到返回
initEntityNameMap(entityClass);
}
//再查一次,因为第一次可能entityTable==null.
entityTable = entityTableMap.get(entityClass);
return entityTable;
}
---初始化实体属性
/**
* @Author feizhou
* @Description 初始化实体属性
* @Date 下午 1:27 2019/10/9 0009
* @Param [entityClass]
* @return void
**/
private synchronized static void initEntityNameMap(Class<?> entityClass) {
//如果实体存在,就不初始化
if (entityTableMap.get(entityClass) != null){
return;
}
Style style = Style.camelhumpAndLowercase;// 默认驼峰命名法
// style,该注解优先于全局配置
if (entityClass.isAnnotationPresent(NameStyle.class)){
style = entityClass.getAnnotation(NameStyle.class).value();
}
// 创建并缓存EntityTable
EntityTable entityTable = new EntityTable(entityClass);
//实体类需要table注解
if (!entityClass.isAnnotationPresent(Table.class)){
throw new DataException(ErrCode.table_Not_Exist);
}
Table table = entityClass.getAnnotation(Table.class);
//表名存在的情况
if (!table.name().equals("")) {
entityTable.setTableName(table.name());
}else {
String tableName = StyleUtil.convertByStyle(entityClass.getSimpleName(), style);
entityTable.setTableName(table.prefix()+tableName);
}
//字段转换方式
entityTable.setStyle(style);
// 处理所有列
List<ColumnProperty> columnProperties = ColumnPropertyUtil.getColumnProperties(entityClass, style);
buildEntityTable(entityTable,columnProperties);
entityTableMap.put(entityClass, entityTable);
}
其中entityTableMap定义
private static final Map<Class<?>, EntityTable> entityTableMap = new ConcurrentHashMap<>();
buildEntityTable方法
/**
* @Author feizhou
* @Description 构建主键EntityTable
* @Date 下午 3:23 2019/10/9 0009
* @Param [entityTable, columnProperties]
* @return void
**/
private static void buildEntityTable(EntityTable entityTable, List<ColumnProperty> columnProperties) {
StringBuffer sqlColumns=new StringBuffer();
Map<String, String> propertyColumn=new HashMap<>();
for (ColumnProperty columnProperty : columnProperties) {
String columnName = columnProperty.getColumnName();
String propertyName = columnProperty.getPropertyName();
sqlColumns.append(columnName);
sqlColumns.append(",");
//构建主键
if(columnProperty.getIsPK()){
entityTable.setPKColumn(columnName);
entityTable.setPKProperty(propertyName);
entityTable.setIdStrategy(columnProperty.getIdStrategy());
}
propertyColumn.put(propertyName,columnName);
}
entityTable.setPropertyColumn(propertyColumn);
//sql查询列
if(sqlColumns.length()>0){
entityTable.setSqlColumns(sqlColumns.substring(0,sqlColumns.length()-1));
}
}
getColumnProperties
/**
* @Author feizhou
* @Description ColumnProperty工具类
* @Date 下午 2:25 2019/10/9 0009
* @Param
* @return
**/
public class ColumnPropertyUtil {
private static final IColumnPropertyHelper columnPropertyHelper;
private static final String JAVA_VERSION = System
.getProperty("java.version");
static {
if (JAVA_VERSION.contains("1.8.")) {
columnPropertyHelper = new Jdk8ColumnPropertyHelper();
} else {
//目前先不处理
columnPropertyHelper = new Jdk8ColumnPropertyHelper();
}
}
/**
* 获取ColumnProperty
*
* @param entityClass
* @return
*/
public static List<ColumnProperty> getColumnProperties(Class<?> entityClass, Style style) {
return columnPropertyHelper.getColumnProperties(entityClass, style);
}
/**
* Field接口
*/
interface IColumnPropertyHelper {
/**
* 获取ColumnPropertie
*
* @param entityClass
* @return
*/
List<ColumnProperty> getColumnProperties(Class<?> entityClass, Style style);
}
/**
* 支持jdk8
*/
static class Jdk8ColumnPropertyHelper implements IColumnPropertyHelper {
/**
* 获取全部的getColumnProperties
*
* @param entityClass
* @return
*/
public List<ColumnProperty> getColumnProperties(Class<?> entityClass, Style style) {
return _getColumnProperties(entityClass, null, null, style);
}
/**
* @return java.util.List<com.apiserver.data.mybatis.model.ColumnProperty>
* @Author feizhou
* @Description 获取全部的ColumnPropertie
* @Date 下午 1:41 2019/10/9 0009
* @Param [entityClass, list, level]
**/
private List<ColumnProperty> _getColumnProperties(Class<?> entityClass, List<ColumnProperty> list, Integer level, Style style) {
if (list == null) {
list = new ArrayList<ColumnProperty>();
}
if (level == null) {
level = 0;
}
//Object就直接返回
if (entityClass.equals(Object.class)) {
return list;
}
//获取所有的字段
Field[] fields = entityClass.getDeclaredFields();
int index = 0;
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
//排除构造参数this
if (field.getName().contains("this$0")) {
continue;
}
// 排除静态字段
if (!Modifier.isStatic(field.getModifiers())) {
ColumnProperty columnProperty = getColumnProperty(field, style);
if (level.intValue() != 0) {
// 将父类的字段放在前面
list.add(index, columnProperty);
index++;
} else {
list.add(columnProperty);
}
}
}
//构建父类的字段,迭代
Class<?> superClass = entityClass.getSuperclass();
if (superClass != null && !superClass.equals(Object.class)
&& (superClass.isAnnotationPresent(Entity.class)
|| (!Map.class.isAssignableFrom(superClass) && !Collection.class.isAssignableFrom(superClass)))) {
return _getColumnProperties(entityClass.getSuperclass(), list, ++level, style);
}
return list;
}
/**
* @return void
* @Author feizhou
* @Description 获取ColumnProperty
* @Date 下午 1:38 2019/10/9 0009
* @Param [field]
**/
private ColumnProperty getColumnProperty(Field field, Style style) {
String propertyName = field.getName();
//数据库列名
String columnName = propertyName;
Class<?> javaType = field.getType();
Boolean isPK = false;
Boolean isTransient = false;
IdStrategy idStrategy=null;
// Transient注解
if (field.isAnnotationPresent(Transient.class)) {
isTransient = true;
}
// 主键
if (field.isAnnotationPresent(Id.class)) {
isPK = true;
idStrategy=field.getAnnotation(Id.class).value();
}
//数据库列名
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
columnName = column.name();
} else {
columnName = StyleUtil.convertByStyle(columnName, style);
}
return new ColumnProperty(columnName, propertyName, isPK, isTransient, null, javaType,idStrategy);
}
}
}
3.7 下面给出2个重要的类
public class EntityTable {
private String sqlColumns;
private String tableName;
private Class<?> entityClass;
//字段转换方式
private Style style;
//主键
private String PKColumn;
//主键
private String PKProperty;
//主键策略
private IdStrategy idStrategy;
//key:属性名, value:数据库列名
private Map<String, String> propertyColumn;
public EntityTable(Class<?> entityClass) {
super();
this.entityClass = entityClass;
}
}
----
public class ColumnProperty {
//数据库列名称
private String columnName;
//实体属性名称
private String propertyName;
//是否主键
private Boolean isPK;
//是否过滤字段
private Boolean isTransient;
//值
private Object value;
//实体字段对应的类型
private Class<?> javaType;
//实体字段对应的类型
private IdStrategy idStrategy;
}
3.8 后面通过实体entity解析sql
EntityTable entity = EntityUtil.getEntityTable(m);
SQL sql = new SQL()
.SELECT(entity.getSqlColumns())
.FROM(entity.getTableName())
.WHERE("1 = 1");
getWhere(m, sql, entity);
getLikeWhere(likeQueryMap, sql, entity);
getWhereForIn(arrayQueryMap, sql, entity);
getOrderSql(sortMap, sql, entity);
-- 获取where语句,解析出来和mybaties的xml配置里面写的是一样的。
protected <M> SQL getWhere(M m, SQL sql, EntityTable entity) {
Map<String, Object> queryMap = MapTools.objectToMapNotNull(m);
for (Map.Entry<String, Object> entry : queryMap.entrySet()) {
sql = sql.WHERE(entity.getPropertyColumn().get(entry.getKey()) + "=#{m." + entry.getKey() + "}");
}
return sql;
}
四、代码位置
https://gitee.com/DanShenGuiZu/GongKaiZiYuan/tree/master/mrgo-api