写在前面
nuxt-bnhcp 是我写的一个全栈商城系统, 从前端 ui 切图到后台 MySQL 以及 Redis 缓存, 是一个相对完整且系统的项目, nuxt-bnhcp 开源至今, 收到了大量的反馈和朋友们遇到的问题以及 nuxt-bnhcp 后台源码问题, 因为后台配置和项目庞大没有时间腾出手写一篇文章去详细的介绍一下自己项目, 今天, 所有的后台代码以及前端代码已经提交至 GitHub. 我非常期待大家可以给我提出建议和优化. 下面介绍下我的 nuxt-bnhcp:
GitHub 地址: https://github.com/github1586/nuxt-bnhcp
线上地址: http://nodet.cn
流程图
后台目录介绍
├── API ## 请求 API 目录
│ ├── controller ## 处理业务逻辑
│ │ ├── cart ## 购物车
│ │ │ └── index.JS
│ │ ├── course ## 课程列表
│ │ │ └── index.JS
│ │ ├── home ## 首页加载
│ │ │ └── index.JS
│ │ ├── interface.JS
│ │ ├── login ## 登录注册
│ │ │ └── index.JS
│ │ ├── order ## 订单中心
│ │ │ └── index.JS
│ │ ├── paramsFilter.JS ##sql 参数过滤器
│ │ └── router.JS ## 路由
│ ├── index.JS ## 导出路由
│ ├── model ##MySQL 数据库相关
│ │ ├── db.JS ## 数据库增删改查封装
│ │ ├── settings.JS ## 数据库配置用户
│ │ └── sql.JS ##sql 语句
│ └── Redis ##Redis 设置
│ └── Redis.JS
└── index.JS ## 后台服务入口
后台源码分析
interface.JS
- import {
- Router
- } from 'express'
- const myrouter = require('./router.js')
- var router = Router()
- // index router
- router.get('/', myrouter.indexShow)
- // 页面初始化加载一级分类第一个
- router.get('/listhome', myrouter.gradeOne)
- // 点击对应一级 给出三级响应
- router.get('/listhome/:id', myrouter.gradeOne)
- // 点击筛选请求展示内容
- router.get('/listhome/filter/data', myrouter.filter)
- // 课程列表
- router.get('/courselist', myrouter.getCourseList)
- // 课程详情
- router.get('/courseDetail/index/:id', myrouter.getDetail)
- // 课程模糊查询
- router.get('/getleckCourse', myrouter.getleckCourse)
- // 购物车存储 id
- router.get('/postCourseId', myrouter.postCourseId)
- // 是否存在购物车
- router.get('/isexistCart/:id', myrouter.isCart)
- // 购物车列表
- router.get('/cartList', myrouter.cartList)
- // 删除购物车列表
- router.get('/deleteCart', myrouter.deleteCart)
- // 批量提交购物车
- router.get('/mostAddClass', myrouter.mostAddClass)
- // 登录
- router.post('/longin', myrouter.longin)
- // 提交订单
- router.get('/submitOrder', myrouter.submitOrder)
- // 支付成功 更改订单状态
- router.get('/paySuccess', myrouter.paySuccess)
- // 请求订单列表
- router.get('/getOrderList', myrouter.getOrderList)
- export default router
匹配路由调用处理对应业务逻辑
- /**
- * Created by bobo on 2017/06/10 21.31
- */
- var indexshowController = require('./home') // 主页
- var courseController = require('./course') // 课程
- var cartController = require('./cart') // 购物车
- var loginController = require('./login') // 登录
- var orderController = require('./order') // 订单
- exports.indexShow = indexshowController.indexShow // 首页展示
- exports.gradeOne = courseController.gradeOne // 默认一级分类
- exports.filter = courseController.filter // 筛选条件
- exports.getCourseList = courseController.getCourseList // 课程列表
- exports.getDetail = courseController.getDetail // 课程详情
- exports.getleckCourse = courseController.getleckCourse // 课程模糊查询
- exports.postCourseId = cartController.postCourseId // 购物车 商品 id
- exports.isCart = cartController.isCart // 是否存在购物车
- exports.cartList = cartController.cartList // 购物车列表
- exports.deleteCart = cartController.deleteCart // 删除购物车
- exports.mostAddClass = cartController.mostAddClass // 批量提交购物车
- exports.longin = loginController.longin // 登录
- exports.submitOrder = orderController.submitOrder // 订单
- exports.paySuccess = orderController.paySuccess // 支付成功
- exports.getOrderList = orderController.getOrderList // 获取订单列表
引入对应业务模块 导出对应业务方法
- const db = require('../../model/db.js')
- const sql = require('../../model/sql.js')
- // 引入 Redis
- var dbs = require('../../redis/redis.js')
- /**
- * index show
- */
- exports.indexShow = (req, res, next) => {
- db.query(sql.index, function (err, rows, fields) {
- if (err) {
- throw err
- }
- // 检查是否存在获取值 (Redis)
- dbs.exists('indexshow', function (err, results) {
- if (err) {
- throw err
- }
- if (results) {
- dbs.get('indexshow', function (err, result) {
- if (err) {
- return
- }
- res.JSON(JSON.parse(result))
- })
- } else {
- var allparentinfo = []
- var indexClass = []
- for (var i = 0; i <rows.length; i++) {
- // 两个大分类
- var classList = []
- // 四个小分类
- var classMoreList = []
- // 两个大分类
- var classImg = rows[i].showMainName.split('&')
- for (var j = 0; j < classImg.length; j++) {
- // 每次得到的对象 push 进数组
- classList.push({ classname: classImg[j].split('@')[0], imgurl: classImg[j].split('@')[1], coueseGradeId: rows[i].coueseGradeId })
- }
- // 四个小分类 课程名称
- var classSmall = rows[i].showSmallName.split('&')
- for (var x = 0; x < classSmall.length; x++) {
- classMoreList.push({classname: classSmall[x].split('@')[0], imgurl: classSmall[x].split('@')[1], coueseGradeId: rows[i].coueseGradeId})
- }
- // 把整块 push 到数据数组
- allparentinfo.push({headinfo: {before: rows[i].showCourseMore, after: rows[i].showCourseName, imgurl: rows[i].showCourseIcon},
- course: {
- classList: classList,
- classMoreList: classMoreList
- }})
- }
- // 查找分类
- db.query(sql.showClass, function (err, rows, fields) {
- if (err) {
- throw err
- }
- // 循环查找数据
- for (var i = 0; i < rows.length; i++) {
- var classObj = {}
- classObj.showClassImg = rows[i].showClassImg
- classObj.showClassName = rows[i].showClassName
- classObj.classPid = rows[i].classPid
- indexClass.push(classObj)
- }
- // 专成 JSON 格式
- var data = {allparentinfo: allparentinfo, indexClass: indexClass}
- // 设置值
- dbs.set('indexshow', JSON.stringify(data), 300, function (err, result) {
- if (err) {
- res.JSON(err)
- }
- })
- res.JSON(data)
- })
- }
- })
- })
- }
首页业务处理, 接收请求 -> 是否走缓存 -> 是否命中缓存 -> 正常业务处理
MySQL 部分
MySQL 是一种 DBMS(数据库管理系统), 也是一个关系数据库. 其中 My 是 MySQL 的联合创始人 - Monty Widenius 的女儿的名字. MySQL 是 My 和 SQL 的组合, 这就是 MySQL 命名的由来. 它是由 Oracle 支持的开源软件. 这意味着任何一个人都可以免费使用 MySQL. 另外, 如果需要, 还可以更改其源代码或进行二次开发以满足您的需要.
MySQL 可以在各种平台上运行 UNIX,Linux,Windows 等. 可以将其安装在服务器甚至桌面系统上. 此外, MySQL 是可靠, 可扩展和快速的.
- /**
- * 数据库操作 @bobo
- * 2017/06/10
- */
- const MySQL = require('mysql')
- const setting = require('./settings.js')
- // 填写数据库连接信息,
- const option = {
- host: setting.host,
- port: setting.port,
- user: setting.username,
- password: setting.password,
- database: setting.name
- }
- // 建立连接池
- const pool = MySQL.createPool(option)
- /**
- * select 和 delete 操作
- * @param {string} sql sql 语句
- * @param {Function} callback 回调函数
- * @return {none}
- * */
- const __selsctDelete = (sql, callback) => {
- pool.getConnection(function (err, conn) {
- if (err) {
- console.log('CONNECT ERROR:', err.message)
- callback(err, null, null)
- } else {
- conn.query(sql, function (err, rows, fields) {
- // 释放连接
- conn.release()
- // 事件驱动回调
- callback(err, rows, fields)
- })
- }
- })
- }
- /**
- * update 和 insert 操作
- * @param {string} sql sql 语句
- * @param {array} params 参数数组
- * @param {Function} callback 回调函数
- * @return {none}
- */
- const __updateInsert = function (sql, params, callback) {
- pool.getConnection(function (err, conn) {
- if (err) {
- console.log('CONNECT ERROR:', err.message)
- callback(err, null, null)
- } else {
- conn.query(sql, params, function (err, rows, fields) {
- // 释放连接
- conn.release()
- // 事件驱动回调
- callback(err, rows, fields)
- })
- }
- })
- }
- /**
- * query 函数重载
- * @return {none}
- */
- exports.query = function () {
- var length = arguments.length
- var sql = '' var cb =''
- if (length === 2) {
- sql = arguments[0]
- cb = arguments[1]
- __selsctDelete(sql, cb)
- } else if (length === 3) {
- sql = arguments[0]
- var params = arguments[1]
- cb = arguments[2]
- __updateInsert(sql, params, cb)
- } else {
- console.log('ERROR:', '参数不对呀? 亲~~')
- }
- }
利用重载对 MySQL 的增删改查做一些封装操作
Redis 介绍
Redis 是一个开源的使用 ANSI C 语言编写, 支持网络, 可基于内存亦可持久化的日志型, Key-Value 数据库, 并提供多种语言的 API
- var dbs = {}
- var Redis = require('redis')
- var client = Redis.createClient()
- client.on('error', function (err) {
- console.log('Error :', err)
- })
- client.on('connect', function () {
- // console.log('Redis 连接成功.')
- })
- /**
- * 添加 string 类型的数据
- * @param key 键
- * @params value 值
- * @params expire (过期时间, 单位秒; 可为空, 为空表示不过期)
- * @param callBack(err,result)
- */
- dbs.set = function (key, value, expire, callback) {
- client.set(key, value, function (err, result) {
- if (err) {
- console.log(err)
- callback(err, null)
- return
- }
- if (!isNaN(expire) && expire> 0) {
- client.expire(key, parseInt(expire))
- }
- callback(null, result)
- })
- }
- /**
- * 查询 string 类型的数据
- * @param key 键
- * @param callBack(err,result)
- */
- dbs.get = function (key, callback) {
- client.get(key, function (err, result) {
- if (err) {
- console.log(err)
- callback(err, null)
- return
- }
- callback(null, result)
- })
- }
- /**
- * 查询是否存在
- * @param key 键
- * @param callBack(err,result)
- */
- dbs.exists = function (key, callback) {
- client.exists(key, function (err, result) {
- if (err) {
- console.log(err)
- callback(err, null)
- return
- }
- callback(null, result)
- })
- }
- /**
- * 生成自增 id
- * @param key 键
- * @param callBack(err,result)
- */
- dbs.orderId = function (callback) {
- let time = new Date()
- let second = time.getTime()
- let year = time.getFullYear()
- let month = time.getMonth() + 1
- let date = time.getDate()
- client.exists('orders', function (err, result) {
- if (err) {
- throw err
- }
- if (!result) { // 第一次进入生成 id
- client.set('orders', second, function (err, result) { // 设置 id
- if (err) {
- throw err
- }
- })
- } else {
- client.INCR('orders') // 每次自增
- dbs.get('orders', function (err, results) { // 得到 id 回调上传
- if (err) {
- throw err
- }
- results = results + '' + year + month + date
- callback(null, results)
- })
- }
- })
- }
- // 导出对象
- module.exports = dbs
对 Redis 的增删改查做封装, 其中生成自增 id 方法是针对提交订单后生成唯一订单号
nginx 介绍
5, nginx 配置文件
nginx.conf 文件:
- worker_processes 1;
- error_log logs/error.log;
- error_log logs/error.log notice;
- error_log logs/error.log info;
- pid logs/nginx.pid;
- events {
- use epoll;
- worker_connections 1024;
- }
- http {
- include mime.types;
- default_type application/octet-stream;
- sendfile on;
- keepalive_timeout 65;
- #gzip on;
- include /usr/local/nginx/conf/conf_site/*.conf; // 单独 include conf 文件
- }
include 的 conf 配置 :
- server{
- listen 80;
- location / {
- deny all;
- }
- }
- upstream maven_domain_com {
- server localhost:8000; // 自己的服务器 ip
- }
- server{
- listen 80; // 监听 80 端口
- server_name maven.domains.com; // 自己的二级域名
- location / {
- proxy_pass http://maven_domains_com/nexus/;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
- location /nexus/ {
- proxy_pass http://maven_domain_com/nexus/;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
- }
CentOS 服务器上的 nginx 配置.
END!!!
欢迎大家交流~
来源: https://juejin.im/post/5bd2d9a36fb9a05cd77788eb