当前位置:   article > 正文

微信读书第十章(nodejs数据连接+上线)_http//192.168.0.174:8000

http//192.168.0.174:8000

Vue项目构建

分析:
1.将环境变量文件.env.development名字改成.env.producation
2.将环境变量里面的环境地址都改成线上地址

//原来
VUE_APP_RES_URL=http://192.168.0.174:9000
VUE_APP_EPUB_URL=http://47.99.166.157/epub
VUE_APP_BASE_URL=http://192.168.0.174:8080
VUE_APP_BOOK_URL=http://47.99.166.157:3000
VUE_APP_EPUB_OPF_URL=http://47.99.166.157/epub2
VUE_APP_VOICE_URL=http://47.99.166.157:3000
//改
VUE_APP_RES_URL=http://47.99.166.157/book/res
VUE_APP_EPUB_URL=http://47.99.166.157/epub
VUE_APP_BASE_URL=http://47.99.166.157:3000
VUE_APP_BOOK_URL=http://47.99.166.157:3000
VUE_APP_EPUB_OPF_URL=http://47.99.166.157/epub2
VUE_APP_VOICE_URL=http://47.99.166.157:3000
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3.调cnpm run build,构建完了会生成dist目录,
分析:如有警告就是文件大小过大,
需要配置vue.config,修改配置后再执行一次cnpm run build

     configureWebpack:{
      performance: {
	    	hints:'warning',
	    	//入口起点的最大体积
	    	maxEntrypointSize: 50000000,
	    	//生成文件的最大体积
	    	maxAssetSize: 30000000,
	    	//只给出 js 文件的性能提示
	    	assetFilter: function(assetFilename) {
	    		return assetFilename.endsWith('.js');
	    	}
	    }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

4.再次报console.log打印错误,可以直接点击左上方的find in path 搜索console.log,把console.log注释掉
5.打包编译后,点击阅读电子书,出现404错误,在read中获取电子书的路径拼错了,修改如下

 this.setFileName(books.join('/')).then(()=>{
                    const url = process.env.VUE_APP_EPUB_URL + '/'+ this.fileName + '.epub'
                    this.initEpub(url)
  • 1
  • 2
  • 3

添加加入书架功能

1.在storeDetail组件中添加点击事件,addOrRemoveShelf,调用store.js中两个方法
需要把vuex中的数据进行更新

 addOrRemoveShelf() {
        // 判断这本书是否在书架中
        if(this.inBookShelf){
          // 存在就删除,再异步保存
          removeFromBookShelf(this.bookItem).then(()=>{
            saveBookShelf(this.ShelfList)
        }else{
          // 不在求添加
          addToShelf(this.bookItem)
        }
        this.setShelfList(getBookShlef) //更新VUEX
      },

    //  将次方法改为shelfList,两处
inBookShelf() {
        if (this.bookItem && this.shelfList) {      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2.上述的删除书本和添加书本方法可能会多处使用,所以我们添加到store.js中

//添加书本方法
export function addToShelf(book) {
	//到书架中把书拿出来
  let shelfList = getBookShelf()
  //去到最后一本书
  shelfList = removeAddFromShelf(shelfList)
  book.type = 1  //要添加到最后,添加一个字段
  shelfList.push(book)  //添加
  shelfList = computeId(shelfList)  //重新计算id
  //最后再删除的添加进去
  shelfList = appendAddToShelf(shelfList)
  saveBookShelf(shelfList)  //保存
}
//删除书本方法
export function removeFromBookShelf(book) {
//获取书本
  return getBookShelf().filter(item => {	
    if (item.itemList) { //书架里是否有这本书
    //删除
      item.itemList = removeAddFromShelf(item.itemList)
    }
    //不相等就保留,相等就移除
    return item.fileName !== book.fileName
  })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

6.添加书架按钮状态获取,我们可以调用mixin中的getShelfList方法,到StoreDetail中的counted属性中调用,获取到书架数据,从而可以判断到该书是否在书架中

 mounted() {
      this.init()
     //判断是否等于0时和,才刷新,解决性能消耗
      if(!this.ShelfList || this.ShelfList.length === 0){
        this.getShelfList()
      }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

7.前面把read的获取电子书的地址改动了以后,把分类地址删除了。现在在运行过程中出现报错。原因是在StoreDetail组件中获取分类是空,所以在readBook方法中把分类地址添加进去

 readBook() {
        this.$router.push({
          path: `/ebook/${this.categoryText}|${this.fileName}`
        })
      },
      //改为
       path: `/ebook/${this.bookItem.categoryText}|${this.fileName}`
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 这是read中的报错解决
	 if(href){
          if(href[1]===loc){
             nav.pagelist.push(item)
      }
}
  • 1
  • 2
  • 3
  • 4
  • 5

上线

数据库环境准备

1.建立一个数据库,数据库名book,字符集utf8 排序规则utf8_general_ci
2.到入第十章的book.sql数据表
3.还有cover和img主要存储了图书的封面数据,把它拷贝到resoures下载文件夹中。
4.把epub和epub2(是电子书解压以后的路径)也拷贝到resoures

创建Nodejs+express编写api

1.在页面创建一个名为node-imooc-ebook的空项目;
2.创建app.js,然后初始化项目,npm init
3.安装express框架:cnpm i express -S
4.在Node中不能使用e6导入文件,所以导入express
解析:原理express源码中是一个暴露了一个function,返回了一个app,还是一个方法。app里有很多方法get

const express = require('express')
const app = express()

app.get('/', (req, res) => {
  res.send(new Date().toDateString())
})

//项目启动接口,用app.listen
const server = app.listen(3000, () => {
//通过回调函数获取返回值,host 是获取当前的ip地址
  const host = server.address().address
  //监听的端口号
  const port = server.address().port
	//启动成功输出的内容
  console.log('server is listening at http://%s:%s', host, port)
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

5.启动方法:1.node app.js
2.使用左上add Configuration,点+号,点击Node.js. Name写app,node parameters写app.js
调试直接就可以点击上方的甲虫
6.安装cnpm i mysql -S 然后导入mysql数据库。配置数据库

const mysql = require('mysql')

//链接数据库
function connect() {
  return mysql.createConnection({
    host: constant.dbHost, //本地localhost
    user: constant.dbUser, //root
    password: constant.dbPwd, //123456
    database: 'book'  
  })
}

//再写一个接口
app.get('/book/list', (req, res) => {
  const conn = connect() //链接
  //调用conn.query返回的对象,调用查询语句
  conn.query('select * from book where cover!=\'\'',
  //err是否错误
    (err, results) => {
      if (err) { //有错误
      	//向前台返回一个json对象
        res.json({
          error_code: 1,
          msg: '获取失败'
        })
      } else { //成功
      
        results.map(item => handleData(item))
        const data = {}
        constant.category.forEach(categoryText => {
          data[categoryText] = results.filter(item => item.categoryText === categoryText)
        })
        //成功了就返回提示
        res.json({
          error_code: 0,
          msg: '获取成功',
          data: data,
          total: results.length
        })
      }
      //一定要把数据库链接关闭
      conn.end()
    })
})


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

首页接口

app.get('/book/home', (req, res) => {
  const conn = connect()
  conn.query('select * from book where cover != \'\'',
    (err, results) => {
     //获取长度
      const length = results.length
      //返回的类表
      const guessYouLike = []
      //首页封面图片
      const banner = constant.resUrl + '/home_banner2.jpg'
      const recommend = [] //推荐图书
      const featured = []  //精选
      const random = []  //随机图书
      const categoryList = createCategoryData(results) 
      const categories = [ //分类的数据
        {
          category: 1,
          num: 56,
          img1: constant.resUrl + '/cover/cs/A978-3-319-62533-1_CoverFigure.jpg',
          img2: constant.resUrl + '/cover/cs/A978-3-319-89366-2_CoverFigure.jpg'
        },
        {
          category: 2,
          num: 51,
          img1: constant.resUrl + '/cover/ss/A978-3-319-61291-1_CoverFigure.jpg',
          img2: constant.resUrl + '/cover/ss/A978-3-319-69299-9_CoverFigure.jpg'
        },
        {
          category: 3,
          num: 32,
          img1: constant.resUrl + '/cover/eco/A978-3-319-69772-7_CoverFigure.jpg',
          img2: constant.resUrl + '/cover/eco/A978-3-319-76222-7_CoverFigure.jpg'
        },
        {
          category: 4,
          num: 60,
          img1: constant.resUrl + '/cover/edu/A978-981-13-0194-0_CoverFigure.jpg',
          img2: constant.resUrl + '/cover/edu/978-3-319-72170-5_CoverFigure.jpg'
        },
        {
          category: 5,
          num: 23,
          img1: constant.resUrl + '/cover/eng/A978-3-319-39889-1_CoverFigure.jpg',
          img2: constant.resUrl + '/cover/eng/A978-3-319-00026-8_CoverFigure.jpg'
        },
        {
          category: 6,
          num: 42,
          img1: constant.resUrl + '/cover/env/A978-3-319-12039-3_CoverFigure.jpg',
          img2: constant.resUrl + '/cover/env/A978-4-431-54340-4_CoverFigure.jpg'
        },
        {
          category: 7,
          num: 7,
          img1: constant.resUrl + '/cover/geo/A978-3-319-56091-5_CoverFigure.jpg',
          img2: constant.resUrl + '/cover/geo/978-3-319-75593-9_CoverFigure.jpg'
        },
        {
          category: 8,
          num: 18,
          img1: constant.resUrl + '/cover/his/978-3-319-65244-3_CoverFigure.jpg',
          img2: constant.resUrl + '/cover/his/978-3-319-92964-4_CoverFigure.jpg'
        },
        {
          category: 9,
          num: 13,
          img1: constant.resUrl + '/cover/law/2015_Book_ProtectingTheRightsOfPeopleWit.jpeg',
          img2: constant.resUrl + '/cover/law/2016_Book_ReconsideringConstitutionalFor.jpeg'
        },
        {
          category: 10,
          num: 24,
          img1: constant.resUrl + '/cover/ls/A978-3-319-27288-7_CoverFigure.jpg',
          img2: constant.resUrl + '/cover/ls/A978-1-4939-3743-1_CoverFigure.jpg'
        },
        {
          category: 11,
          num: 6,
          img1: constant.resUrl + '/cover/lit/2015_humanities.jpg',
          img2: constant.resUrl + '/cover/lit/A978-3-319-44388-1_CoverFigure_HTML.jpg'
        },
        {
          category: 12,
          num: 14,
          img1: constant.resUrl + '/cover/bio/2016_Book_ATimeForMetabolismAndHormones.jpeg',
          img2: constant.resUrl + '/cover/bio/2017_Book_SnowSportsTraumaAndSafety.jpeg'
        },
        {
          category: 13,
          num: 16,
          img1: constant.resUrl + '/cover/bm/2017_Book_FashionFigures.jpeg',
          img2: constant.resUrl + '/cover/bm/2018_Book_HeterogeneityHighPerformanceCo.jpeg'
        },
        {
          category: 14,
          num: 16,
          img1: constant.resUrl + '/cover/es/2017_Book_AdvancingCultureOfLivingWithLa.jpeg',
          img2: constant.resUrl + '/cover/es/2017_Book_ChinaSGasDevelopmentStrategies.jpeg'
        },
        {
          category: 15,
          num: 2,
          img1: constant.resUrl + '/cover/ms/2018_Book_ProceedingsOfTheScientific-Pra.jpeg',
          img2: constant.resUrl + '/cover/ms/2018_Book_ProceedingsOfTheScientific-Pra.jpeg'
        },
        {
          category: 16,
          num: 9,
          img1: constant.resUrl + '/cover/mat/2016_Book_AdvancesInDiscreteDifferential.jpeg',
          img2: constant.resUrl + '/cover/mat/2016_Book_ComputingCharacterizationsOfDr.jpeg'
        },
        {
          category: 17,
          num: 20,
          img1: constant.resUrl + '/cover/map/2013_Book_TheSouthTexasHealthStatusRevie.jpeg',
          img2: constant.resUrl + '/cover/map/2016_Book_SecondaryAnalysisOfElectronicH.jpeg'
        },
        {
          category: 18,
          num: 16,
          img1: constant.resUrl + '/cover/phi/2015_Book_TheOnlifeManifesto.jpeg',
          img2: constant.resUrl + '/cover/phi/2017_Book_Anti-VivisectionAndTheProfessi.jpeg'
        },
        {
          category: 19,
          num: 10,
          img1: constant.resUrl + '/cover/phy/2016_Book_OpticsInOurTime.jpeg',
          img2: constant.resUrl + '/cover/phy/2017_Book_InterferometryAndSynthesisInRa.jpeg'
        },
        {
          category: 20,
          num: 26,
          img1: constant.resUrl + '/cover/psa/2016_Book_EnvironmentalGovernanceInLatin.jpeg',
          img2: constant.resUrl + '/cover/psa/2017_Book_RisingPowersAndPeacebuilding.jpeg'
        },
        {
          category: 21,
          num: 3,
          img1: constant.resUrl + '/cover/psy/2015_Book_PromotingSocialDialogueInEurop.jpeg',
          img2: constant.resUrl + '/cover/psy/2015_Book_RethinkingInterdisciplinarityA.jpeg'
        },
        {
          category: 22,
          num: 1,
          img1: constant.resUrl + '/cover/sta/2013_Book_ShipAndOffshoreStructureDesign.jpeg',
          img2: constant.resUrl + '/cover/sta/2013_Book_ShipAndOffshoreStructureDesign.jpeg'
        }
      ]
      //随机获取9本不同的书,
      randomArray(9, length).forEach(key => { //这个数组通过for来获取全部数组
      //通过createGuessYouLike加工后,把数据再加入到guessYouLike中
        guessYouLike.push(createGuessYouLike(createData(results, key)))
      })
      //推荐图书,拿到三本图书
      randomArray(3, length).forEach(key => {
        recommend.push(createRecommendData(createData(results, key)))
      })
      //获取6本精选图书
      randomArray(6, length).forEach(key => {
      	//书普通图书,直接获取就好了
        featured.push(createData(results, key))
      })
      //随机图书,
      randomArray(1, length).forEach(key => {
      	//随机获取一本就好了
        random.push(createData(results, key))
      })
      //把上面所定义的数据,都返回
      res.json({
        guessYouLike,  
        banner,
        recommend,
        featured,
        categoryList,
        categories,
        random
      })
      //断开链接
      conn.end()
    })
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182

2.首页api中需要实现随机数,添加一个方法.
测试时localhost:3000/book/home

//n是要几本书,l是一共有几本书
function randomArray(n, l) {
	//保存到rnd的变量中
  let rnd = []
  for (let i = 0; i < n; i++) {
  	//向下取整,获取0到1之间的随机时,再*l,这样最大的数都不会大于l
    rnd.push(Math.floor(Math.random() * l))
  }
  //返回
  return rnd
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3.创建createData

//根据results和key找到对应的书
function createData(results, key) {
  return handleData(results[key])
}
//封装的
function handleData(data) {
	//对封面进行加工,不是http://开头的
  if (!data.cover.startsWith('http://')) {
  	//resUrl地址,
    data['cover'] = `${constant.resUrl}/img${data.cover}`
  }
  //其他的属性
  data['selected'] = false
  data['private'] = false
  data['cache'] = false //是否缓存
  data['haveRead'] = 0  //是否阅读
  //返回
  return data
}

//再创建本地地址resUrl

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

4.创建const.js模块来储存公用数据,然后再到app.js中把const模块引入

 const  resUrl = 'http://192.168.31.243:8081'
 
 module.exports = {
  resUrl,
}

//引入模块
const constant = require('./const')

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

6.创建createGuessYouLike方法给获取到的数据再次加工一下

function createGuessYouLike(data) {
	//随机生成,1-3的数字
  const n = parseInt(randomArray(1, 3)) + 1
  data['type'] = n
  switch (n) {
    case 1:
    	//根据id是否为偶数,显示另外一种形式.简单算法
      data['result'] = data.id % 2 === 0 ? '《Executing Magic》' : '《Elements Of Robotics》'
      break
    case 2:
      data['result'] = data.id % 2 === 0 ? '《Improving Psychiatric Care》' : '《Programming Languages》'
      break
    case 3:
      data['result'] = '《Living with Disfigurement》'
      data['percent'] = data.id % 2 === 0 ? '92%' : '97%'
      break
  }
  //返回数据
  return data
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

7.推荐图书加工

function createRecommendData(data) {
	//随机生成
  data['readers'] = Math.floor(data.id / 2 * randomArray(1, 100))
  return data
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

8.添加通用数据const.jscategory

const category = [
  'Biomedicine',
  'BusinessandManagement',
  'ComputerScience',
  'EarthSciences',
  'Economics',
  'Engineering',
  'Education',
  'Environment',
  'Geography',
  'History',
  'Laws',
  'LifeSciences',
  'Literature',
  'SocialSciences',
  'MaterialsScience',
  'Mathematics',
  'MedicineAndPublicHealth',
  'Philosophy',
  'Physics',
  'PoliticalScienceAndInternationalRelations',
  'Psychology',
  'Statistics'
]

module.exports = {
  resUrl,
  category,
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

9.修改handleData

function handleData(data) {
  if (!data.cover.startsWith('http://')) {
    data['cover'] = `${constant.resUrl}/img${data.cover}`
  }
  data['selected'] = false
  data['private'] = false
  data['cache'] = false
  data['haveRead'] = 0
  return data
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

到项目中调用首页api

1.把vue.config.js中的devServer都注释掉,和mock函数,和引入 的 4个组件,再去修改.env.development中的api,把BASE 修改成本地接口

VUE_APP_RES_URL=http://192.168.0.174:9000
VUE_APP_EPUB_URL=http://192.168.0.174:9000/epub
VUE_APP_BASE_URL=http://192.168.0.174:3000
VUE_APP_BOOK_URL=http://192.168.0.174:3000
VUE_APP_EPUB_OPF_URL=http://192.168.0.174:9000/epub2
VUE_APP_VOICE_URL=http://192.168.0.174:3000

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.报错,到node.js接口中解决跨域问题,引入库cnpm i -S cors
在app.js中引入

const cors = require('cors')
app.use(cors())
  • 1
  • 2

3.首页bulnn图(轮播图)没有加入进来,到app.js中把图加入

  const banner = constant.resUrl + '/home_banner2.jpg'

  • 1
  • 2

4.修改图书少出的问题

function createCategoryData(data) {
  const categoryIds = createCategoryIds(6)
  const result = []
  categoryIds.forEach(categoryId => {
    const subList = data.filter(item => item.category === categoryId).slice(0, 4)
    subList.map(item => {
      return handleData(item)
    })
    result.push({
      category: categoryId,
      list: subList
    })
  })
  //返回时过滤,如果itme.list小于4就不要了
  return result.filter(item => item.list.length === 4)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

电子书详情页api开发

1.添加app.get方法
如果获取失败,第一步就查看查询语句是否有误,输出查看

app.get('/book/detail', (req, res) => {
  const conn = connect() //链接数据库
  //获取图书参数
  const fileName = req.query.fileName
  //查询,把获取到的图书参数传入查询
  const sql = `select * from book where fileName='${fileName}'`
  //通过conn.query,来查询这个语言,然把结果放到results中
  conn.query(sql, (err, results) => {
    if (err) { //失败
      res.json({ //返回
        error_code: 1,
        msg: '电子书详情获取失败'
      })
    } else {
      if (results && results.length === 0) { //还是获取失败
        res.json({
          error_code: 1,
          msg: '电子书详情获取失败'
        })
      } else {//成功
      //获取第一本书,进行封装,加工
        const book = handleData(results[0])
        res.json({ //返回成功
          error_code: 0,
          msg: '获取成功',
          data: book
        })
      }
    }
    //关闭数据库
    conn.end()
  })
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

电子书列表api

1.主要是用在分类里面的电子书,里面主要是包含了树状结构

app.get('/book/list', (req, res) => {
  const conn = connect()
  //查找封面不为空的电子书
  conn.query('select * from book where cover!=\'\'',
    (err, results) => {
      if (err) {//请求失败
        res.json({
          error_code: 1,
          msg: '获取失败'
        })
      } else {//成功
      //获取到结果,进行遍历
        results.map(item => handleData(item))
        //对象
        const data = {}
        //对分类进行遍历,categoryText文本
        constant.category.forEach(categoryText => {
        //categoryText作为kye,用filter赛选分类名称相同的电子书找出来
          data[categoryText] = results.filter(item => item.categoryText === categoryText)
        })
        res.json({ //成功
          error_code: 0,
          msg: '获取成功',
          data: data,
          total: results.length //把筛选的内容返回
        })
      }
      conn.end()
    })
})


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

2.普通结构的list

app.get('/book/flat-list', (req, res) => {
  const conn = connect()
  conn.query('select * from book where cover!=\'\'',
    (err, results) => {
      if (err) {
        res.json({
          error_code: 1,
          msg: '获取失败'
        })
      } else {
        results.map(item => handleData(item))
        res.json({
          error_code: 0,
          msg: '获取成功',
          data: results,  //不同的返回results
          total: results.length
        })
      }
      conn.end()
    })
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

图书在线缓存接口

1.比较简单,直接返回一个数组就行,
因为没有数据,+号(添加书籍)按钮没有出现,所以我们要用json返回一个空的数组

app.get('/book/shelf', (req, res) => {
  res.json({
    bookList: []
  })
})
  • 1
  • 2
  • 3
  • 4
  • 5

科大讯飞在线语音合成API对接

1.到科大讯飞官方注册账号,点击控制台,然后点击右上角的创建新应用。
在这里插入图片描述
2.需要添加服务,添加在线语音合成
3.ip白名单,在线系统就需要把在线系统的ip输入进去,本地要拿到外网ip,这样才能调用。不然不能调用。
4.可以点击开发文档实现语音对接,语音合成
5.需要授权认证,
6.到node.js中创建voice模块,用来合成语音api。然后给app.js引入voice模块,创建一个api

const voice = require('./voice')
//这个方法很简单,只要把结果和传入,就能在模块中拿到
app.get('/voice', (req, res) => {
  voice(req, res)
})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

7.到voice创建接口
8.授权认证,x-Appid在我们注册时的id
最会一个需要apikey也在注册中
在这里插入图片描述
需要安装cnpm i -S js-base64库
cnpm i -S js-md5加密库
cnpm i -S qs 对字符串进行处理,让post请求称为,键值对形式
以上都是给xParam使用
cnpm i -S http 库给herad请求

const Base64 = require('js-base64').Base64
const md5 = require('js-md5')
const qs = require('qs')
const http = require('http')
const mp3FilePath = require('./const').mp3FilePath
const resUrl = require('./const').resUrl
const fs = require('fs')




//接收app传来的请求
function createVoice(req, res) {
 //需要传入两个参数,文本和语音
  const text = req.query.text
  const lang = req.query.lang
  // const text = '测试科大讯飞在线语音合成api的功能,比如说,我们输入一段话,科大讯飞api会在线实时生成语音返回给客户端'
  // const lang = 'cn'  cn代表中文
  //中文
  let engineType = 'intp65'
  //如果传入的是英文
  if (lang.toLowerCase() === 'en') {
  	//就修改引擎为英文
    engineType = 'intp65_en'
  }
  //朗读的速度
  const speed = '30'
  //
  const voiceParam = {
    auf: 'audio/L16;rate=16000', //返回的是语音格式
    aue: 'lame', //音频才采样率
    voice_name: 'xiaoyan', //人语音
    speed,  //速度
    volume: '50', //音量
    pitch: '50', //音高
    engine_type: engineType, //引擎类型
    text_type: 'text' //文本类型
  }
  
 //认证部分
 //先获取时间utc的时间,/1000就可以了                    
  const currentTime = Math.floor(new Date().getTime() / 1000)
  //获取注册处的appId 
  const appId = '5c04d087'
  //apiKey祖册中有
  const apiKey = 'd42c864c47d91f468a70079aab059be5'
  //调用Base64.encode进行加密,再用stringify把上面的参数传入
  const xParam = Base64.encode(JSON.stringify(voiceParam))
  //封装三个参数进行加密
  const checkSum = md5(apiKey + currentTime + xParam)
  //定义变量
  const headers = {}
  //封装把参数传入变量
  headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8'
  headers['X-Param'] = xParam
  headers['X-Appid'] = appId
  headers['X-CurTime'] = currentTime
  headers['X-CheckSum'] = checkSum
  headers['X-Real-Ip'] = '127.0.0.1'
  //定义把文本传入,生成请求参数
  const data = qs.stringify({
    text: text
  })
  //请求参数
  const options = {
    host: 'api.xfyun.cn',
    path: '/v1/service/v1/tts', //科大讯飞地址,到接口地址查看
    method: 'POST',
    headers
  }
  //调用http库请求
  const request = http.request(options, response => { //到这可以测试
  //创建mp3文件
    let mp3 = ''
    //对结果进行处理
    const contentLength = response.headers['content-length']
    //将编码格式为二进制文件
    response.setEncoding('binary')
    //通过response.on回调方法回调结果data
    response.on('data', data => {
    //拿到data是语音播放的文件,把data传换成mp3文件
      mp3 += data
      //进度百分显示,用当前接收到长度/总长度
      const process = data.length / contentLength * 100
      //转化成保留两位小数
      const percent = parseInt(process.toFixed(2))
      // console.log(percent)
    })
    //end的时候所有信息以及获取好了
    response.on('end', () => {
      // console.log(response.headers)
      // console.log(mp3)
      //通过这判断类型
      const contentType = response.headers['content-type']
      //如果不是mp3就失败
      if (contentType === 'text/html') {
        res.send(mp3) //直接显示报错
      } else if (contentType === 'text/plain') { //报错,把结果返回前端
        res.send(mp3)
      } else {
      	//将文件保存,名字用当前时间作为名字
        const fileName = new Date().getTime()
        //创建文件路径,到resource中穿件mp3文件夹,输出路径
        const filePath = `${mp3FilePath}/${fileName}.mp3`
        //实际下载的路径
        const downloadUrl = `${resUrl}/mp3/${fileName}.mp3`
        // console.log(filePath, downloadUrl)
        //通过fs写入,filePath路径,数据,文件类型
        fs.writeFile(filePath, mp3, 'binary', err => { //返回
          if (err) { 
            res.json({
              error: 1,
              msg: '下载失败'
            })
          } else {
            res.json({//返回下载成功
              error: 0,
              msg: '下载成功',
              path: downloadUrl
            })
          }
        })
      }
    })
  })
  //传入data
  request.write(data)
  //断开
  request.end()
}
//返回请求内容
module.exports = createVoice

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133

在const.js中加入mp3文件路径地址

 mp3FilePath = '/root/nginx/upload/mp3'
  • 1

后端API源码上传到git

1.打开git,复制一个仓库地址,
2.回到node.js中,调用git init初始化
3.点View>Wool Windows >version Control >browse。然后把四个文件选中,右键Add to vcs。在控制台右键commi 提交到到本地git仓库
4.建立一个.gitignore文件,排除掉一些不希望上传的文件,然后再次commi,把不需要的移除
5.到vcs>git >remots >
在这里插入图片描述
文件名和项目地址,再点击右边的斜上箭头,push

node_modules
.iml
.idea

  • 1
  • 2
  • 3
  • 4

阿里云ECS服务器开通(正式上线)

1.注册账号,点击产品,选择云服务器ECS
2.购买服务器,选择地区,选择核数,单核最便宜17元,镜像选择wind.选6.9(64)
3.存储,选择40g
4.网络不是运维的不需要配置,公网宽度需要选择分配公网IP地址,选择1M固定带宽
5.安全组80窗口
6.系统配置:实例名称用来自定义,剩下的都可以不选
7.分组设置也可以不设置
8.购买期限,下单
购买成功后到管理控制台
1.等待启动…
2.点击升降配置设置密码,然后点击重启。
3.打开cmd控制台:把公网地址复制,输入
ssh root@106.15.231.180
4.点击yes ,输入密码
5.链接上去输入who查看
6.输入ssh-keygen -t rsa 生成公钥,三次y
7.找到公钥的位置 ssh-copy-id -i ~/.ssh/id_rsa.pub root@/106.15.12(公网地址)
8.出现Nub后就可以免密登录
9.出现Broken pipe服务器断开了
10.输入 vim/etc/ssh/sshd_config打开文件
11.选择ClientAliveInterval设置i30,为30秒链接一次服务器
12.改完后输入exit断开,
13.改完配置后需要输入service sshd restart生效,然后再输入exit断开
14.再输入ssh root@imooc链接

安装node.js环境nvm

在这里插入图片描述
1.复制指这段话,到服务器环境中执行,然后输入ll .nvm可以查看是否安装成功
2.输入nvm可以查看是否有效,无效输入vim .bashrc查看是否在这个文件,在这个文件输入source .bashrc 来讲环境变量生效,再输入nvm就可以生效
3.通过nvm install node来安装最近的版本
4.再安装cnpm 进入官方查找
npm install -g cnpm --registry=https://registry.npm.taobao.org


  • 1

  • 1

  • 1

  • 1

  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/247805
推荐阅读
相关标签
  

闽ICP备14008679号