springboot+freemarker实现代码逆向工程

 

采用架构,springboot+freemarker

工具:idea最新版,jdk1.8,mysql

创建boot工程,加依赖,jdbc,web,freemarker,lombok

创建生成界面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>代码生成</title>
    <!-- 开发环境版本,包含了有帮助的命令行警告 vue-->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <!--引入样式-->
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <!--引入组件库-->
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
    <table>
        <tr>
            <td><el-tag size="mini">数据库用户名:</el-tag></td>
            <td><el-input siez="mini" v-model="db.username"></el-input></td>
        </tr>
        <tr>
            <td><el-tag size="mini">数据库密码:</el-tag></td>
            <td><el-input siez="mini" v-model="db.password"></el-input></td>
        </tr>
        <tr>
            <td><el-tag size="mini">数据库连接地址:</el-tag></td>
            <td><el-input siez="mini" v-model="db.url">
                <template slot="prepend">jdbc:mysql://</template>
                <template slot="append">
                    ?useUnicode=true&characterEncoding=UTF-8
                </template>
            </el-input></td>
        </tr>
    </table>
    <div style="display: flex">
        <el-button type="primary"size="mini" @click="connect":disabled="!connectBtnEnabled">连接数据库</el-button>
        <div style="color: #ff0114;font-weight: bold">*{{msg}}*</div>
        <el-input v-model="packageName" size="mini" style="width: 300px"></el-input>
        <el-button type="primary" size="mini" @Click="config">配置</el-button>
    </div>
    <el-table
            :data="tableData"
            stripe
            border
            style="width: 100%">
        <el-table-column
                prop="tableName"
                label="表名称"
                width="180">
        </el-table-column>
        <el-table-column
                label="实体类名称"
                width="180">
            <template slot-scope="scope">
                <el-input v-model="scope.row.modelName"></el-input>
            </template>
        </el-table-column>
        <el-table-column
                label="Mapper名称">
            <template slot-scope="scope">
                <el-input v-model="scope.row.mapperName"></el-input>
            </template>
        </el-table-column>
        <el-table-column

                label="Service名称">
            <template slot-scope="scope">
                <el-input v-model="scope.row.serviceName"></el-input>
            </template>
        </el-table-column>
        <el-table-column
                label="Controller名称">
            <template slot-scope="scope">
                <el-input v-model="scope.row.controllerName"></el-input>
            </template>
        </el-table-column>
    </el-table>
    <div>
        <el-button @click="generateCode" type="success">生成代码</el-button>
    <div style="color: #ff0114;font-weight: bold">{{result}}</div>
        <div>{{codePath}}</div>
    </div>
</div>


<script>
    new Vue({
        el:"#app",
        data:function (){
            return {
                tableData: [],
                result:'',
                codePath:'',
                packageName: 'cn.nixiang',
                msg:'数据库未连接',
                connectBtnEnabled:true,
                db:{
                    username: "root",
                    password: "mysql",
                    url:"localhost:3306/emp"
                }
            }
        },
        methods:{
            generateCode(){
                let _this=this;
                axios.post('/generateCode',this.tableData)
                    .then(function (response) {
                    _this.result=response.data.msg;
                    _this.codePath=response.data.obj;
                    })
                    .catch(function (error) {
                        console.log(error);
                    });
            },
            config(){
                let  _this=this;
                axios.post('/config', {packageName:this.packageName})
                    .then(function (response) {
                        _this.msg=response.data.msg;//把返回数据展示到提示信息
                        _this.tableData=response.data.obj;//集合
                    })
                    .catch(function (error) {
                        console.log(error);
                    });
            },
            connect(){
                let  _this=this;
             this.db.url="jdbc:mysql://"+this.db.url+"?useUnicode=true&characterEncoding=UTF-8";
                axios.post('/connect', this.db)
                    .then(function (response) {
                        _this.msg=response.data.msg;//把返回数据展示到提示信息
                      _this.db= {
                            username: "root",
                                password: "mysql",
                                url: "localhost:3306/emp"
                        }
                        _this.connectBtnEnabled =false;
                    })
                    .catch(function (error) {
                        console.log(error);
                    });
            }
        }
    })
</script>
</body>
</html>
运行效果:
、
创建生成的属性类
@Data
public class RespBean {
    private Integer status;
    private String  msg;
    private  Object obj;
    private RespBean(){

    }

    public static  RespBean ok(String msg,Object obj){
        return  new RespBean(200,msg,obj);

    }
    //重载,有的时候不需要
    public static RespBean ok(String msg) {
        return  new RespBean(200,msg,null);
    }

private RespBean(Integer status, String msg, Object obj) {
        this.status = status;
        this.msg = msg;
        this.obj = obj;
    }

    public static  RespBean error(String msg,Object obj){
        return  new RespBean(500,msg,obj);

    }
    public static RespBean error(String msg) {
        return  new RespBean(500,msg,null);
    }
}

创建统一返回类

@Data
public class RespBean {
    private Integer status;
    private String  msg;
    private  Object obj;
    private RespBean(){

    }

    public static  RespBean ok(String msg,Object obj){
        return  new RespBean(200,msg,obj);

    }
    //重载,有的时候不需要
    public static RespBean ok(String msg) {
        return  new RespBean(200,msg,null);
    }

private RespBean(Integer status, String msg, Object obj) {
        this.status = status;
        this.msg = msg;
        this.obj = obj;
    }

    public static  RespBean error(String msg,Object obj){
        return  new RespBean(500,msg,obj);

    }
    public static RespBean error(String msg) {
        return  new RespBean(500,msg,null);
    }
}

创建数据库链接类,规定数据库链接信息

@Data
public class Db {
    private String username;
    private String password;
    private String url;
}

 

创建数据库读取接口,以及配置接口

@RestController
public class DbController {
    @PostMapping("/connect")
    public RespBean connection(@RequestBody Db db){
        Connection cn= DbUtils.initDb(db);
        if(cn!=null){
            return RespBean.ok("数据库链接成功");

        }
        return RespBean.error("数据库链接失败");

    }
    @PostMapping("/config")
    public RespBean config(@RequestBody Map<String,String> map){
        String packageName=map.get("packageName");
        try {
            Connection connection=DbUtils.getConnection();
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet tables=metaData.getTables(connection.getCatalog(),null,null,null);
            List<TableClass> tableClassList=new ArrayList<>();
            while(tables.next()){
                TableClass tableClass=new TableClass();
                tableClass.setPackageName(packageName);
                String table_name=tables.getString("TABLE_NAME");//获取表名
                String modelName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, table_name);//转换成驼峰写法
                tableClass.setTableName(table_name);//赋值表名
                tableClass.setControllerName(modelName+"Controller");
                tableClass.setModelName(modelName);//实体类
                tableClass.setMapperName(modelName+"Mapper");//mapper
                tableClass.setServiceName(modelName+"Service");
                tableClassList.add(tableClass);

            }
            return RespBean.ok("数据库信息读取成功",tableClassList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return RespBean.error("数据库信息读取失败");

    }
}

转换驼峰写法我这里是采用的google工具,

依赖如下:

<dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>28.2-android</version>
        </dependency>

具体实现方法;

@Service
public class GenerateCodeService {
        Configuration cfg =null;
    {
        //freemarker版本
        cfg=new Configuration(Configuration.VERSION_2_3_31);
        //设置一下模板,第一个当前类  第二个是模板位置
        cfg.setTemplateLoader(new ClassTemplateLoader(GenerateCodeService.class,"/templates"));
        //设置一下编码
        cfg.setDefaultEncoding("UTF-8");

    }
    public RespBean generateCode(List<TableClass> tableClassList, String realPath) {
        try {
            //获取模板
            Template modelTemplate=cfg.getTemplate("Model.java.ftl");
            Template serviceTemplate=cfg.getTemplate("Service.java.ftl");
            Template mapperJavaTemplate=cfg.getTemplate("Mapper.java.ftl");
            Template mapperXmlTemplate=cfg.getTemplate("Mapper.xml.ftl");
            Template controllerTemplate=cfg.getTemplate("Controller.java.ftl");

            //获取链接
            Connection connection= DbUtils.getConnection();
            DatabaseMetaData metaData = connection.getMetaData();//获取列的信息
            for (TableClass tableClass: tableClassList) {
                //获取列的信息
                ResultSet columns = metaData.getColumns(connection.getCatalog(), null, tableClass.getTableName(), null);
                //获取表中的主键
                ResultSet primaryKeys = metaData.getPrimaryKeys(connection.getCatalog(), null, tableClass.getTableName());
                List<ColumnClass>columnClassList=new ArrayList<>();
                while (columns.next()){
                    String column_name = columns.getString("COLUMN_NAME");//列明
                   String type_name = columns.getString("TYPE_NAME");//类型
                 String remarks= columns.getString("REMARKS");//备注
                    ColumnClass columnClass = new ColumnClass();
                    columnClass.setRemark(remarks);
                    columnClass.setColumnName(column_name);
                    columnClass.setType(type_name);
                    columnClass.setPropertyName(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL,column_name));//属性的名字。驼峰
                    primaryKeys.first();//挪到第一位
                    while (primaryKeys.next()){
                    String pkName= primaryKeys.getString("COLUMN_NAME");//主键的名字
                        if(column_name.equals(pkName)){//如果相等说明是主键
                            columnClass.setIsPrimary(true);
                        }

                    }
                    columnClassList.add(columnClass);
                }
                tableClass.setColumns(columnClassList);
                String path=realPath+"/"+tableClass.getPackageName().replace(".","/");//设置路径
                generate(modelTemplate,tableClass,path+"/model/");
                generate(mapperJavaTemplate,tableClass,path+"/mapper/");
                generate(mapperXmlTemplate,tableClass,path+"/mapper/");
                generate(serviceTemplate,tableClass,path+"/service/");
                generate(controllerTemplate,tableClass,path+"/controller/");


            }
            return  RespBean.ok("代码已生成",realPath);
        }catch (Exception e){
            e.printStackTrace();

        }
        return RespBean.error("代码生成失败");
    }

    private void generate(Template template, TableClass tableClass, String path) throws IOException, TemplateException {
        File floder = new File(path);
        if(!floder.exists()){
            floder.mkdirs();//不存在创建该路径

        }
        String fileName=path+"/"+tableClass.getModelName() + template.getName().replace(".ftl","").replace("Model","");
        FileOutputStream fos = new FileOutputStream(fileName);
        OutputStreamWriter out=new OutputStreamWriter(fos);
        template.process(tableClass,out);
        fos.close();
    }
}

链接数据库工具类

/**连接数据库工具类
 * @author 
 * @date 
 **/
public class DbUtils {
    private static  Connection connection;

    public static Connection getConnection() {
        return connection;
    }
    public static Connection initDb(Db db){
        if(connection ==null){
            try {
                Class.forName("com.mysql.jdbc.Driver");
                connection =  DriverManager.getConnection(db.getUrl(),db.getUsername(),db.getPassword());
            } catch (ClassNotFoundException | SQLException e) {
                e.printStackTrace();
            }
        }
    return  connection;
    }
}

创建生成的ftl模板

Model.java.ftl

package ${packageName}.model;

import java.util.Date;
public class ${modelName}{
<#if columns??>
    <#list  columns as column>
        <#if column.type='VARCHAR'|| column.type='TEXT'||column.type='CHAR'>
            /**
            *${column.remark}
            */
            private String ${column.propertyName?uncap_first};
        </#if>
        <#if column.type='INT'>
            /**
            *${column.remark}
            */
            private Integer ${column.propertyName?uncap_first};
        </#if>
        <#if column.type='DATETIME'>
            /**
            *${column.remark}
            */
            private Date ${column.propertyName?uncap_first};
        </#if>
        <#if column.type='BIGINT'>
            /**
            *${column.remark}
            */
            private Long ${column.propertyName?uncap_first};
        </#if>
        <#if column.type='DOUBLE'>
            /**
            *${column.remark}
            */
            private Double ${column.propertyName?uncap_first};
        </#if>
        <#if column.type='BIT'>
            /**
            *${column.remark}
            */
            private Boolean ${column.propertyName?uncap_first};
        </#if>
    </#list>
</#if>
<#if columns??>
    <#list  columns as column>
        <#if column.type='VARCHAR'|| column.type='TEXT'||column.type='CHAR'>
            public String get${column.propertyName}(){
            return ${column.propertyName?uncap_first};
            }
            public void set${column.propertyName}(String ${column.propertyName?uncap_first}){
            this.${column.propertyName?uncap_first}=${column.propertyName?uncap_first};
            }
        </#if>
        <#if column.type='INT'>
            public Integer get${column.propertyName}(){
            return ${column.propertyName?uncap_first};
            }
            public void set${column.propertyName}(Integer ${column.propertyName?uncap_first}){
            this.${column.propertyName?uncap_first}=${column.propertyName?uncap_first};
            }
        </#if>
        <#if column.type='DATETIME'>
            public Date get${column.propertyName}(){
            return ${column.propertyName?uncap_first};
            }
            public void set${column.propertyName}(Date ${column.propertyName?uncap_first}){
            this.${column.propertyName?uncap_first}=${column.propertyName?uncap_first};
            }
        </#if>

        <#if column.type='BIGINT'>
            public Long get${column.propertyName}(){
            return ${column.propertyName?uncap_first};
            }
            public void set${column.propertyName}(Long ${column.propertyName?uncap_first}){
            this.${column.propertyName?uncap_first}=${column.propertyName?uncap_first};
            }
        </#if>
        <#if column.type='DOUBLE'>
            public Double get${column.propertyName}(){
            return ${column.propertyName?uncap_first};
            }
            public void set${column.propertyName}(Double ${column.propertyName?uncap_first}){
            this.${column.propertyName?uncap_first}=${column.propertyName?uncap_first};
            }
        </#if>
        <#if column.type='BIT'>
            public Boolean get${column.propertyName}(){
            return ${column.propertyName?uncap_first};
            }
            public void set${column.propertyName}(Boolean ${column.propertyName?uncap_first}){
            this.${column.propertyName?uncap_first}=${column.propertyName?uncap_first};
            }
        </#if>
    </#list>
</#if>

}

 mapper.xml.ftl

<#if这一长串是为了枚举一些sql类型,比如text转换成varchar类型等等,

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${packageName}.mapper.${mapperName}">
    <resultMap id="BaseResultMap" type="${packageName}.model.${modelName}">
        <#list columns as column>
            <<#if column.primary??>id<#else>result</#if> column="${column.columnName}" property="${column.propertyName?uncap_first}" jdbcType="<#if column.type='INT'>INTEGER<#elseif column.type='DATETIME'>TIMESTAMP<#elseif column.type='TEXT'>VARCHAR<#else>${column.type}</#if>"/>
        </#list>
    </resultMap>
    <select id="getAll${modelName}s" resultMap="BaseResultMap">
        select * from ${tableName};
    </select>
</mapper>

Mapper.java.ftl

package ${packageName}.mapper;

import ${packageName}.model.${modelName};
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface ${mapperName}{
    List<${modelName}>getAll${modelName}s();
}

Service.java.ftl

package ${packageName}.Service;

import ${packageName}.model.${modelName};
import ${packageName}.mapper.${mapperName};
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
@Service
public class ${serviceName}{
    @Autowired
    ${mapperName} ${mapperName?uncap_first};
    public   List<${modelName}>getAll${modelName}s(){
        return  ${mapperName?uncap_first}.getAll${modelName}s();
}
}

Controller.java.ftl

package ${packageName}.controller;

import ${packageName}.model.${modelName};
import ${packageName}.service.${serviceName};
import org.springframework.web.bind.annotation.RestController;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
@RestController
public class ${controllerName}{
    @Autowired
    ${serviceName} ${serviceName?uncap_first};
@GetMapping("/${modelName?lower_case}s")
public List<${modelName}>getAll${modelName}s(){
return ${serviceName?uncap_first}.getAll${modelName}s();
}
}

生成路径为:服务器上地址,点击对应地址即可查找到相应的生成代码。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值