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<String> 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文件的<generatorConfiguration>下的<context>标签内增加以下代码即可,像这样

<generatorConfiguration>
    <context id="testTables" targetRuntime="MyBatis3">
        <plugin type="MapperPlugin"/>

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

public interface BaseMapper<T, E> {
    int countByExample(E example);

    int deleteByExample(E example);

    int deleteByPrimaryKey(Long id);

    int insert(T record);

    int insertSelective(T record);

    List<T> 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<T> {

    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<T extends BaseBean, E> implements BaseService<T> {

    @Autowired
    private BaseMapper<T, E> 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<TPurchaserAccountLog> {
    // do nothing
}
@Service
public class TestServiceImpl extends BaseServiceImpl<TPurchaserAccountLog, TPurchaserAccountLogExample> implements TestService {
    // do nothing
}
@RestController
public class TestController {

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

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

@Autowired
BaseService<TPurchaserAccountLog, TPurchaserAccountLogExample> purchaserAccountLogService;

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

public interface BaseService<T, E> {

    int save(T t);

    int update(T t);

    int delete(Long id);

    T queryObject(Long id);

    List<T> selectByExample(E example);
}

BaseServiceImpl更改为

public class BaseServiceImpl<T extends BaseBean, E> implements BaseService<T, E> {

并增加实现

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

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

public class MapperPlugin extends PluginAdapter {

    @Override
    public boolean validate(List<String> 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<InnerClass> 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<BaseCriteria> oredCriteria;

    public BaseExample() {
        oredCriteria = new ArrayList<BaseCriteria>();
    }

    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<? extends BaseCriteria> 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<Criterion> criteria;

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

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

        public List<Criterion> getAllCriteria() {
            return criteria;
        }

        public List<Criterion> 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<Long> values) {
            addCriterion("id in", values, "id");
            return (BaseCriteria) this;
        }

        public BaseCriteria andIdNotIn(List<Long> 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<Date> values) {
            addCriterion("create_time in", values, "createTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateTimeNotIn(List<Date> 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<Date> values) {
            addCriterion("update_time in", values, "updateTime");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateTimeNotIn(List<Date> 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<Long> values) {
            addCriterion("create_user in", values, "createUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andCreateUserNotIn(List<Long> 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<Long> values) {
            addCriterion("update_user in", values, "updateUser");
            return (BaseCriteria) this;
        }

        public BaseCriteria andUpdateUserNotIn(List<Long> 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<Integer> values) {
            addCriterion("version in", values, "version");
            return (BaseCriteria) this;
        }

        public BaseCriteria andVersionNotIn(List<Integer> 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<Boolean> values) {
            addCriterion("delete_flag in", values, "deleteFlag");
            return (BaseCriteria) this;
        }

        public BaseCriteria andDeleteFlagNotIn(List<Boolean> 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<? extends BaseCriteria>,因为上面在生成子类时我们继承了BaseCriteria
这个时候我们更改BaseServiceImpl为

@Service("baseServiceImpl")
public abstract class BaseServiceImpl<T extends BaseBean, E extends BaseExample> implements BaseService<T, E> {

    @Autowired
    private BaseMapper<T, E> baseMapper;

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

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

    int deleteByExample(E example);

    int deleteByPrimaryKey(Long id);

    int insert(T record);

    int insertSelective(T record);

    List<T> 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<T> selectByExample(E example) {
        E.BaseCriteria criteria = example.createCriteria();
        criteria.andCreateTimeBetween(new Date(), new Date());
        criteria.andDeleteFlagEqualTo(false);
        return baseMapper.selectByExample(example);
    }

比如说你可以这样写

@Override
    public List<T> 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<T> 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<String> list = topLevelClass.getJavaDocLines();
        list.set(3, " * @author Connor");
        return true;
    }

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

<javaModelGenerator>
    <property name="rootClass" value="com.xxx.modules.common.entity.BaseBean"/>
<javaModelGenerator>

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

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<Parameter> 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<String> 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<T, E> baseMapper;

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

在子Service中去定义

String testRedis();

在子实现中去使用

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

测试结果:


image.png

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 1、什么是Mybatis? (1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只...
    月哥说了算阅读 461评论 0 0
  • 1.什么是Mybatis? 1、Mybatis 是一个半 ORM对象关系映射框架,内部封装了JDBC,开发时只需要...
    奇点一氪阅读 397评论 0 6
  • mybatis中的sqlSession是线程安全的吗? 链接:https://blog.csdn.net/qq_3...
    刘小刀tina阅读 2,076评论 0 3
  • 前段时间,把微信通讯录好好清理了一下。人数从之前的五六百,降至到了三百多。 看微信,在这个大型“鉴人”场域,不用多...
    马老师的职萃坊阅读 667评论 0 2
  • 有时候看别人的go代码,发现他们有的在代码里面用了指针,有的不使用。 假设有个结构体类型叫做Person, 发现有...
    iamdev阅读 1,946评论 0 2