Java SpringBoot实现带界面的代码生成器详解
作者:一只y
这篇文章主要介绍了Java SpringBoot如何实现带界面的代码生成器,帮助大家更好的理解和使用Java SpringBoot编程语言,感兴趣的朋友可以了解下
1.项目gitthub地址链接: https://github.com/baisul/generateCode.git切换到master分支
2.环境
2.1 springboot+freemarker+mysql
2.2 要装node.js,vue文件运行依赖node.js
3.以下就只拿生成java实体类来作为例子
4.application.xml
server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=root
5.pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.yl</groupId> <artifactId>generate_code</artifactId> <version>0.0.1-SNAPSHOT</version> <name>generate_code</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1-jre</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
6.Utils
package com.yl.generate_code.utils; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; public class CORFSConfiguration extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry registry) { //所有请求都允许跨域 registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*") .allowedHeaders("*"); } }
package com.yl.generate_code.utils; import com.yl.generate_code.model.Db; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class DBUtils { private static Connection connection; public static Connection getConnection() { return connection; } public static Connection init(Db db) { if (connection == null) { try { Class.forName("com.mysql.cj.jdbc.Driver"); connection = DriverManager.getConnection( db.getUrl(),db.getUsername(), db.getPassword()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } return connection; } }
7.生成模板
package ${packetName}.model; import java.util.Date; /** * @Description: ${modelName}实体类 * @Author: wfj * @CreateDate ${createDate} * @Version: 1.0V */ 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> <#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> }
8.Controller
package com.yl.generate_code.controller; import com.google.common.base.CaseFormat; import com.yl.generate_code.model.Db; import com.yl.generate_code.model.ResultModel; import com.yl.generate_code.model.TableClass; import com.yl.generate_code.utils.DBUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; @RestController public class DBController { @PostMapping("/connect") public ResultModel connect(@RequestBody Db db) { Connection connection = DBUtils.init(db); if (connection == null) { return ResultModel.fail("数据库连接失败"); } else { return ResultModel.success("数据库连接成功"); } } @PostMapping("/config") public ResultModel config(@RequestBody Map<String,Object> map) { String packetName = (String)map.get("packetName"); try { //获取数据库连接 Connection connection = DBUtils.getConnection(); //获取数据库元数据 DatabaseMetaData metaData = connection.getMetaData(); //获取数据库所有的表 ResultSet rs = metaData.getTables(connection.getCatalog(), null, null, null); List<TableClass> list = new ArrayList<>(); while (rs.next()) { TableClass tableClass = new TableClass(); tableClass.setPacketName(packetName); //获取表名 String tableName = rs.getString("TABLE_NAME"); //数据库表下划线的字段转成驼峰,且首字母大写 String modelName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, tableName); tableClass.setTableName(tableName); tableClass.setModelName(modelName); tableClass.setServiceName(modelName + "Service"); tableClass.setMapperName(modelName + "Mapper"); tableClass.setControllerName(modelName + "Controller"); list.add(tableClass); } return ResultModel.success("数据库信息读取成功",list); } catch (SQLException e) { e.printStackTrace(); return ResultModel.fail("数据库信息读取失败"); } } }
package com.yl.generate_code.controller; import com.yl.generate_code.model.ResultModel; import com.yl.generate_code.model.TableClass; import com.yl.generate_code.service.GenerateCodeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.List; @RestController public class GenerateCodeController { @Autowired private GenerateCodeService generateCodeService; @PostMapping("/generateCode") public ResultModel generateCode(@RequestBody List<TableClass> list, HttpServletRequest request) { return generateCodeService.generateCode(list,request.getServletContext().getRealPath("/")); } }
9.Model
package com.yl.generate_code.model; import java.io.Serializable; public class ColumnClass implements Serializable { //实体类属性名 private String propertyName; //实体类属性名对应的表的字段名 private String columnName; //字段类型 private String type; //备注 private String remark; //该字段是否为主键 private Boolean isPrimary; public String getPropertyName() { return propertyName; } public void setPropertyName(String propertyName) { this.propertyName = propertyName; } public String getColumnName() { return columnName; } public void setColumnName(String columnName) { this.columnName = columnName; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public Boolean getPrimary() { return isPrimary; } public void setPrimary(Boolean primary) { isPrimary = primary; } @Override public String toString() { return "ColumnClass{" + "propertyName='" + propertyName + '\'' + ", columnName='" + columnName + '\'' + ", type='" + type + '\'' + ", remark='" + remark + '\'' + ", isPrimary=" + isPrimary + '}'; } }
package com.yl.generate_code.model; import java.io.Serializable; public class Db implements Serializable { private String username; private String password; private String url; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
package com.yl.generate_code.model; import java.io.Serializable; public class ResultModel implements Serializable { private Integer code; private String msg; private Object obj; public static ResultModel success(String msg,Object obj) { return new ResultModel(200,msg,obj); } public static ResultModel success(String msg) { return new ResultModel(200,msg,null); } public static ResultModel fail(String msg,Object obj) { return new ResultModel(500,msg,obj); } public static ResultModel fail(String msg) { return new ResultModel(500,msg,null); } private ResultModel() { } public ResultModel(Integer code, String msg, Object obj) { this.code = code; this.msg = msg; this.obj = obj; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } }
package com.yl.generate_code.model; import java.io.Serializable; import java.util.ArrayList; import java.util.Date; import java.util.List; public class TableClass implements Serializable { private String tableName; private String modelName; private String serviceName; private String mapperName; private String controllerName; private String packetName; private String createDate; private List<ColumnClass> columns = new ArrayList<>(); public String getTableName() { return tableName; } public void setTableName(String tableName) { this.tableName = tableName; } public String getModelName() { return modelName; } public void setModelName(String modelName) { this.modelName = modelName; } public String getServiceName() { return serviceName; } public void setServiceName(String serviceName) { this.serviceName = serviceName; } public String getMapperName() { return mapperName; } public void setMapperName(String mapperName) { this.mapperName = mapperName; } public String getControllerName() { return controllerName; } public void setControllerName(String controllerName) { this.controllerName = controllerName; } public String getPacketName() { return packetName; } public void setPacketName(String packetName) { this.packetName = packetName; } public List<ColumnClass> getColumns() { return columns; } public void setColumns(List<ColumnClass> columns) { this.columns = columns; } public String getCreateDate() { return createDate; } public void setCreateDate(String createDate) { this.createDate = createDate; } }
10.index.html(数据库连接生成代码的界面)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!--引入vue.js,elementui和axios--> <script src="https://cdn.jsdelivr.net/npm/vue@2/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://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <div id="app"> <table> <tr> <td><el-tag size="mini">数据库用户名:</el-tag></td> <td><el-input size="mini" v-model="db.username"></el-input></td> </tr> <tr> <td><el-tag size="mini">数据库密码:</el-tag></td> <td><el-input size="mini" v-model="db.password"></el-input></td> </tr> <tr> <td><el-tag size="mini">数据库连接地址:</el-tag></td> <td><el-input size="mini" v-model="db.url"> <template slot="prepend">jdbc:mysql://</template> <template slot="append">?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai</template> </el-input></td> </tr> </table> <div style="display: flex"> <el-button type="primary" size="mini" @click="connect" :disabled="!enableButton">连接数据库</el-button> <div style="color: red;font-weight: bold" >{{msg}}</div> <el-input v-model="packetName" size="mini" style="width:300px"></el-input> <el-button size="mini" type="primary" @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 type="success" size="mini" @click="generateCode">生成代码</el-button> <div style="color: green;font-weight: bold">{{result}}</div> <div>{{codePath}}</div> </div> </div> <script> new Vue({ el:"#app", data() { return{ result: '', codePath: '', tableData:[], packetName: 'com.yl', msg : "数据库未连接", enableButton: true, db: { username: "root", password: "root", url : "localhost:3306/demo" } } }, methods: { connect() { let _this = this this.db.url = "jdbc:mysql://" + this.db.url + "?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai" axios.post("/connect",this.db).then(res => { console.log(res.data) _this.db = { username: "root", password: "root", url : "localhost:3306/demo" } _this.msg = res.data.msg _this.enableButton = false }).catch(err => { console.log(err) }) }, config() { let _this = this axios.post("/config",{packetName: _this.packetName}).then(res => { console.log(res.data) _this.msg = res.data.msg _this.tableData = res.data.obj }).catch(err => { console.log(err) }) }, generateCode() { let _this = this axios.post("/generateCode",_this.tableData).then(res => { console.log(res.data) _this.result = res.data.msg _this.codePath = res.data.obj }).catch(err => { console.log(err) }) } } }) </script> </body> </html>
11.接口
package com.yl.generate_code.service; import com.yl.generate_code.model.ResultModel; import com.yl.generate_code.model.TableClass; import javax.servlet.http.HttpServletRequest; import java.util.List; public interface GenerateCodeService { ResultModel generateCode(List<TableClass> list, String realpath); }
package com.yl.generate_code.service.impl; import com.google.common.base.CaseFormat; import com.yl.generate_code.model.ColumnClass; import com.yl.generate_code.model.ResultModel; import com.yl.generate_code.model.TableClass; import com.yl.generate_code.service.GenerateCodeService; import com.yl.generate_code.utils.DBUtils; import freemarker.cache.ClassTemplateLoader; import freemarker.template.Configuration; import freemarker.template.Template; import freemarker.template.TemplateException; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.io.*; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; @Service public class GenerateCodeServiceImpl implements GenerateCodeService { Configuration cfg = null; { cfg = new Configuration(Configuration.VERSION_2_3_31); cfg.setTemplateLoader(new ClassTemplateLoader(GenerateCodeServiceImpl.class,"/templates")); cfg.setDefaultEncoding("utf-8"); } @Override public ResultModel generateCode(List<TableClass> list, String realpath) { try { Template modelTemplate = cfg.getTemplate("Model.java.ftl"); Template serviceTemplate = cfg.getTemplate("Service.java.ftl"); Template serviceImplTemplate = cfg.getTemplate("ServiceImpl.java.ftl"); Template mapperTemplate = cfg.getTemplate("Mapper.java.ftl"); Template mapperXmlTemplate = cfg.getTemplate("Mapper.xml.java.ftl"); Template controllerTemplate = cfg.getTemplate("Controller.java.ftl"); Connection connection = DBUtils.getConnection(); DatabaseMetaData metaData = connection.getMetaData(); for (TableClass tableClass : list) { //根据表名获取该表的所有字段 ResultSet columns = metaData.getColumns(connection.getCatalog(), null, tableClass.getTableName(), null); //获取该表的所有主键 ResultSet primaryKeys = metaData.getPrimaryKeys(connection.getCatalog(), null, tableClass.getTableName()); List<ColumnClass> columnClasses = new ArrayList<>(); while (columns.next()) { //获取字段名 String column_name = columns.getString("COLUMN_NAME"); //获取字段类型 String type_name = columns.getString("TYPE_NAME"); //获取字段注释 String remark = columns.getString("REMARKS"); ColumnClass columnClass = new ColumnClass(); columnClass.setColumnName(column_name); columnClass.setType(type_name); columnClass.setRemark(remark); columnClass.setPropertyName(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL,column_name)); //指标挪到第一 primaryKeys.first(); while (primaryKeys.next()) { String primaryKey = primaryKeys.getString("COLUMN_NAME"); if (column_name.equals(primaryKey)) { columnClass.setPrimary(true); } } columnClasses.add(columnClass); } tableClass.setColumns(columnClasses); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); tableClass.setCreateDate(sdf.format(new Date())); String path = realpath + "/" + tableClass.getPacketName().replace(".","/"); generate(modelTemplate,tableClass,path+"/model/",1); generate(serviceTemplate,tableClass,path+"/service/",1); generate(serviceImplTemplate,tableClass,path+"/service/impl",1); generate(mapperTemplate,tableClass,path+"/mapper/",1); generate(mapperXmlTemplate,tableClass,path+"/mapper/",2); generate(controllerTemplate,tableClass,path+"/controller/",1); } return ResultModel.success("代码已生成",realpath); } catch (Exception e) { e.printStackTrace(); return ResultModel.fail("代码生成失败"); } } private void generate(Template template,TableClass tableClass,String path,Integer flag) throws IOException, TemplateException { File file = new File(path); if (!file.exists()) { file.mkdirs(); } String fileName; if (flag == 1) { fileName = path + "/" + tableClass.getModelName() + template.getName().replace(".ftl","").replace("Model",""); } else { fileName = path + "/" + tableClass.getModelName() + template.getName().replace(".ftl","").replace(".java",""); } FileOutputStream fos = new FileOutputStream(fileName); OutputStreamWriter out = new OutputStreamWriter(fos); template.process(tableClass,out); fos.close(); out.close(); } }
12.图形化界面
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!