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
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');
}
}
}
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.在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) {
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
})
}
6.添加书架按钮状态获取,我们可以调用mixin中的getShelfList方法,到StoreDetail中的counted属性中调用,获取到书架数据,从而可以判断到该书是否在书架中
mounted() {
this.init()
//判断是否等于0时和,才刷新,解决性能消耗
if(!this.ShelfList || this.ShelfList.length === 0){
this.getShelfList()
}
}
7.前面把read的获取电子书的地址改动了以后,把分类地址删除了。现在在运行过程中出现报错。原因是在StoreDetail组件中获取分类是空,所以在readBook方法中把分类地址添加进去
readBook() {
this.$router.push({
path: `/ebook/${this.categoryText}|${this.fileName}`
})
},
//改为
path: `/ebook/${this.bookItem.categoryText}|${this.fileName}`
- 这是read中的报错解决
if(href){
if(href[1]===loc){
nav.pagelist.push(item)
}
}
上线
数据库环境准备
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)
})
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()
})
})
首页接口
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()
})
})
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
}
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
4.创建const.js模块来储存公用数据,然后再到app.js中把const模块引入
const resUrl = 'http://192.168.31.243:8081'
module.exports = {
resUrl,
}
//引入模块
const constant = require('./const')
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
}
7.推荐图书加工
function createRecommendData(data) {
//随机生成
data['readers'] = Math.floor(data.id / 2 * randomArray(1, 100))
return data
}
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,
}
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
}
到项目中调用首页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
2.报错,到node.js接口中解决跨域问题,引入库cnpm i -S cors
在app.js中引入
const cors = require('cors')
app.use(cors())
3.首页bulnn图(轮播图)没有加入进来,到app.js中把图加入
const banner = constant.resUrl + '/home_banner2.jpg'
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)
}
电子书详情页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()
})
})
电子书列表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()
})
})
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.比较简单,直接返回一个数组就行,
因为没有数据,+号(添加书籍)按钮没有出现,所以我们要用json返回一个空的数组
app.get('/book/shelf', (req, res) => {
res.json({
bookList: []
})
})
科大讯飞在线语音合成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)
})
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
在const.js中加入mp3文件路径地址
mp3FilePath = '/root/nginx/upload/mp3'
后端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
阿里云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