mybatis-plus代码生成器自定义模板

    最近接受到一个任务,代码生成器的开发。当时自己有两种思路来实现,第一种:自己写个程序,通过java代码生成,第二种:寻找第三方插件来支持,引用他们的。当时自己开发了一个代码生成器程序,但是不够完善,不能全面满足需求,还是借鉴他人意见,网上查询资料,发现Mybatis-plus插件还是挺不错,分享给大家,不过本人才疏学浅,若有说的不对,还望大家指出来。
 

  1.    Mybatis-plus官网,有兴趣的可以了解了解,学习学习的。
  2.    官网配置代码生成器的例子。

   

   当时针对参数校验方面,是需要判断表中字段非空约束,可是查看了Mybatis-plus的源代码,一直没有找出非空字段,幸好TableField中有个  customMap  map结构,只好通过jdbc去查询sql,获取字段的非空约束,再设置到customMap中。

package com.poi.code.creator.tool;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.converts.PostgreSqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.config.rules.PropertyInfo;
import com.google.common.collect.Maps;
import com.poi.code.creator.config.OrdinaryGeneratorConfig;
import com.poi.code.creator.util.SQLExecutor;

//import lombok.Data;
//import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 方式二:代码生成器
 * 可按照表 生成crud。
 * </P>
 *
 * @author : dengbin
 * @date :  2019/10/11
 */
//@RunWith(SpringRunner.class)
//@SpringBootTest(classes = Application.class)
//@Data
//@Slf4j
public class OrdinaryCodeGenerator {


//    @Autowired
//    private OrdinaryGeneratorConfig ordinaryGeneratorConfig;


    private final static String sql = "SELECT a.attnum,\n" +
            "       a.attname AS name,\n" +
            "       t.typname AS type,\n" +
            "       a.attlen AS length,\n" +
            "       a.atttypmod AS lengthvar,\n" +
            "       a.attnotnull AS isNull,\n" +
            "       b.description AS columnComment\n" +
            "  FROM pg_class c,\n" +
            "       pg_attribute a\n" +
            "       LEFT OUTER JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid,\n" +
            "       pg_type t\n" +
            " WHERE c.relname =" + " ? \n" +
            "       and a.attnum > 0\n" +
            "       and a.attrelid = c.oid\n" +
            "       and a.atttypid = t.oid\n" +
            " ORDER BY a.attnum";

    private final static Map<String, Object> params = Maps.newHashMap();
    private final static List<String> placeholderNameList = Collections.singletonList("tableName");


    public static void main(String[] args) throws IOException {
        OrdinaryGeneratorConfig ordinaryGeneratorConfig = new OrdinaryGeneratorConfig();
        ordinaryGeneratorConfig.setAbsolutePath("src/main/java");
        ordinaryGeneratorConfig.setAuthor("dengbin");
        ordinaryGeneratorConfig.setRelativeName("com.poi.code.creator");
        ordinaryGeneratorConfig.setTables("ent_i_meter");
        generateCode(ordinaryGeneratorConfig);
    }

    public static void generateCode(OrdinaryGeneratorConfig ordinaryGeneratorConfig) throws IOException {

        String author = ordinaryGeneratorConfig.getAuthor();
        String resultPath = ordinaryGeneratorConfig.getAbsolutePath() + "/" + ordinaryGeneratorConfig.getRelativeName().replace(".", "/");
        boolean exists = new File(resultPath).exists();
        if (!exists) {
            throw new RuntimeException("目录:" + resultPath + "不存在,请重新确认!");
        }
        String tables = ordinaryGeneratorConfig.getTables();
        params.put("tableName", tables);

        //获取数据库连接
        GlobalConfig config = new GlobalConfig();
        String dbUrl = "你的数据库url链接";
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDbType(DbType.POSTGRE_SQL)
                .setUrl(dbUrl)
                .setUsername("你的数据库用户名称")
                .setPassword("你的数据库用户账号")
                .setDriverName("org.postgresql.Driver")
                .setSchemaName("**");

        //类型转换
        dataSourceConfig.setTypeConvert(new PostgreSqlTypeConvert() {
            @Override
            public PropertyInfo processTypeConvert(GlobalConfig globalConfig, String fieldType) {
                System.out.println("转换类型:" + fieldType);
                // 注意!!processTypeConvert 存在默认类型转换,如果不是你要的效果请自定义返回、非如下直接返回。
                if (fieldType.contains("numeric")) {
                    return DbColumnType.DOUBLE;
                } else {
                    return super.processTypeConvert(globalConfig, fieldType);
                }
            }
        });

        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig
                .setCapitalMode(true)
                .setLogicDeleteFieldName("rec_status")
                .setEntityLombokModel(false)
                .setNaming(NamingStrategy.underline_to_camel)
//                .setTablePrefix("eff_","ent_i_","ent_s_","ent_r_","eqp_i_","eqp_r_","eqp_s_","prod_i_","prod_r_","prod_s_","sys_i_")
                .setInclude(tables)                               //修改替换成你需要的表名,多个表名传数组
                .setEntityLombokModel(true);                      //是否使用lombok
        config.setActiveRecord(true)
                .setAuthor(author)
                .setOutputDir(ordinaryGeneratorConfig.getAbsolutePath())
                .setEnableCache(false)
                .setBaseColumnList(false)
                .setBaseColumnList(false)
                .setIdType(IdType.AUTO)                            //主键类型  定死id自增
                .setFileOverride(true)
                .setServiceName("%sService")
                .setSwagger2(true);                                //是否使用Swagger

        InjectionConfig ic = new InjectionConfig() {
            @Override
            public void initMap() {
                this.setMap(getMap());
            }
        };
        TemplateConfig tc = new TemplateConfig();
        tc.setXml(null)
                .setServiceImpl(null)
                .setController("template/controller.java.vm")
                .setEntity("template/entity.java.vm")
                .setService("template/service.java.vm");

        //添加add 请求对象
        List<FileOutConfig> foc = new ArrayList<>();
        foc.add(new FileOutConfig("/template/addVo.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                setCustomMap(tableInfo);
                return resultPath + "/vo/req/Add" + tableInfo.getEntityName() + "Req"
                        + StringPool.DOT_JAVA;
            }
        });
        //添加update 请求对象
        foc.add(new FileOutConfig("/template/updateVo.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                setCustomMap(tableInfo);
                return resultPath + "/vo/req/Update" + tableInfo.getEntityName() + "Req"
                        + StringPool.DOT_JAVA;
            }
        });
        //添加list请求对象
        foc.add(new FileOutConfig("/template/listVo.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return resultPath + "/vo/req/List" + tableInfo.getEntityName() + "Req"
                        + StringPool.DOT_JAVA;
            }
        });
        //添加分页请求对象
        foc.add(new FileOutConfig("/template/pageVo.java.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return resultPath + "/vo/req/Page" + tableInfo.getEntityName() + "Req"
                        + StringPool.DOT_JAVA;
            }
        });
        ic.setFileOutConfigList(foc);
        new AutoGenerator()
                .setGlobalConfig(config)
                .setDataSource(dataSourceConfig)
                .setStrategy(strategyConfig)
                .setTemplate(tc)
                .setCfg(ic)
                .setPackageInfo(
                        new PackageConfig()
                                .setParent(ordinaryGeneratorConfig.getRelativeName())
                                .setController("controller")
                                .setEntity("entity")
                ).execute();
    }

    private static void setCustomMap(TableInfo tableInfo) {
        List<Map<String, Object>> execute = SQLExecutor.execute(sql, params, placeholderNameList);
        List<TableField> fields = tableInfo.getFields();
        for (TableField field : fields) {
            Optional<Map<String, Object>> mapOptional = execute.stream().filter(item -> item.get("name").equals(field.getName())).findAny();
            Map<String, Object> customMap = Maps.newHashMap();
            mapOptional.ifPresent(stringObjectMap -> customMap.put("isNull", (Boolean) stringObjectMap.get("isnull")));
            field.setCustomMap(customMap);
        }
    }
}

   controller的模板(controller.java.vm)内容如下:

package ${package.Controller};

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import ${package.Service.replace(".service","")}.service.${table.serviceName} ;
import ${package.Service.replace(".service","")}.vo.req.Add${entity}Req;
import ${package.Service.replace(".service","")}.vo.req.List${entity}Req;
import ${package.Service.replace(".service","")}.vo.req.Page${entity}Req;
import ${package.Service.replace(".service","")}.vo.req.Update${entity}Req;
import com.poit.commons.utils.resp.ApiResp;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;



/**
* @author ${author}
* @since ${date}
*/
@Api(description = "$!{table.comment}")
@RestController
@RequestMapping("/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end" )
@Slf4j
public class ${table.controllerName}  {

    @Autowired
    private ${table.serviceName}  ${table.entityPath}Service;

    @ApiOperation("列表")
    @GetMapping("/list")
    public ApiResp list(List${entity}Req req) throws Exception {
        return ${table.entityPath}Service.list(req);
    }

    @ApiOperation("分页")
    @GetMapping("/page")
    public ApiResp page(Page${entity}Req req) throws Exception {
        return ${table.entityPath}Service.page(req);
    }

    @ApiOperation("获取详情")
    @GetMapping("/get")
    public ApiResp get(#foreach($field in ${table.fields})#if(${field.keyFlag})@RequestParam("${field.propertyName}") ${field.propertyType} ${field.propertyName}#end#end) throws Exception {
        return ${table.entityPath}Service.get(#foreach($field in ${table.fields})#if(${field.keyFlag})${field.propertyName}#end#end);
    }

    @ApiOperation("添加")
    @PostMapping("/add")
    public ApiResp add(@Valid @RequestBody Add${entity}Req req) throws Exception {
        return ${table.entityPath}Service.add(req);
    }

    @ApiOperation("修改")
    @PostMapping("/modify")
    public ApiResp modify(@Valid @RequestBody Update${entity}Req req) throws Exception {
        return ${table.entityPath}Service.modify(req);
    }

    @ApiOperation("删除")
    @GetMapping("/delete")
    public ApiResp delete(#foreach($field in ${table.fields})#if(${field.keyFlag})@RequestParam("${field.propertyName}") ${field.propertyType} ${field.propertyName}#end#end) throws Exception {
        return ${table.entityPath}Service.delete(#foreach($field in ${table.fields})#if(${field.keyFlag})${field.propertyName}#end#end);
    }
 }

entity.java.vm

package ${package.Entity};

    #foreach($pkg in ${table.importPackages})
    import ${pkg};
    #end
    #if(${swagger2})
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    #end
    #if(${entityLombokModel})
    import lombok.Data;
    #end
import com.baomidou.mybatisplus.annotation.TableName;

import javax.validation.constraints.Size;
/**
 * <p>
 * ${entity}对象
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
#if(${entityLombokModel})
@Data
#end
@TableName("${table.name}")
#if(${swagger2})
@ApiModel(value = "${entity}对象", description = "$!{table.comment}")
#end
#if(${superEntityClass})
public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
#elseif(${activeRecord})
public class ${entity} extends Model<${entity}> {
#else
public class ${entity} implements Serializable{
#end

## ----------  BEGIN 字段循环遍历  ----------
#foreach($field in ${table.fields})
    #if(${field.keyFlag})
        #set($keyPropertyName=${field.propertyName})
    #end
    #if("$!field.comment" != "")
        #if(${swagger2})
    @ApiModelProperty(value = "${field.comment}")
        #end
    #end
    #if(${field.keyFlag})
        #if(${field.keyIdentityFlag})
    @TableId(value = "${field.name}", type = IdType.AUTO)
        #elseif(!$null.isNull(${idType}) && "$!idType" != "")
    @TableId(value = "${field.name}", type = IdType.${idType})
        #elseif(${field.convert})
    @TableId("${field.name}")
        #end
    #elseif(${field.fill})
        #if(${field.convert})
        @TableField(value = "${field.name}", fill = FieldFill.${field.fill})
        #else
        @TableField(fill = FieldFill.${field.fill})
        #end
    #elseif(${field.convert})
    @TableField("${field.name}")
    #end
    #if(${logicDeleteFieldName}==${field.name})
    @TableLogic
    #end
    #if(${field.columnType}=="STRING" && ${field.type} !="text")
    @Size(max = ${field.type.replace("character varying(","").replace(")","")}, message = "${field.comment}应该在0-${field.type.replace("character varying(","").replace(")","")}字符之间")
    #end
    private ${field.propertyType} ${field.propertyName};

#end
#if(!${entityLombokModel})
    #foreach($field in ${table.fields})
        #if(${field.propertyType.equals("boolean")})
            #set($getprefix="is")
        #else
            #set($getprefix="get")
        #end
    public ${field.propertyType} ${getprefix}${field.capitalName}(){
            return ${field.propertyName};
            }
        #if(${entityBuilderModel})
        public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}){
        #else
        public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
        #end
            this.${field.propertyName} = ${field.propertyName};
        #if(${entityBuilderModel})
                return this;
        #end
            }
    #end
#end

#if(${entityColumnConstant})
    #foreach($field in ${table.fields})
    public static final String ${field.name.toUpperCase()} ="${field.name}";
    #end
#end
#if(${activeRecord})
    @Override
    protected Serializable pkVal(){
    #if(${keyPropertyName})
        return this.${keyPropertyName};
    #else
            return null;
    #end
    }
#end
#if(!${entityLombokModel})
@Override
public String toString() {
        return "${entity}{" +
    #foreach($field in ${table.fields})
        #if($!{foreach.index}==0)
                "${field.propertyName}=" + ${field.propertyName} +
        #else
                ", ${field.propertyName}=" + ${field.propertyName} +
        #end
    #end
        "}";
        }
#end
}

service.java.vm

package ${package.Service};

import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${package.Entity}.${entity};
import ${package.Mapper}.${table.mapperName};
import ${package.Service.replace(".service","")}.vo.req.Add${entity}Req;
import ${package.Service.replace(".service","")}.vo.req.List${entity}Req;
import ${package.Service.replace(".service","")}.vo.req.Page${entity}Req;
import ${package.Service.replace(".service","")}.vo.req.Update${entity}Req;
import com.poit.commons.utils.resp.ApiResp;

/**
 * <p>
 * ${entity}服务类
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@Service
public class ${table.serviceName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}>  {

    public ApiResp list(List${entity}Req req)throws Exception{
        String keyword = req.getKeyword();
        QueryWrapper<${entity}> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(keyword)) {
            queryWrapper.like("", req.getKeyword());
        }
        return  ApiResp.of(baseMapper.selectList(queryWrapper));
    }

    public ApiResp page(Page${entity}Req req)throws Exception{
        String keyword = req.getKeyword();
        IPage<${entity}> page = new Page<>(req.getPageNum(), req.getPageSize());
        QueryWrapper<${entity}> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(keyword)) {
            queryWrapper.like("", keyword);
        }
        return  ApiResp.of(baseMapper.selectPage(page, queryWrapper));
    }

    public ApiResp add(Add${entity}Req req)throws Exception{
        ${entity} data = new  ${entity}();
        BeanUtils.copyProperties(req, data);
        #foreach($field in ${table.fields})
            #if(${field.propertyName.equals("createTime")})
        data.set${field.capitalName}(new Date());
            #end
        #end
        baseMapper.insert(data);
        return  ApiResp.of(#foreach($field in ${table.fields})#if(${field.keyFlag})data.get${field.capitalName}()#end#end);
    }

    public ApiResp modify(Update${entity}Req req)throws Exception{
        ${entity} data = new  ${entity}();
        BeanUtils.copyProperties(req, data);
        #foreach($field in ${table.fields})
           #if(${field.propertyName.equals("updateTime")} || ${field.propertyName.equals("modifyTime")})
        data.set${field.capitalName}(new Date());
           #end
        #end
        baseMapper.updateById(data);
        return ApiResp.of(Boolean.TRUE);
    }

    public ApiResp delete(#foreach($field in ${table.fields})#if(${field.keyFlag})${field.propertyType} ${field.propertyName}#end#end)throws Exception{
        baseMapper.deleteById(#foreach($field in ${table.fields})#if(${field.keyFlag})${field.propertyName}#end#end);
        return ApiResp.of(Boolean.TRUE);
    }

    public ApiResp get(#foreach($field in ${table.fields})#if(${field.keyFlag})${field.propertyType} ${field.propertyName}#end#end)throws Exception{
        return ApiResp.of(baseMapper.selectById(#foreach($field in ${table.fields})#if(${field.keyFlag})${field.propertyName}#end#end));
    }
}

接下来VO对象,请求对象,返回对象  

package  ${package.Service.replace(".service","")}.vo.req;


import java.io.Serializable;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * <p>
 * Add${entity}Req 请求对象
 * </p>
 *
 * @author ${author}
 * @since ${date}
 */
@Data
@ApiModel(value = "${entity}新增请求对象", description = "$!{table.comment}")
public class Add${entity}Req implements Serializable {

    #foreach($field in ${table.fields})
    #if(${swagger2} && !${field.propertyName.equals("recStatus")}  &&!${field.propertyName.equals("updateTime")}  &&!${field.propertyName.equals("createTime")} &&!${field.propertyName.equals("modifyTime")}&&!${field.keyFlag})
    #if("$!field.comment" != "")
    @ApiModelProperty(value = "${field.comment}")
    #else
    @ApiModelProperty(value = "")
    #end
    #if(${field.columnType}=="STRING" && ${field.type} !="text")
    @Size(max = ${field.type.replace("character varying(","").replace(")","")}, message = "${field.comment}应该在0-${field.type.replace("character varying(","").replace(")","")}字符之间")
    #end
    #if(${field.customMap.get("isNull")})
    @NotNull(message = "${field.comment}不能为空")
    #end
    private ${field.propertyType} ${field.propertyName};

            #end
        #end
}

 

MyBatis-Plus代码生成器提供了自定义模板的功能,可以根据自己的需求生成对应的代码。下面是自定义模板的处理步骤: 1. 在代码生成器的配置文件中,设置自定义模板的路径。例如: ``` <property name="templatePath" value="/templates/mybatis-plus"/> ``` 2. 在自定义模板路径下创建对应的模板文件。例如,创建一个模板文件 `Entity.java.vm`,用于生成实体类的代码。 3. 在模板文件中使用 Velocity 模板语言,编写生成代码的逻辑。例如: ``` package ${package_name}.${module_name}.entity; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** * <p> * ${table_comment} * </p> */ @Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @TableName("${table_name}") public class ${entity_name} { private static final long serialVersionUID = 1L; #foreach($field in $fields) /** * ${field.comment} */ private ${field.javaType} ${field.name}; #end } ``` 4. 在代码生成器中配置要使用的自定义模板。例如: ``` <property name="templateConfig"> <bean class="com.baomidou.mybatisplus.generator.config.TemplateConfig"> <property name="entity" value="/templates/mybatis-plus/Entity.java.vm"/> <property name="mapper" value="/templates/mybatis-plus/Mapper.java.vm"/> <property name="xml" value="/templates/mybatis-plus/Mapper.xml.vm"/> <property name="service" value="/templates/mybatis-plus/Service.java.vm"/> <property name="serviceImpl" value="/templates/mybatis-plus/ServiceImpl.java.vm"/> <property name="controller" value="/templates/mybatis-plus/Controller.java.vm"/> </bean> </property> ``` 在这个例子中,我们配置了生成实体类、Mapper接口、Mapper XML文件、Service接口、Service实现类和Controller类的模板路径。 5. 运行代码生成器,即可根据自定义模板生成对应的代码。 注意:自定义模板的命名必须与 MyBatis-Plus 内置模板的命名一致,才能正确覆盖内置模板。例如,要自定义生成实体类的模板,必须将模板文件命名为 `Entity.java.vm`。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值