国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

koa2+vue+mysql 全棧開發記錄

Rango / 3545人閱讀

摘要:全棧開發記錄基于想要自己制作一個個人項目為由,于是有了這么一個開發記錄梳理開發過程也是一個知識鞏固的過程個人的一個通用本篇文章的范例地址前端工具頁面組件百度強大的圖表展示花褲衩大佬的一個實用管理后臺模版配套教程國際化后端工具解析請

koa2+vue2+mysql 全棧開發記錄
基于想要自己制作一個個人項目為由,于是有了這么一個開發記錄(梳理開發過程也是一個知識鞏固的過程)
koa2+vue2+mysql 個人的一個通用DEMO(本篇文章的范例)

koa2+vue2+mysql GITHUB地址

前端工具

vue

vue-router

vuex

axios

element ui 頁面UI組件

echartsjs 百度強大的圖表展示

vue-admin-template 花褲衩大佬的一個實用管理后臺模版 配套教程

vue-i18n 國際化

scss

后端工具

koa

koa-bodyparser 解析 PUT / POST 請求中的 body

koa-convert

koa-json

koa-jwt jwt鑒權

koa-logger

koa-mysql-session

koa-onerror

koa-router

koa-session-minimal

koa-static

koa-views

koa2-cors 處理跨域

md5 加密

moment 時間處理

mysql

前端篇
前端這邊其實沒什么好寫的,主要是在vue-admin-template基礎上做了一些修改
src/utils/request.js的修改

request攔截器

  // request攔截器
  service.interceptors.request.use(
    config => {
      if (store.getters.token) {
        // config.headers["X-Token"] = getToken()
        // 因為是jwt方式鑒權 所以在header頭中改為如下寫法
        config.headers["Authorization"] = "Bearer " + getToken() // 讓每個請求攜帶自定義token 請根據實際情況自行修改
      }
      return config
    },
    error => {
      // Do something with request error
      console.log(error) // for debug
      Promise.reject(error)
    }
  )

response 攔截器

  // response 攔截器
  service.interceptors.response.use(
    response => {
      /**
      * code為非0是拋錯 可結合自己業務進行修改
      */
      const res = response.data
      if (res.code !== 0) { // 因為后臺返回值為0則是成功,所以將原來的20000改為了0
        Message({
          message: res.message,
          type: "error",
          duration: 5 * 1000
        })

        // 70002:非法的token; 50012:其他客戶端登錄了;  50014:Token 過期了;
        if (res.code === 70002 || res.code === 50012 || res.code === 50014) {
          MessageBox.confirm(
            "你已被登出,可以取消繼續留在該頁面,或者重新登錄",
            "確定登出",
            {
              confirmButtonText: "重新登錄",
              cancelButtonText: "取消",
              type: "warning"
            }
          ).then(() => {
            store.dispatch("FedLogOut").then(() => {
              location.reload() // 為了重新實例化vue-router對象 避免bug
            })
          })
        }
        return Promise.reject("error")
      } else {
        return response.data
      }
    },
    error => {
      console.log("err" + error) // for debug
      Message({
        message: error.message,
        type: "error",
        duration: 5 * 1000
      })
      return Promise.reject(error)
    }
  )
封裝了一個Echart組件

具體參考我的另外一個文章 vue中使用echarts 使用記錄

后端篇 構建項目目錄

通過項目生成器生成koa-generator

npm install -g koa-generator

koa2 /server && cd /server

npm install

安裝組件

npm i jsonwebtoken koa-jwt koa-mysql-session koa-session-minimal koa2-cors md5 moment mysql save --save

配置app.js

  const Koa = require("koa")
  const jwt = require("koa-jwt")
  const app = new Koa()
  const views = require("koa-views")
  const json = require("koa-json")
  const onerror = require("koa-onerror")
  const bodyparser = require("koa-bodyparser")
  const logger = require("koa-logger")
  const convert = require("koa-convert");

  var session = require("koa-session-minimal")
  var MysqlStore = require("koa-mysql-session")
  var config = require("./config/default.js")
  var cors = require("koa2-cors")

  const users = require("./routes/users")
  const account = require("./routes/account")

  // error handler
  onerror(app)

  // 配置jwt錯誤返回
  app.use(function(ctx, next) {
    return next().catch(err => {
      if (401 == err.status) {
        ctx.status = 401
        ctx.body = ApiErrorNames.getErrorInfo(ApiErrorNames.INVALID_TOKEN)
        // ctx.body = {
        //   // error: err.originalError ? err.originalError.message : err.message
        // }
      } else {
        throw err
      }
    })
  })

  // Unprotected middleware
  app.use(function(ctx, next) {
    if (ctx.url.match(/^/public/)) {
      ctx.body = "unprotected
"
    } else {
      return next()
    }
  })

  // Middleware below this line is only reached if JWT token is valid

  app.use(
    jwt({ secret: config.secret, passthrough: true }).unless({
      path: [//register/, //user/login/]
    })
  )

  // middlewares
  app.use(convert(bodyparser({
    enableTypes:["json", "form", "text"]
  })))
  app.use(convert(json()))
  app.use(convert(logger()))
  app.use(require("koa-static")(__dirname + "/public"))

  app.use(views(__dirname + "/views", {
    extension: "pug"
  }))

  // logger
  app.use(async (ctx, next) => {
    const start = new Date()
    await next()
    const ms = new Date() - start
    console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
  })

  // cors
  app.use(cors())

  // routes
  app.use(users.routes(), users.allowedMethods())
  app.use(account.routes(), account.allowedMethods())

  // error-handling
  app.on("error", (err, ctx) => {
    console.error("server error", err, ctx)
  });

  module.exports = app

新建config文件夾用于存放數據庫連接等操作

default.js
// 數據庫配置
  const config = {
    port: 3000,
    database: {
      DATABASE: "xxx", //數據庫
      USERNAME: "root", //用戶
      PASSWORD: "xxx", //密碼
      PORT: "3306", //端口
      HOST: "127.0.0.1" //服務ip地址
    },
    secret: "jwt_secret"
  }

  module.exports = config
數據庫相關(mysql)
createTables.js 一個簡單的用戶角色權限表 用戶、角色、權限表的關系(mysql)
// 數據庫表格創建
const createTable = {
  users: `CREATE TABLE IF NOT EXISTS user_info (
      id INT PRIMARY KEY NOT NULL AUTO_INCREMENT COMMENT "(自增長)",
      user_id VARCHAR ( 100 ) NOT NULL COMMENT "賬號",
      user_name VARCHAR ( 100 ) NOT NULL COMMENT "用戶名",
      user_pwd VARCHAR ( 100 ) NOT NULL COMMENT "密碼",
      user_head VARCHAR ( 225 ) COMMENT "頭像",
      user_mobile VARCHAR ( 20 ) COMMENT "手機",
      user_email VARCHAR ( 64 ) COMMENT "郵箱",
      user_creatdata TIMESTAMP NOT NULL DEFAULT NOW( ) COMMENT "注冊日期",
      user_login_time TIMESTAMP DEFAULT NOW( ) COMMENT "登錄時間",
      user_count INT COMMENT "登錄次數"
    ) ENGINE = INNODB charset = utf8;`,
    role: `CREATE TABLE IF NOT EXISTS role_info (
      id INT PRIMARY KEY NOT NULL AUTO_INCREMENT COMMENT "(自增長)",
      role_name VARCHAR ( 20 ) NOT NULL COMMENT "角色名",
      role_description VARCHAR ( 255 ) DEFAULT NULL COMMENT "描述"
    ) ENGINE = INNODB charset = utf8;`,
    permission: `CREATE TABLE IF NOT EXISTS permission_info (
      id INT PRIMARY KEY NOT NULL AUTO_INCREMENT COMMENT "(自增長)",
      permission_name VARCHAR ( 20 ) NOT NULL COMMENT "權限名",
      permission_description VARCHAR ( 255 ) DEFAULT NULL COMMENT "描述"
    ) ENGINE = INNODB charset = utf8;`,
    userRole: `CREATE TABLE IF NOT EXISTS user_role (
      id INT PRIMARY KEY NOT NULL AUTO_INCREMENT COMMENT "(自增長)",
      user_id INT NOT NULL COMMENT "關聯用戶",
      role_id INT NOT NULL COMMENT "關聯角色",
      KEY fk_user_role_role_info_1 ( role_id ),
      KEY fk_user_role_user_info_1 ( user_id ),
      CONSTRAINT fk_user_role_role_info_1 FOREIGN KEY ( role_id ) REFERENCES role_info ( id ) ON DELETE CASCADE ON UPDATE CASCADE,
      CONSTRAINT fk_user_role_user_info_1 FOREIGN KEY ( user_id ) REFERENCES user_info ( id ) ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE = INNODB charset = utf8;`,
    rolePermission: `CREATE TABLE IF NOT EXISTS role_permission (
      id INT PRIMARY KEY NOT NULL AUTO_INCREMENT COMMENT "(自增長)",
      role_id INT NOT NULL COMMENT "關聯角色",
      permission_id INT NOT NULL COMMENT "關聯權限",
      KEY fk_role_permission_role_info_1 ( role_id ),
      KEY fk_role_permission_permission_info_1 ( permission_id ),
      CONSTRAINT fk_role_permission_role_info_1 FOREIGN KEY ( role_id ) REFERENCES role_info ( id ) ON DELETE CASCADE ON UPDATE CASCADE,
      CONSTRAINT fk_role_permission_permission_info_1 FOREIGN KEY ( permission_id ) REFERENCES permission_info ( id ) ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE = INNODB charset = utf8;`
}

module.exports = createTable

創建lib文件夾 用于存儲數據庫查詢語句

mysql.js
const mysql = require("mysql")
const config = require("../config/default")
const createTables = require("../config/createTables.js")

var pool = mysql.createPool({
  host: config.database.HOST,
  user: config.database.USERNAME,
  password: config.database.PASSWORD,
  database: config.database.DATABASE
})

let query = function(sql, values) {
  return new Promise((resolve, reject) => {
    pool.getConnection(function(err, connection) {
      if (err) {
        resolve(err)
      } else {
        connection.query(sql, values, (err, rows) => {
          if (err) {
            reject(err)
          } else {
            resolve(rows)
          }
          connection.release()
        })
      }
    })
  })
}

let createTable = function(sql) {
  return query(sql, [])
}

// 建表
// createTable(createTables.users)
// createTable(createTables.role)
// createTable(createTables.permission)
// createTable(createTables.userRole)
// createTable(createTables.rolePermission)

// 查詢用戶是否存在
let findUser = async function(id) {
  let _sql = `
        SELECT * FROM user_info where user_id="${id}" limit 1;
    `
  let result = await query(_sql)

  if (Array.isArray(result) && result.length > 0) {
    result = result[0]
  } else {
    result = null
  }
  return result
}
// 查詢用戶以及用戶角色
let findUserAndRole = async function(id) {
  let _sql = `
      SELECT u.*,r.role_name FROM user_info u,user_role ur,role_info r where u.id=(SELECT id FROM user_info where user_id="${id}" limit 1) and ur.user_id=u.id and r.id=ur.user_id limit 1;
    `
  let result = await query(_sql)

  if (Array.isArray(result) && result.length > 0) {
    result = result[0]
  } else {
    result = null
  }
  return result
}

// 更新用戶登錄次數和登錄時間
let UpdataUserInfo = async function(value) {
  let _sql =
    "UPDATE user_info SET user_count = ?, user_login_time = ? WHERE id = ?;"
  return query(_sql, value)
}

module.exports = {
  //暴露方法
  createTable,
  findUser,
  findUserAndRole,
  UpdataUserInfo,
  getShopAndAccount
}
koa 路由配置

接口報錯信息統一方法 創建error文件夾

ApiErrorNames.js
/**
 * API錯誤名稱
 */
var ApiErrorNames = {};

ApiErrorNames.UNKNOW_ERROR = "UNKNOW_ERROR";
ApiErrorNames.SUCCESS = "SUCCESS";

/* 參數錯誤:10001-19999 */
ApiErrorNames.PARAM_IS_INVALID = "PARAM_IS_INVALID";
ApiErrorNames.PARAM_IS_BLANK = "PARAM_IS_BLANK";
ApiErrorNames.PARAM_TYPE_BIND_ERROR = "PARAM_TYPE_BIND_ERROR";
ApiErrorNames.PARAM_NOT_COMPLETE = "PARAM_NOT_COMPLETE";

/* 用戶錯誤:20001-29999*/
ApiErrorNames.USER_NOT_LOGGED_IN = "USER_NOT_LOGGED_IN";
ApiErrorNames.USER_LOGIN_ERROR = "USER_LOGIN_ERROR";
ApiErrorNames.USER_ACCOUNT_FORBIDDEN = "USER_ACCOUNT_FORBIDDEN";
ApiErrorNames.USER_NOT_EXIST = "USER_NOT_EXIST";
ApiErrorNames.USER_HAS_EXISTED = "USER_HAS_EXISTED";

/* 業務錯誤:30001-39999 */
ApiErrorNames.SPECIFIED_QUESTIONED_USER_NOT_EXIST = "SPECIFIED_QUESTIONED_USER_NOT_EXIST";

/* 系統錯誤:40001-49999 */
ApiErrorNames.SYSTEM_INNER_ERROR = "SYSTEM_INNER_ERROR";

/* 數據錯誤:50001-599999 */
ApiErrorNames.RESULE_DATA_NONE = "RESULE_DATA_NONE";
ApiErrorNames.DATA_IS_WRONG = "DATA_IS_WRONG";
ApiErrorNames.DATA_ALREADY_EXISTED = "DATA_ALREADY_EXISTED";

/* 接口錯誤:60001-69999 */
ApiErrorNames.INTERFACE_INNER_INVOKE_ERROR = "INTERFACE_INNER_INVOKE_ERROR";
ApiErrorNames.INTERFACE_OUTTER_INVOKE_ERROR = "INTERFACE_OUTTER_INVOKE_ERROR";
ApiErrorNames.INTERFACE_FORBID_VISIT = "INTERFACE_FORBID_VISIT";
ApiErrorNames.INTERFACE_ADDRESS_INVALID = "INTERFACE_ADDRESS_INVALID";
ApiErrorNames.INTERFACE_REQUEST_TIMEOUT = "INTERFACE_REQUEST_TIMEOUT";
ApiErrorNames.INTERFACE_EXCEED_LOAD = "INTERFACE_EXCEED_LOAD";

/* 權限錯誤:70001-79999 */
ApiErrorNames.PERMISSION_NO_ACCESS = "PERMISSION_NO_ACCESS";
ApiErrorNames.INVALID_TOKEN = "INVALID_TOKEN";

/**
 * API錯誤名稱對應的錯誤信息
 */
const error_map = new Map();

error_map.set(ApiErrorNames.SUCCESS, { code: 0, message: "成功" });
error_map.set(ApiErrorNames.UNKNOW_ERROR, { code: -1, message: "未知錯誤" });
/* 參數錯誤:10001-19999 */
error_map.set(ApiErrorNames.PARAM_IS_INVALID, { code: 10001, message: "參數無效" });
error_map.set(ApiErrorNames.PARAM_IS_BLANK, { code: 10002, message: "參數為空" });
error_map.set(ApiErrorNames.PARAM_TYPE_BIND_ERROR, { code: 10003, message: "參數類型錯誤" });
error_map.set(ApiErrorNames.PARAM_NOT_COMPLETE, { code: 10004, message: "參數缺失" });
/* 用戶錯誤:20001-29999*/
error_map.set(ApiErrorNames.USER_NOT_LOGGED_IN, { code: 20001, message: "用戶未登錄" });
error_map.set(ApiErrorNames.USER_LOGIN_ERROR, { code: 20002, message: "賬號不存在或密碼錯誤" });
error_map.set(ApiErrorNames.USER_ACCOUNT_FORBIDDEN, { code: 20003, message: "賬號已被禁用" });
error_map.set(ApiErrorNames.USER_NOT_EXIST, { code: 20004, message: "用戶不存在" });
error_map.set(ApiErrorNames.USER_HAS_EXISTED, { code: 20005, message: "用戶已存在" });
/* 業務錯誤:30001-39999 */
error_map.set(ApiErrorNames.SPECIFIED_QUESTIONED_USER_NOT_EXIST, { code: 30001, message: "某業務出現問題" });
/* 系統錯誤:40001-49999 */
error_map.set(ApiErrorNames.SYSTEM_INNER_ERROR, { code: 40001, message: "系統繁忙,請稍后重試" });
/* 數據錯誤:50001-599999 */
error_map.set(ApiErrorNames.RESULE_DATA_NONE, { code: 50001, message: "數據未找到" });
error_map.set(ApiErrorNames.DATA_IS_WRONG, { code: 50002, message: "數據有誤" });
error_map.set(ApiErrorNames.DATA_ALREADY_EXISTED, { code: 50003, message: "數據已存在" });
/* 接口錯誤:60001-69999 */
error_map.set(ApiErrorNames.INTERFACE_INNER_INVOKE_ERROR, { code: 60001, message: "內部系統接口調用異常" });
error_map.set(ApiErrorNames.INTERFACE_OUTTER_INVOKE_ERROR, { code: 60002, message: "外部系統接口調用異常" });
error_map.set(ApiErrorNames.INTERFACE_FORBID_VISIT, { code: 60003, message: "該接口禁止訪問" });
error_map.set(ApiErrorNames.INTERFACE_ADDRESS_INVALID, { code: 60004, message: "接口地址無效" });
error_map.set(ApiErrorNames.INTERFACE_REQUEST_TIMEOUT, { code: 60005, message: "接口請求超時" });
error_map.set(ApiErrorNames.INTERFACE_EXCEED_LOAD, { code: 60006, message: "接口負載過高" });
/* 權限錯誤:70001-79999 */
error_map.set(ApiErrorNames.PERMISSION_NO_ACCESS, { code: 70001, message: "無訪問權限" });
error_map.set(ApiErrorNames.INVALID_TOKEN, { code: 70002, message: "無效token" });

//根據錯誤名稱獲取錯誤信息
ApiErrorNames.getErrorInfo = (error_name) => {

    var error_info;

    if (error_name) {
        error_info = error_map.get(error_name);
    }

    //如果沒有對應的錯誤信息,默認"未知錯誤"
    if (!error_info) {
        error_name = UNKNOW_ERROR;
        error_info = error_map.get(error_name);
    }

    return error_info;
}

//返回正確信息
ApiErrorNames.getSuccessInfo = (data) => {

    var success_info;
    let name = "SUCCESS";
    success_info = error_map.get(name);
    if (data) {
        success_info.data = data
    }

    return success_info;
}

module.exports = ApiErrorNames;

創建controller文件夾

對路由users進行邏輯編寫
const mysqlModel = require("../lib/mysql") //引入數據庫方法
const jwt = require("jsonwebtoken")
const config = require("../config/default.js")
const ApiErrorNames = require("../error/ApiErrorNames.js")
const moment = require("moment")

/**
 * 普通登錄
 */
exports.login = async (ctx, next) => {
  const { body } = ctx.request
  try {
    const user = await mysqlModel.findUser(body.username)
    if (!user) {
      // ctx.status = 401
      ctx.body = ApiErrorNames.getErrorInfo(ApiErrorNames.USER_NOT_EXIST)
      return
    }
    let bodys = await JSON.parse(JSON.stringify(user))
    // 匹配密碼是否相等
    if ((await user.user_pwd) === body.password) {
      let data = {
        user: user.user_id,
        // 生成 token 返回給客戶端
        token: jwt.sign(
          {
            data: user.user_id,
            // 設置 token 過期時間
            exp: Math.floor(Date.now() / 1000) + 60 * 60 // 60 seconds * 60 minutes = 1 hour
          },
          config.secret
        )
      }
      ctx.body = ApiErrorNames.getSuccessInfo(data)
    } else {
      ctx.body = ApiErrorNames.getErrorInfo(ApiErrorNames.USER_LOGIN_ERROR)
    }
  } catch (error) {
    ctx.throw(500)
  }
}

/**
 * 獲取用戶信息
 */
exports.info = async (ctx, next) => {
  const { body } = ctx.request
  // console.log(body)
  try {
    const token = ctx.header.authorization
    let payload
    if (token) {
      payload = await jwt.verify(token.split(" ")[1], config.secret) // 解密,獲取payload
      const user = await mysqlModel.findUserAndRole(payload.data)
      if (!user) {
        ctx.body = ApiErrorNames.getErrorInfo(ApiErrorNames.USER_NOT_EXIST)
      } else {
        let cont = user.user_count + 1
        let updateInfo = [
          cont,
          moment().format("YYYY-MM-DD HH:mm:ss"),
          user.id
        ]
        await mysqlModel
        .UpdataUserInfo(updateInfo)
        .then(res => {
          let data = {
            avatar: "https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif",
            name: user.user_id,
              // roles: [user.user_admin === 0 ? "admin" : ""]
            roles: [user.role_name]
          }
          ctx.body = ApiErrorNames.getSuccessInfo(data)
        })
        .catch(err => {
          ctx.body = ApiErrorNames.getErrorInfo(ApiErrorNames.DATA_IS_WRONG)
        })
      }
    } else {
      ctx.body = ApiErrorNames.getErrorInfo(ApiErrorNames.INVALID_TOKEN)
    }
  } catch (error) {
    ctx.throw(500)
  }
}

/**
 * 退出登錄
 */
exports.logout = async (ctx, next) => {
  try {
    // ctx.status = 200
    ctx.body = ApiErrorNames.getSuccessInfo()
  } catch (error) {
    ctx.throw(500)
  }
}
routes中的users.js
const router = require("koa-router")() //引入路由函數
const userControl = require("../controller/users") //引入邏輯
// const config = require("../config/default.js")

router.get("/", async (ctx, next) => {
  "use strict"
  ctx.redirect("/user/login")
})
// 路由中間間,頁面路由到/,就是端口號的時候,(網址),頁面指引到//user/login

router.get("/user/info", userControl.info)
router.post("/user/logout", userControl.logout)
router.post("/user/login", userControl.login)

module.exports = router
//將頁面暴露出去
備注

ctx.request 獲取post請求中的body
ctx.query.xx 獲取get請求中的參數
router.prefix("/account") 給router實例添加前綴

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102622.html

相關文章

  • 全棧前端入門必看 koa2+mysql+vue+vant 構建簡單版移動端博客

    摘要:要注意這里必須和創建的時候傳入的一致,因為服務端需要用創建時的來解密。是校驗碼解析時需要一致才能取到信息過期時間設置為格式有。 koa2+mysql+vue+vant 構建簡單版移動端博客 具體內容展示 showImg(https://segmentfault.com/img/remote/1460000015962704?w=375&h=670); showImg(https://s...

    maybe_009 評論0 收藏0
  • 全棧前端入門必看 koa2+mysql+vue+vant 構建簡單版移動端博客

    摘要:要注意這里必須和創建的時候傳入的一致,因為服務端需要用創建時的來解密。是校驗碼解析時需要一致才能取到信息過期時間設置為格式有。 koa2+mysql+vue+vant 構建簡單版移動端博客 具體內容展示 showImg(https://segmentfault.com/img/remote/1460000015962704?w=375&h=670); showImg(https://s...

    Galence 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<