Thought analysis
We can think of a code generator as gathering some information and rendering it into a fixed code template to generate the final code
Prepare knowledge
From the above analysis, we know that to write a code generator we need to know the following things:
- You can get user input
- You can obtain database information
- Memory information can be written to a local file
Almost all popular programming languages can do this. We chose to use nodeJs Express here
ejs
mysql
Key step code
-
Install the Express application generator
#If the installation is slow please use CNPM https://www.oschina.net/p/cnpm?hmsr=aladdin1e1 npm install -g express-generator #Later versions of Node (included in Node.js 8.2.0 and later) can be installed using the following command npx express-generator Copy the code
-
Generate the Express basic framework
#Generate project folder mkdir gen cd gen #Generating the Express Framework express -e --git Copy the code
-
Installing dependency packages
Lodash is a common JavaScript toolkit npm install --save lodash mysql Copy the code
-
Create a basic information collection form
Open the Express project folder generated by the previous command and open the app.js file in the root directory of the project
// Around 12-14 of the code // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine'.'ejs'); Copy the code
Ejs template directory is the views folder in the project root directory. Add a form to index.ejs as follows
<! DOCTYPEhtml> <html> <head> <title>Quick clustering code generator</title> <link rel='stylesheet' href='/ lib/bootstrap 4.6.0 / CSS/bootstrap. Min. CSS'/> <link rel='stylesheet' href='/stylesheets/style.css'/> </head> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" href="#">Quick clustering code generator</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item active"> <a class="nav-link" href="#">The generated code<span class="sr-only">(current)</span></a> </li> </ul> </div> </nav> <div class="row" style="margin:30px auto; width:600px "> <form action="/tables" method="post"> <div class="form-group"> <label for="exampleInputEmail1">The project name</label> <input type="name" class="form-control"> </div> <div class="form-group"> <label for="exampleInputPassword1">The author</label> <input class="form-control" name="author"> </div> <div class="form-group"> <label for="exampleInputPassword1">Table prefix Removal</label> <input class="form-control" name="pre"> </div> <div class="form-group"> <label for="exampleInputPassword1">Generate the file</label> <br/> <span>The backend:</span> <label><input type="checkbox" name="files[]" value="mappper">mappper</label> <label><input type="checkbox" name="files[]" value="mappperXML">mappperXML</label> <label><input type="checkbox" name="files[]" value="entity">entity</label> <label><input type="checkbox" name="files[]" value="param">param</label> <label><input type="checkbox" name="files[]" value="result">result</label> <label><input type="checkbox" name="files[]" value="controller">controller</label> <label><input type="checkbox" name="files[]" value="service">service</label> <label><input type="checkbox" name="files[]" value="serviceimpl">serviceimpl</label> <label><input type="checkbox" name="files[]" value="enum">enum</label> <br/> <span>Front end:</span> <label><input type="checkbox" name="files[]" value="indexJsx">indexJsx</label> <label><input type="checkbox" name="files[]" value="addJsx">addJsx</label> <label><input type="checkbox" name="files[]" value="editJsx">editJsx</label> <label><input type="checkbox" name="files[]" value="apiJs">apiJs</label> </div> <div class="form-group"> <label for="exampleInputPassword1">Whether to generate API documentation</label> <br/> <label><input type="radio" name="api">is</label> <label><input type="radio" name="api">no</label> </div> <button type="submit" class="btn btn-primary">The next step</button> </form> </div> </body> </html> Copy the code
-
Create a route for receiving form information
The Express route file is written in the routes folder under the root of the project. We added a new route to routes/index.js to receive form information
Express Basic Routing
router.post('/tables'.function (req, res) { // req requests objects for data }); Copy the code
-
Create a database connection pool
After we get the information submitted by the user we also need to get the information in the database.
#Create a configuration folder under the project root directory to store configuration files mkdir config Copy the code
Create a db.js file in the config folder to configure database information and create a database connection pool
var mysql = require('mysql') var pool = mysql.createPool({ connectionLimit: 10.host: '127.0.0.1'.user: 'root'.password: ' '.database: 'database' }); function query(sql, values, callback) { console.log("db pool"); pool.getConnection(function (err, connection) { if(err) throw err; console.log("sql ",sql,values); //Use the connection connection.query(sql, values,function (err, results, fields) { console.log(JSON.stringify(results),err); // Every query is called back callback(err, results); // Just release the link in the buffer pool, not destroyed connection.release(); if(err) throw error; }); }); } exports.query = query; Copy the code
-
Gets information about all tables in the specified library
With the database connection pool created above to read information from the database, we return to the routes/index.js file
// Import the database const db = require(".. /config/db").../** * get all data from the database */ router.post('/tables'.function (req, res) { /** * 1. Get the information submitted in the previous step from req.body. Query the database to get the current connected database table information */ db.query("show tables"[],function (err, rows) { res.render('index', { postData: {... req.body}, tables }); }); });Copy the code
-
Gets information about all fields in the specified table
In the same way, we can create a new route to get all the fields in the specified table
/** * returns table structure information by table name */ router.get('/table_info'.function (req, res) { db.query('show full fields from' + req.query.name, [], function (err, rows) { res.send(rows); }); }); Copy the code
-
Summary database information and form information rendered to the template
router.post('/gen'.function (req, res) { // let dir = tempRootPath + new Date().getTime() + "/" let dir = tempRootPath const {tableColumn, postData} = req.body // Loop through all tables _.each(tableColumn, function (item, key) { // The name of the PASCAL table let pskTableName = _.capitalize(key) let frontPath = dir + key + "/front/" + pskTableName + "/" // Generate the front end of the component according to the table name in PASCAL mode mkdirsSync(frontPath) // Use a direct structure to avoid bugs const {author, pre} = postData /* * Configure the template according to the file structure to generate the corresponding data */ let allColumns = tableColumn[key] ? tableColumn[key] : [] // Generate code generate(frontTemplateFiles, frontPath, { updateColumns: _.filter(allColumns, item= > item.showUpdate), updateMustColumns: _.filter(allColumns, item= > item.mustUpdate), addColumns: _.filter(allColumns, item= > item.showAdd), addMustColumns: _.filter(allColumns, item= > item.mustAdd), listColumns: _.filter(allColumns, item= > item.showList), searchColumns: _.filter(allColumns, item= > item.isSearch), allColumns, author, pre, pskTableName }) }) res.send("ok")})Copy the code
The code address
Making the address