Java技术贴之Mybatis逆向工程增强

前言

  • 在项目初期开发过程中,会写大量的增删改查代码,这个时候大家肯定会想到Mybatis逆向工程,但是使用了逆向工程之后代码量还是会比较大,比如说还要去自己实现增删改查的逻辑,但是事实上大多数的逻辑是通用的,所以这里重新做了一个工具。
    如果只是想使用Mapper,没有针对Example做一些特殊通用操作的话,下面这些可以省略,可以直接跳到BaseMapper部分
  • 为什么不适用现有的插件呢,因为他们不符合我的要求
  • 为什么不使用Mybatis Plus呢,这部分Mybatis Plus也没有实现,并且封装和Mybatis Plus不冲突,可以一起使用
    举个例子
    下面是tk.mybatis的源码
public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        FullyQualifiedJavaType entityType = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType());
        Iterator var5 = this.mappers.iterator();

        while(var5.hasNext()) {
            String mapper = (String)var5.next();
            interfaze.addImportedType(new FullyQualifiedJavaType(mapper));
            interfaze.addSuperInterface(new FullyQualifiedJavaType(mapper + "<" + entityType.getShortName() + ">"));
        }

        interfaze.addImportedType(entityType);
        return true;
    }

可以看到,他的泛型只支持一个,如果我也想把Example通过泛型传入是不行的,如果去继承他的MapperPlugin类,重写会比较复杂,所以我们直接自己写一个类好了

public class MapperPlugin extends PluginAdapter {

    @Override
    public boolean validate(List list) {
        return true;
    }

    @Override
    public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        FullyQualifiedJavaType entityType = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType());
        String mapper = "com.xxx.modules.common.dao.BaseMapper";
        interfaze.addImportedType(new FullyQualifiedJavaType(mapper));
        interfaze.addSuperInterface(new FullyQualifiedJavaType(mapper + "<" + entityType.getShortName() + ", "
                + entityType.getShortName() + "Example>"));
        interfaze.addImportedType(entityType);
        return true;
    }
}

事实上实现是差不多的,只是加了一些东西,简化了配置部分。带来的后果就是xml的扩展性较差,但是代码在自己项目中,改java比改xml更友好(主要是也可以不用写参数的配置)
然后在generatorConfig.xml文件的下的标签内增加以下代码即可,像这样


    
        

然后再去定义BaseMapper.java(其实就是复制一份逆向工程生成的Mapper文件,将实体替换为T,Example替换为E)

public interface BaseMapper {
    int countByExample(E example);

    int deleteByExample(E example);

    int deleteByPrimaryKey(Long id);

    int insert(T record);

    int insertSelective(T record);

    List selectByExample(E example);

    T selectByPrimaryKey(Long id);

    int updateByExampleSelective(@Param("record") T record, @Param("example") E example);

    int updateByExample(@Param("record") T record, @Param("example") E example);

    int updateByPrimaryKeySelective(T record);

    int updateByPrimaryKey(T record);
}

通过BaseMapper大家应该也能看到我的意图了。并且你可以在这里面实现任何扩展,例如selectOne/分页插件等常用接口,因为T和E都是可以通过继承传入的
再定义BaseService.java

@Service
public interface BaseService {

    int save(T t);

    int update(T t);

    int delete(Long id);

    T queryObject(Long id);
}

然后这里就需要T的基类了,BaseBean

public class BaseBean {

    /**
     * 创建时间
     */
    private Date createTime;

    /**
     * 更新时间
     */
    private Date updateTime;

    /**
     * 创建者
     */
    private Long createUser;

    /**
     * 更新者
     */
    private Long updateUser;

    /**
     * 乐观锁
     */
    private Integer version;

    /**
     * 逻辑删除
     */
    private Boolean deleteFlag;

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }

    public Long getCreateUser() {
        return createUser;
    }

    public void setCreateUser(Long createUser) {
        this.createUser = createUser;
    }

    public Long getUpdateUser() {
        return updateUser;
    }

    public void setUpdateUser(Long updateUser) {
        this.updateUser = updateUser;
    }

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    public Boolean getDeleteFlag() {
        return deleteFlag;
    }

    public void setDeleteFlag(Boolean deleteFlag) {
        this.deleteFlag = deleteFlag;
    }
}

然后是BaseServiceImpl.java

@Service
public class BaseServiceImpl implements BaseService {

    @Autowired
    private BaseMapper baseMapper;

    @Override
    public int save(T t) {
        t.setCreateTime(new Date());
        t.setUpdateTime(new Date());
        return baseMapper.insertSelective(t);
    }

    @Override
    public int update(T t) {
        t.setUpdateTime(new Date());
        return baseMapper.updateByPrimaryKeySelective(t);
    }

    @Override
    public int delete(Long id) {
        T t = queryObject(id);
        if (t == null) {
            return 0;
        }
        t.setDeleteFlag(true);
        t.setUpdateTime(new Date());
        return update(t);
    }

    @Override
    public T queryObject(Long id) {
        return baseMapper.selectByPrimaryKey(id);
    }
}

这个时候代码是存在问题的,如果有两个子类,Autowired的是哪个mapper呢,并且BaseMapper也没有对应的Xml啊。下面会有解决办法。
假如你加入了分页插件,那么只需要在BaseMapper加入分页插件的接口,然后BaseService去定义,在BaseServiceImpl中去实现,就完成了整个接口的开发,对于后续的接口来说那就是0代码了。
后续的代码

public interface TestService extends BaseService {
    // do nothing
}
@Service
public class TestServiceImpl extends BaseServiceImpl implements TestService {
    // do nothing
}
@RestController
public class TestController {

    @Autowired
    private TestService testService;
    public void testSave() {
        testService.save(new TPurchaserAccountLog());
    }
}

什么?代码还要写,如果没有业务我写一个空的service干嘛?那下面的写法就很香了

@Autowired
BaseService purchaserAccountLogService;

可以看到只需要写控制器层的方法就好了(对于基于接口开发也是同理的,甚至都不需要去写接口),也就是说有表接口只需要生成然后就可以直接调用基础方法了~~~
上述BaseMapper代码中增加了Example相关,如果需要使用Example之类的方法,那么需要更改BaseService,例如selectByExample

public interface BaseService {

    int save(T t);

    int update(T t);

    int delete(Long id);

    T queryObject(Long id);

    List selectByExample(E example);
}

BaseServiceImpl更改为

public class BaseServiceImpl implements BaseService {

并增加实现

@Override
    public List selectByExample(E example) {
        return baseMapper.selectByExample(example);
    }

那么如何注入Example呢,我们需要更改插件,添加方法modelExampleClassGenerated

public class MapperPlugin extends PluginAdapter {

    @Override
    public boolean validate(List list) {
        return true;
    }

    @Override
    public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        FullyQualifiedJavaType entityType = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType());
        String mapper = "com.xxx.modules.common.dao.BaseMapper";
        interfaze.addImportedType(new FullyQualifiedJavaType(mapper));
        interfaze.addSuperInterface(new FullyQualifiedJavaType(mapper + "<" + entityType.getShortName() + ", "
                + entityType.getShortName() + "Example>"));
        interfaze.addImportedType(entityType);
        return true;
    }

    @Override
    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        String baseBean = "com.xxx.modules.common.service.BaseExample";
        topLevelClass.addImportedType(new FullyQualifiedJavaType(baseBean));
        topLevelClass.setSuperClass(new FullyQualifiedJavaType(baseBean));
        List list = topLevelClass.getInnerClasses();
        InnerClass innerClass = list.get(0);
        String criteria = "com.xxx.modules.common.service.BaseExample.BaseCriteria";
        innerClass.setSuperClass(new FullyQualifiedJavaType(criteria));
        list.remove(2); //不生成 Criterion
        return true;
    }
}

可以看到在方法汇总首先是继承BaseExample然后又删除了Criterion的生成,并且让内部类GeneratedCriteria继承BaseCriteria
那么下面是BaseExample的方法,配合BaseBean一起食用效果更佳(如果没有BaseBean那么Example也没什么用了)

public class BaseExample {
    protected String orderByClause;

    protected boolean distinct;

    protected List oredCriteria;

    public BaseExample() {
        oredCriteria = new ArrayList();
    }

    public void setOrderByClause(String orderByClause) {
        this.orderByClause = orderByClause;
    }

    public String getOrderByClause() {
        return orderByClause;
    }

    public void setDistinct(boolean distinct) {
        this.distinct = distinct;
    }

    public boolean isDistinct() {
        return distinct;
    }

    public List getOredCriteria() {
        return oredCriteria;
    }

    public void or(BaseCriteria criteria) {
        oredCriteria.add(criteria);
    }

    public BaseCriteria or() {
        BaseCriteria criteria = createCriteriaInternal();
        oredCriteria.add(criteria);
        return criteria;
    }

    public BaseCriteria createCriteria() {
        BaseCriteria criteria = createCriteriaInternal();
        if (oredCriteria.size() == 0) {
            oredCriteria.add(criteria);
        }
        return criteria;
    }

    protected BaseCriteria createCriteriaInternal() {
        BaseCriteria criteria = new BaseCriteria();
        return criteria;
    }

    public void clear() {
        oredCriteria.clear();
        orderByClause = null;
        distinct = false;
    }

    /**
     *
     *
     * @author wcyong
     *
     * @date 2019-11-27
     */
    public abstract static class GeneratedCriteria {
        protected List criteria;

        protected GeneratedCriteria() {
            super();
            criteria = new ArrayList();
        }

        public boolean isValid() {
            return criteria.size() > 0;
        }

        public List getAllCriteria() {
            return criteria;
        }

        public List getCriteria() {
            return criteria;
        }

        protected void addCriterion(String condition) {
            if (condition == null) {
                throw new RuntimeException("Value for condition cannot be null");
            }
            criteria.add(new Criterion(condition));
        }

        protected void addCriterion(String condition, Object value, String property) {
            if (value == null) {
                throw new RuntimeException("Value for " + property + " cannot be null");
            }
            criteria.add(new Criterion(condition, value));
        }

        protected void addCriterion(String condition, Object value1, Object value2, String property) {
            if (value1 == null || value2 == null) {
                throw new RuntimeException("Between values for " + property + " cannot be null");
            }
            criteria.add(new Criterion(condition, value1, value2));
        }

        public BaseCriteria andIdIsNull() {
            addCriterion("id is null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdIsNotNull() {
            addCriterion("id is not null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdEqualTo(Long value) {
            addCriterion("id =", value, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdNotEqualTo(Long value) {
            addCriterion("id <>", value, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdGreaterThan(Long value) {
            addCriterion("id >", value, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdGreaterThanOrEqualTo(Long value) {
            addCriterion("id >=", value, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdLessThan(Long value) {
            addCriterion("id <", value, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdLessThanOrEqualTo(Long value) {
            addCriterion("id <=", value, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdIn(List values) {
            addCriterion("id in", values, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdNotIn(List values) {
            addCriterion("id not in", values, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdBetween(Long value1, Long value2) {
            addCriterion("id between", value1, value2, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdNotBetween(Long value1, Long value2) {
            addCriterion("id not between", value1, value2, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeIsNull() {
            addCriterion("create_time is null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeIsNotNull() {
            addCriterion("create_time is not null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeEqualTo(Date value) {
            addCriterion("create_time =", value, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeNotEqualTo(Date value) {
            addCriterion("create_time <>", value, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeGreaterThan(Date value) {
            addCriterion("create_time >", value, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeGreaterThanOrEqualTo(Date value) {
            addCriterion("create_time >=", value, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeLessThan(Date value) {
            addCriterion("create_time <", value, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeLessThanOrEqualTo(Date value) {
            addCriterion("create_time <=", value, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeIn(List values) {
            addCriterion("create_time in", values, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeNotIn(List values) {
            addCriterion("create_time not in", values, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeBetween(Date value1, Date value2) {
            addCriterion("create_time between", value1, value2, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeNotBetween(Date value1, Date value2) {
            addCriterion("create_time not between", value1, value2, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeIsNull() {
            addCriterion("update_time is null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeIsNotNull() {
            addCriterion("update_time is not null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeEqualTo(Date value) {
            addCriterion("update_time =", value, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeNotEqualTo(Date value) {
            addCriterion("update_time <>", value, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeGreaterThan(Date value) {
            addCriterion("update_time >", value, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeGreaterThanOrEqualTo(Date value) {
            addCriterion("update_time >=", value, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeLessThan(Date value) {
            addCriterion("update_time <", value, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeLessThanOrEqualTo(Date value) {
            addCriterion("update_time <=", value, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeIn(List values) {
            addCriterion("update_time in", values, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeNotIn(List values) {
            addCriterion("update_time not in", values, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeBetween(Date value1, Date value2) {
            addCriterion("update_time between", value1, value2, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeNotBetween(Date value1, Date value2) {
            addCriterion("update_time not between", value1, value2, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserIsNull() {
            addCriterion("create_user is null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserIsNotNull() {
            addCriterion("create_user is not null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserEqualTo(Long value) {
            addCriterion("create_user =", value, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserNotEqualTo(Long value) {
            addCriterion("create_user <>", value, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserGreaterThan(Long value) {
            addCriterion("create_user >", value, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserGreaterThanOrEqualTo(Long value) {
            addCriterion("create_user >=", value, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserLessThan(Long value) {
            addCriterion("create_user <", value, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserLessThanOrEqualTo(Long value) {
            addCriterion("create_user <=", value, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserIn(List values) {
            addCriterion("create_user in", values, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserNotIn(List values) {
            addCriterion("create_user not in", values, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserBetween(Long value1, Long value2) {
            addCriterion("create_user between", value1, value2, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserNotBetween(Long value1, Long value2) {
            addCriterion("create_user not between", value1, value2, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserIsNull() {
            addCriterion("update_user is null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserIsNotNull() {
            addCriterion("update_user is not null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserEqualTo(Long value) {
            addCriterion("update_user =", value, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserNotEqualTo(Long value) {
            addCriterion("update_user <>", value, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserGreaterThan(Long value) {
            addCriterion("update_user >", value, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserGreaterThanOrEqualTo(Long value) {
            addCriterion("update_user >=", value, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserLessThan(Long value) {
            addCriterion("update_user <", value, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserLessThanOrEqualTo(Long value) {
            addCriterion("update_user <=", value, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserIn(List values) {
            addCriterion("update_user in", values, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserNotIn(List values) {
            addCriterion("update_user not in", values, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserBetween(Long value1, Long value2) {
            addCriterion("update_user between", value1, value2, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserNotBetween(Long value1, Long value2) {
            addCriterion("update_user not between", value1, value2, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionIsNull() {
            addCriterion("version is null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionIsNotNull() {
            addCriterion("version is not null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionEqualTo(Integer value) {
            addCriterion("version =", value, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionNotEqualTo(Integer value) {
            addCriterion("version <>", value, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionGreaterThan(Integer value) {
            addCriterion("version >", value, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionGreaterThanOrEqualTo(Integer value) {
            addCriterion("version >=", value, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionLessThan(Integer value) {
            addCriterion("version <", value, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionLessThanOrEqualTo(Integer value) {
            addCriterion("version <=", value, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionIn(List values) {
            addCriterion("version in", values, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionNotIn(List values) {
            addCriterion("version not in", values, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionBetween(Integer value1, Integer value2) {
            addCriterion("version between", value1, value2, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionNotBetween(Integer value1, Integer value2) {
            addCriterion("version not between", value1, value2, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagIsNull() {
            addCriterion("delete_flag is null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagIsNotNull() {
            addCriterion("delete_flag is not null");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagEqualTo(Boolean value) {
            addCriterion("delete_flag =", value, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagNotEqualTo(Boolean value) {
            addCriterion("delete_flag <>", value, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagGreaterThan(Boolean value) {
            addCriterion("delete_flag >", value, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagGreaterThanOrEqualTo(Boolean value) {
            addCriterion("delete_flag >=", value, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagLessThan(Boolean value) {
            addCriterion("delete_flag <", value, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagLessThanOrEqualTo(Boolean value) {
            addCriterion("delete_flag <=", value, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagIn(List values) {
            addCriterion("delete_flag in", values, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagNotIn(List values) {
            addCriterion("delete_flag not in", values, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagBetween(Boolean value1, Boolean value2) {
            addCriterion("delete_flag between", value1, value2, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagNotBetween(Boolean value1, Boolean value2) {
            addCriterion("delete_flag not between", value1, value2, "deleteFlag");
            return (BaseCriteria) this;
        }
    }

    public static class BaseCriteria extends GeneratedCriteria {

        public BaseCriteria() {
            super();
        }
    }

    /**
     *
     *
     * @author wcyong
     *
     * @date 2019-11-27
     */
    public static class Criterion {
        private String condition;

        private Object value;

        private Object secondValue;

        private boolean noValue;

        private boolean singleValue;

        private boolean betweenValue;

        private boolean listValue;

        private String typeHandler;

        public String getCondition() {
            return condition;
        }

        public Object getValue() {
            return value;
        }

        public Object getSecondValue() {
            return secondValue;
        }

        public boolean isNoValue() {
            return noValue;
        }

        public boolean isSingleValue() {
            return singleValue;
        }

        public boolean isBetweenValue() {
            return betweenValue;
        }

        public boolean isListValue() {
            return listValue;
        }

        public String getTypeHandler() {
            return typeHandler;
        }

        public Criterion(String condition) {
            super();
            this.condition = condition;
            this.typeHandler = null;
            this.noValue = true;
        }

        protected Criterion(String condition, Object value, String typeHandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.typeHandler = typeHandler;
            if (value instanceof List) {
                this.listValue = true;
            } else {
                this.singleValue = true;
            }
        }

        public Criterion(String condition, Object value) {
            this(condition, value, null);
        }

        protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {
            super();
            this.condition = condition;
            this.value = value;
            this.secondValue = secondValue;
            this.typeHandler = typeHandler;
            this.betweenValue = true;
        }

        public Criterion(String condition, Object value, Object secondValue) {
            this(condition, value, secondValue, null);
        }
    }
}

这里需要注意getOredCriteria方法,因为如果返回BaseCriteria子类是无法重写的,所以返回这种方式List,因为上面在生成子类时我们继承了BaseCriteria
这个时候我们更改BaseServiceImpl为

@Service("baseServiceImpl")
public abstract class BaseServiceImpl implements BaseService {

    @Autowired
    private BaseMapper baseMapper;

请注意,BaseServiceImpl必须必须必须必须必须必须必须必须加上abstract修饰符。否则在BaseMapper有多个子类的情况下,spring会不知道注入哪一个

/**
 * @author Connor
 * 逆向工程增强之通用mapper
 */
@Repository("baseMapper")
public interface BaseMapper {
    int countByExample(E example);

    int deleteByExample(E example);

    int deleteByPrimaryKey(Long id);

    int insert(T record);

    int insertSelective(T record);

    List selectByExample(E example);

    T selectByPrimaryKey(Long id);

    int updateByExampleSelective(@Param("record") T record, @Param("example") E example);

    int updateByExample(@Param("record") T record, @Param("example") E example);

    int updateByPrimaryKeySelective(T record);

    int updateByPrimaryKey(T record);
}

那么随便举个例子:

@Override
    public List selectByExample(E example) {
        E.BaseCriteria criteria = example.createCriteria();
        criteria.andCreateTimeBetween(new Date(), new Date());
        criteria.andDeleteFlagEqualTo(false);
        return baseMapper.selectByExample(example);
    }

比如说你可以这样写

@Override
    public List selectByExample(E example) {
        E.BaseCriteria criteria = example.getBaseOredCriteria().get(0);
        if (criteria == null) {
            criteria = example.createCriteria(); 
        }
        criteria.andCreateTimeBetween(new Date(), new Date());
        criteria.andDeleteFlagEqualTo(false);
        return baseMapper.selectByExample(example);
    }

也可以使用链式编程,像这样

@Override
    public List selectByExample(E example) {
        E.BaseCriteria criteria = example.getBaseOredCriteria().get(0);
        if (criteria == null) {
            criteria = example.createCriteria();
        }
        criteria.andCreateTimeBetween(new Date(), new Date())
                .andDeleteFlagEqualTo(false)
                .andDeleteFlagEqualTo(false)
                .andDeleteFlagEqualTo(false)
                .andDeleteFlagEqualTo(false)
                .andDeleteFlagEqualTo(false);
        return baseMapper.selectByExample(example);
    }

这样就不会覆盖之前的criteria,可以在这个基础上加上除了逻辑删除版本号之类的别的项目中的特性。

继续更新

我们让生成的Bean如何去继承BaseBean并且字段不重复呢?当然,是有插件的,但是我认为我找插件的速度没我写的快,那我就开始造个轮子(事实上别有他用)
在插件类中加入方法modelBaseRecordClassGenerated,当然也可以新建class,为了偷懒就不新建了

public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        String baseBean = "com.xxx.modules.common.entity.BaseBean";
        topLevelClass.addImportedType(new FullyQualifiedJavaType(baseBean));
        topLevelClass.setSuperClass(new FullyQualifiedJavaType(baseBean));
        List list = topLevelClass.getJavaDocLines();
        list.set(3, " * @author Connor");
        return true;
    }

可以看到,继承的操作十分简单,引入父类,继承父类,这就完成了继承这部分并且调皮的改一下Java Doc(事实上可以配置rootClass)所以这里只是去熟悉如何去改Java Doc的,addImportedTypesetSuperClass则分别是引入一个类和继承一个类。


    

下面开始造去除重复字段的轮子。字段本身

public boolean modelFieldGenerated(Field field, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
        String baseBean = "com.xxx.modules.common.entity.BaseBean";
        try {
            Class clazz = Class.forName(baseBean);
            if (clazz.getDeclaredField(field.getName()) != null) {
                // 如果BaseBean字段名和当前字段相同不生成
                return false;
            }
        } catch (ClassNotFoundException | NoSuchFieldException e) {
            // 合理运用异常,如果找不到字段那么代表字段需要生成
            return true;
        }
        return true;
    }

set方法,请参考get方法的注释,只是在基础上多了一个参数类型的判断(甚至都可以不要,因为数据库字段不可能相同,不需要考虑重载的问题)

public boolean modelSetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
        String baseBean = "com.xxx.modules.common.entity.BaseBean";
        try {
            Class clazz = Class.forName(baseBean);
            List parameters = method.getParameters();
            if (clazz.getMethod(method.getName(), Class.forName(parameters.get(0).getType().getFullyQualifiedName()))  != null) {
                return false;
            }
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            return true;
        }
        return true;
    }

那么造轮子的工作到此结束,你要问我get去哪了,那我只能告诉你,get它不是轮子!

public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
        String baseBean = "com.xxx.modules.common.entity.BaseBean";
        try {
            Class clazz = Class.forName(baseBean);
            if (clazz.getMethod(method.getName()) != null) {
                return false;
            }
        } catch (ClassNotFoundException | NoSuchMethodException e) {
            if (introspectedColumn.getDefaultValue() != null) {
                Method defaultMethod = new Method();
                List bodyLines = method.getBodyLines();
                String fieldName = bodyLines.get(0).replace("return ", "").replace(";", "");
                defaultMethod.setName(method.getName() + "DefaultValue");
                String newBodyLine = "return " + fieldName + " == null ? " + getColumnDefaultValue(introspectedColumn) + " : " + fieldName + ";";
                defaultMethod.setReturnType(method.getReturnType());
                defaultMethod.setConstructor(false);
                defaultMethod.setNative(false);
                defaultMethod.setSynchronized(false);
                defaultMethod.setFinal(false);
                defaultMethod.setStatic(false);
                defaultMethod.setVisibility(JavaVisibility.PUBLIC);
                defaultMethod.addBodyLine(newBodyLine);
                topLevelClass.addMethod(defaultMethod);
            }
            return true;
        }
        return true;
    }

private String getColumnDefaultValue(IntrospectedColumn introspectedColumn) {
        String value = introspectedColumn.getDefaultValue();
        if (value == null) {
            return null;
        }
        switch (introspectedColumn.getJdbcTypeName()) {
            case "BIGINT":
                return value + "L";
            case "DECIMAL":
                return "new BigDecimal(\""  + value +  "\")";
            case "VARCHAR":
                return value.isEmpty() ? "\"\"" : "\"" + value + "\"";
            case "BIT":
                return value.equals("b'0'") ? "false" : "true";
            default: return value;
        }
    }

需要注意的是,我们是在类似于拼接sql语句一样拼接代码,所以返回值如果是字符串的话,需要加上双引号。这里就写完数据库用到的字段种类就可以了。
看到这里大家应该知道我的目的了,我重新定义了一个方法(在数据库有默认值的时候才会生成这个方法getXxxDefaultValue)
那么可以做什么呢?
创建一个构造器,传入参数是否需要默认值,这样又可以不用写很多代码了,而且数据库改变后文件重新生成一遍,互不打扰。基本上所有生成的都改过了,后面的这部分算是逆向工程二次开发的文章了吧。
事实上在业务较为复杂的系统中使用该技术是十分有必要的,因为copy/replace的代码部分是很枯燥的并且容易出错,所以尽早解放双手吧。
你还可以在BaseServiceImpl中增加常用组件,比如Redis

    //和BaseMapper一样去定义就可以了
    @Autowired
    protected BaseMapper baseMapper;

    /**
     * 常用组件之redis
     */
    @Autowired
    protected RedisUtils redisUtils;

在子Service中去定义

String testRedis();

在子实现中去使用

    @Override
    public String testRedis() {
        redisUtils.set("aaa", "222");
        return redisUtils.get("aaa");
    }

测试结果:


image.png

基本的封装就到这里了,还有可以扩展的地方欢迎留言

你可能感兴趣的:(Java技术贴之Mybatis逆向工程增强)