Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0824 #22

Open
LeungKaMing opened this issue Aug 24, 2017 · 0 comments
Open

0824 #22

LeungKaMing opened this issue Aug 24, 2017 · 0 comments

Comments

@LeungKaMing
Copy link
Owner

LeungKaMing commented Aug 24, 2017

通常初始化数据库要建立很多表,特别在项目开发的时候表的格式可能会频繁些变动,【这时候就必须把sql文件跟逻辑代码解耦出来】,保留项目的sql脚本文件,然后每次需要重新建表,则执行建表初始化程序(db.js)就行。

目录规划

├── index.js # 程序入口文件
├── sql # sql脚本文件目录
│ ├── data.sql
│ └── user.sql
└── util # 工具代码
├── db.js # 封装的mysql模块方法
├── get-sql-content-map.js # 获取sql脚本文件内容
├── get-sql-map.js # 获取所有sql脚本文件
└── walk-file.js # 遍历sql脚本文件

关于操作SQL的步骤

  1. 遍历sql目录下的sql文件
  2. 解析所有sql文件的内容
  3. 执行sql文件

执行sql文件模块---db.js

const Koa = require('koa')
const cors = require('koa-cors') 
const app = new Koa()

const mysql = require('mysql')
const pool = mysql.createPool({
  host: '127.0.0.1',
  user: 'root',
  password: '********',
  database: 'sys'
})

// 在数据库中进行会话池操作
let query = (sql, values) => {
  return new Promise((resolve, reject) => {
    pool.getConnection((err, connection) => {
      if (err) {
        reject(err)
      } else {
        connection.query(sql, values, (err, rows) => {
          // connected! 
          if (err) {
            reject(err)
          } else {
            resolve(rows)
          }
          connection.release() // ok
        })
      }
      
    })
  })
}

module.exports = { query }

解析所有sql文件的内容---get-sql-content-map.js

const fs = require('fs')
const getSqlMap = require('./get-sql-map')

let sqlContentMap = {}

/**
 * 读取sql文件内容
 * @param  {string} fileName 文件名称
 * @param  {string} path     文件所在的路径
 * @return {string}          脚本文件内容
 */
function getSqlContent( fileName,  path ) {
  // 以二进制形式来读取sql文件
  let content = fs.readFileSync( path, 'binary' )
  // 创建一个以文件名称为键名,值为sql文件内容的对象
  sqlContentMap[ fileName ] = content
}

/**
 * 封装所有sql文件脚本内容
 * @return {object} 
 */
function getSqlContentMap () {
  let sqlMap = getSqlMap()
  for( let key in sqlMap ) {
    // sqlMap[key]是当前sql所在路径,key是当前sql的名称
    getSqlContent( key, sqlMap[key] )
  }

  return sqlContentMap
}

module.exports = getSqlContentMap

遍历sql目录下的sql文件---get-sql-map.js

const fs = require('fs')
const walkFile = require('./walk-file')

/**
 * 获取sql目录下的文件目录数据
 * @return {object} 
 */
function getSqlMap () {
  let basePath = __dirname
  basePath = basePath.replace(/\\/g, '\/')
  let pathArr = basePath.split('\/')
  pathArr = pathArr.splice( 0, pathArr.length - 1 )
  // 搞这么多就是为了获取相对于当前js文件的上一级目录下的sql目录位置。。。
  basePath = pathArr.join('/') + '/sql/'
  
  // 只匹配sql后缀的文件
  let fileList = walkFile( basePath, 'sql' )
  return fileList
}

module.exports = getSqlMap

纯属拆分作为一个遍历模块---walk-file.js

const fs = require('fs')

/**
 * 遍历目录下的文件目录
 * @param  {string} pathResolve  需进行遍历的目录路径
 * @param  {string} mime         遍历文件的后缀名
 * @return {object}              返回遍历后的目录结果
 */
const walkFile = function(  pathResolve , mime ){
  // 遍历目录下的内容
  let files = fs.readdirSync( pathResolve )
  let fileList = {}

   for( let [ i, item] of files.entries() ) {
    let itemArr = item.split('\.')
    
    // 筛选当前文件的后缀 与 传入的文件后缀名进行匹配
    let itemMime = ( itemArr.length > 1 ) ? itemArr[ itemArr.length - 1 ] : 'undefined'
    let keyName = item + ''
    if( mime === itemMime ) {
      fileList[ item ] =  pathResolve + item
    }
  }

  return fileList
}

module.exports = walkFile

入口文件

const fs = require('fs');
const getSqlContentMap = require('./util/get-sql-content-map');
const { query } = require('./util/db');


// 打印脚本执行日志
const eventLog = function( err , sqlFile, index ) {
  if( err ) {
    console.log(`[ERROR] sql脚本文件: ${sqlFile} 第${index + 1}条脚本 执行失败 o(╯□╰)o !`)
  } else {
    console.log(`[SUCCESS] sql脚本文件: ${sqlFile} 第${index + 1}条脚本 执行成功 O(∩_∩)O !`)
  }
}

// 获取所有sql脚本内容
let sqlContentMap = getSqlContentMap()
console.log(sqlContentMap)

// 执行建表sql脚本
const createAllTables = async () => {
  for( let key in sqlContentMap ) {
    let sqlShell = sqlContentMap[key]
    let sqlShellList = sqlShell.split(';')

    for ( let [ i, shell ] of sqlShellList.entries() ) {
      if ( shell.trim() ) {
        let result = await query( shell )
        if ( result.serverStatus * 1 === 2 ) {
          eventLog( null,  key, i)
        } else {
          eventLog( true,  key, i) 
        }
      }
    }
  }
  console.log('sql脚本执行结束!')
  console.log('请按 ctrl + c 键退出!')

}

createAllTables()

总结

现在用到中间件有:

  • koa-router => 简便处理ctx.request.url的过程
  • koa-bodyparser => 简便处理请求类型为POST的参数
  • koa-static => 简便处理模块之间引用静态资源路径的问题
  • koa-views => 模板引擎

现在掌握了的API有:

  1. ctx.url 获取当前url
  2. ctx.request 获取请求对象
  • ctx.request.query / ctx.query 获取请求参数(格式化)
  • ctx.request.queryString / ctx.queryString 获取请求参数(字符串)
  1. ctx.req 调用原生node请求属性/方法
  • ctx.req.addListener('data', (data) => {})
  • ctx.req.addListener('end', () => {}) // 上述两者都用于处理POST请求参数
  1. ctx.response 获取响应对象
  2. ctx.res 调用原生node响应属性/方法
  • ctx.res.writeHead(statusCode, reason) 自定义响应头的状态码和原因
  • ctx.res.write(content, 'binary') 以二进制格式输出内容,第二个参数可变
  • ctx.res.end() 结束响应

现在掌握了的Node原生API有:

  1. fs
  • fs.existsSync(filepath/directorypath) 同步判断该路径下的文件或目录是否存在
  • fs.statSync(directorypath).isDirectory() 同步判断该路径指的是否为目录
  • fs.readFileSync 同步读文件 / fs.readFile 异步读文件
  • fs.mkdirSync 同步创建目录 / fs.mkdir 异步创建文件
  1. path
  • path.join(path1, path2) 将path1和path2拼接起来,返回完整路径
  • path.resolve(path1, path2) 同上
  • path.extname 用于截取请求url的后缀
  • path.dirname(path) 获取当前路径的父级目录
  1. util
  • util.inspect(object[, options]) 传入JS原始值或对象,返回字符串形式的传入参数
  1. cookie
    // koa的ctx自带读取 和 写入 cookie的方法
  • ctx.cookies.get(name, [options]) 读取cookie
  • ctx.cookies.set(name, value, [options]) 写入cookie
ctx.cookies.set('name', 'ljm', {
    domain: 'localhost',  // 写cookie所在的域名
    path: '/index',       // 写cookie所在的路径
    maxAge: 10 * 60 * 1000, // cookie有效时长
    expires: new Date('2017-02-15'),  // cookie失效时间
    httpOnly: false,  // 是否只用于http请求中获取
    overwrite: false  // 是否允许重写
  }
)
  1. session
    // 遗憾的是跟post请求一样,koa并没有提供读取 和 写入session 的方法。只能通过自己实现或者通过第三方中间件实现:
  • koa-session-minimal 适用于koa2 的session中间件,提供存储介质的读写接口 。
  • koa-mysql-session 为存储介质koa-session-minimal中间件提供MySQL数据库的session数据读写操作。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant