# Dvideo **Repository Path**: dbc35/Dvideo ## Basic Information - **Project Name**: Dvideo - **Description**: Dvideo个人测试使用 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-03-18 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 视频网站开发文档 ## Dai35 ## 基于vue和node开发视频网站文档 ## 1-第一阶段 ### 1·项目介绍 - WEB端 - 视频播放 - 登录注册(手机号、社交账号) - 点赞评论 - 支付 - 积分等级系统 - 技术栈(vue / Bootstrap-vue / SSR ) - 管理端 - 视频管理 - 基础信息管理 - 订单管理 - 用户管理 - 广告位管理 - 技术栈(vue、Element UI) - APP+小程序端 - 登录注册(手机号、社交账号) - 视频播放 - 点赞、评论、转发 - 积分等级系统 - 技术栈(vue、uni-app) - 服务端(管理端) - 技术栈(Nest.js 、 MongoDB) - 服务端(客户端) - 技术栈(Nest.js 、 MongoDB) ### 2·使用nest的子项目模式搭建服务端项目 - 1·托管项目到github - 在存放项目的目录下:命令行代码:`git clone GitHub的目录` - 注意 ssh-key - 2·开发顺序: - 从服务端做起,准备好接口; - 然后再做管理端,添加好数据; - 再开始WEB端,有真实的数据,直接进行接口对接。 - 3·添加服务端: - 首先需要安装 Nest :`npm i -g @nest/cli` ; - nest 新建项目:`nest new project-name(项目名)` - 使用Nest新建服务端目录:`nest new server` - 服务端分管理端和客户端,所以需要分两个子项目 - 到server目录:`cd server` - 创建 admin 子项目: `nest g app admin` - 启动并监听 admin 子项目:`nest start -w admin` ### 3·使用Crud装饰器快速实现增删改查接口 - 新建一个独立的数据库db,用于数据数据库独立于admin和server:`nest g lib db` , 选择输入 @libs - 在admin的app.module中引入db中的DBmodule模块 - ` imports: [ DbModule ],` - 启动MongDB - 在MongoDB的 bin 目录下的命令行:`mongod --dbpath ../data/db` - 连接数据库: - 安装 nestjs-tygoose : `npm i nestjs-typegoose @typegoose/typegoose` - 安装mongoose 代码提示: `npm i mongoose @types/mongoose` - 在db.module中连接数据库: - `imports:[ // 连接数据库 TypegooseModule.forRoot('mongodb://localhost/Dai35',{ //连接参数 useNewUrlParser:true, useUnifiedTopology:true, useCreateIndex:true, useFindAndModify:false, }) ], ` - db下的src下创建存放所有数据库模型的文件夹models , 用户模型 user.model.ts - 在需要的地方使用模型 - 也可以全局引用:db.module.ts中: 标记为全局的`@Global` ,引用用户模型 `const model = TypegooseModule.forFeature([User])`,导入导出模型 - 在admin子项目下添加 users 模块 :server >`nest g mo -p admin users` - 在admin子项目下添加 users 模块 控制器:server >`nest g co -p admin users` - 使用nestjs-mongoose-crud模块: - 安装: `npm i nestjs-mongoose-crud` - user.controller中 `import {Crud} from 'nestjs-mongoose-crud' // 使用 crud 完成用户的增删改查 @Crud({ model:User }) @Controller('users') export class UsersController { // 注入模型 constructor(@InjectModel(User) private readonly model){} }` ### 4.使用swagger和装饰器编写接口文档 - 安装swagger: `npm i @nestjs/swagger swagger-ui-express` - main.ts中写接口文档: - `// 使用swagger 写接口文档 const options = new DocumentBuilder() .setTitle('视频网站-后台管理API') .setDescription('共后台管理界面调用的服务端API') .setVersion('1.0') // .addTag('users') .build(); const document = SwaggerModule.createDocument(app , options) // 接口文档名 api-docs SwaggerModule.setup('api-docs',app,document); ` - 注意:Nest中 - @ApiUseTags 现在是 @ApiTags - @ApiModelProperty 现在是 @ApiProperty ### 5·在Typegoose中定义课程和课时的一对多关联 - db>models下建立课程模块 course.model.ts - admin下创建课程模块 courses: - `cd server` - `nest g mo -p admin courses` - 在admin子项目下添加 courses 模块 控制器:server >`nest g co -p admin courses` - 注意:需要在 db> db.module.ts 中引用 课程模块 和 课时模块,否则会报错 - 课时 增删改查 - 总结步骤:server 下: - 1·先创建模块`nest g mo -p admin episodes` - 2.再创建控制器`nest g co -p admin episodes` - 3·episodes中 - `// 使用CRUD快速完成 episode 的增删改查 @Crud({ model:Episode }) @Controller('episodes') @ApiTags('课时管理') export class EpisodesController { constructor( @InjectModel(Episode)private readonly model:ReturnModelType ){} } ` ++ 《以上已经做好用户,课时,课程增删改查的接口》 ++ ### 6·使用Typescript+ElementUI搭建后台界面(前端项目) - 安装vue :`npm i -g @vue/cli` - 新建一个与server同级的vue项目 admin : `vue create admin` 选项使用默认的就可以; - 使用typeScript :网址 `https://cn.vuejs.org/v2/guide/typescript.html#ad` - 到 admin 目录 加上 elementUI :`vue add element` - 加上路由:`vue add router` - 转成 typescript 项目 :`vue add typescript` - 使用`$ cd admin $ npm run serve` - admin > views >新建一个 Main.vue 进行界面布局 - admin > router >index.ts 中添加 Main.vue 的路由 ### 7.使用ts+axios和el-table展示课程列表 - 新建一个课程列表页面:admin > views > courses > List.vue - admin 下安装 axios 以及其代码提示 @types/axios:`npm i axios @types/axios` - admin > main.ts 中引入 axios 和接口根地址 - `import axios from 'axios'` - `Vue.prototype.$http = axios.create({ // 接口根地址 baseURL:'http://localhost:3000' }) ` - 在服务端设置允许跨域 - server > admin > main.ts 中:`app.enableCors()` - 解决 $http 报错 ,新建custom-vue.d.ts 中添加补充声明: - ` import Vue from 'vue' import {AxiosInstance} from 'axios' declare module 'vue/types/vue'{ // 声明为 vue 补充的东西 interface Vue { $http:AxiosInstance } } ` ### 8·使用vue-ele-form动态生成表单 - 创建编辑课程页面 CourseEdit.vue - 编辑课程分为创建和修改 - 两个不同的功能通过路由地址进行区分显示 - 子路由: // 编辑页面允许在路由后面加一个参数,允许接收参数prop为true {name:'courses-edit',path:'/courses/edit/:id',component:CourseEdit, props:true}, {name:'courses-create',path:'/courses/create',component:CourseEdit}, - 三元表达式的运用 `

{{(isNew) ?('创建'):('编辑')}}课程

` - isNew 是方法, get isNew{ return: !this.id}是把方法当成属性来用; - 动态生成表单:`https://www.npmjs.com/package/vue-ele-form` - 安装:admin>`npm i vue-ele-form` - 在 Main.ts中引用,注册 vue-ele-form - 因为 vue-ele-form不是 ts ,所以新建一个声明文件 packages.d.ts 去声明它 - courseEdit.vue ` ` ### 9.在同一页面创建和编辑课程 - CourseEdit.vue `// 提交方法 async submit(data){ // 创建课程和编辑课程 // 根据它有没有 id 来判断是编辑还是创建 ;没有带 id 就是创建 const url = this.isNew ? `courses`:`courses/${this.id}` const method = this.isNew ? `post` :`put` await this.$http[method](url,data) // 并提示保存成功 this.$message.success('保存成功') // 提交完成后清空掉 data this.data = {} // 返回上一页 this.$router.go(-1) } ` - CourseEdit.vue `created() { // this.fetch() // window.console.log(this.id) // 不是一个新纪录的时候执行 fetch() ! this.isNew && this.fetch(); } ` - CourseList.vue ` ` ### 10·带确认框的删除课程功能 - CourseList.vue - `删除 ` - ` // 删除方法 async remove(row){ // 这里将使用 confirm 询问是否删除。取消的时候会抛出一个异常,使用 try ... catch 去捕获处理 try{ await this.$confirm('是否确认删除?') }catch(e){ return } await this.$http.delete(`courses/${row._id}`) this.$message.success('删除成功') // 重新获取一次数据 this.fetch() } ` ### 11.使用Avue改造课程CRUD操作 - Avue安装:`npm i @smallwei/avue -s ` - plugins > avue.js - admin > main.ts 下类似引用 :`import './plugins/avue'` - CourseCrud.vue ` ` ### 12·配合Avue事件完成CRUD接口对接 - 创建接口,更新接口,删除接口 - CourseCrud.vue ` // 创建 async create(row,done,loading){ // 将新增的这一行的数据 通过 post 接口 在后台数据库创建 await this.$http.post('courses',row) // 创建完成弹出消息 this.$message.success('创建成功') // 重新加载数据 this.fetch() // done 表示完成,并关闭创建弹出页(必须要) done() } // 更新 async update(row,index,done,loading){ // 更新的时候 $index 会影响 更新 // 这里将 row 转成字符串,再删除 字符串中的 index const data = JSON.parse(JSON.stringify(row)) delete data.$index // 这时候更新的就是 data 里面的新数据 // 更新的接口请求 await this.$http.put(`courses/${row._id}`,data) // 创建完成弹出消息 this.$message.success('更新成功') // 重新加载数据 this.fetch() // done 表示完成,并关闭创建弹出页(必须要) done() } // 删除方法 async remove(row) { // 这里将使用 confirm 询问是否删除。取消的时候会抛出一个异常,使用 try ... catch 去捕获处理 try { await this.$confirm("是否确认删除?"); } catch (e) { return; } await this.$http.delete(`courses/${row._id}`); this.$message.success("删除成功"); // 重新获取一次数据 this.fetch(); } ` ### 13·使用Avue配合服务器端打造一个适合任意资源通用的CRUD组件 - 为了使扩展复用性更强,将数据挪到服务端去 - admin > ResourceCrud.vue 实现了通过 路由(path:'/:resource/list')和 服务端的(courses, episodes , users )中的 get(option) 来控制 前端课程和课时以及用户 列表内容展示,以及增删改的实现,达到了组件的复用; - router > index.ts :`{name:'courses-crud', path:'/:resource/list',component:ResourceCrud, props:true},` - ### 14·实现数据分页功能 - 全栈的时候有新的需求要先考虑数据怎么办,只有有了后台服务端的这些数据,前端才知道该怎么配合; - 分页的Avue的API:[https://avuejs.com/doc/crud/crud-page] - views>ResourceCrud.vue中 添加以下两个 :page="page" 是用于分页 @on-load="changePage"用于监听分页显示 - // 分页 page:any = { // pageSize:5, // pageSizes:[ 5 ,10 ,20], total:0, } // 查询显示 query:any={ // 限制分页线束 数据条数 limit:5, }; - // 监听分页 async changePage({pageSize,currentPage}){ // global.console.log(currentPage) // 设置当前页 this.query.page = currentPage; // 设置每页显示条数 this.query.limit = pageSize; // 执行完上面的后 再获取数据 this.fetch() } ### 15.实现字段点击排序功能 - query:any={ // sort排序 // -1为按id倒序排序 // sort:{_id:-1} } - 动态本地排序:用 Avue提供的方法, 服务端option中,需要排序的列后面加 sortable:true `{ prop: "name", label: "课程名称" ,sortable:true},` - 动态服务端排序: ` // 服务端排序 async changeSort({prop, order}){ // 查看里面有哪些元素 // global.console.log(params) // 首先进行判断,如果 order 为空值 ,则设置为空值 if(!order){ this.query.sort = null }else{ this.query.sort = { [prop]:order === 'ascending'?1:-1 } } // 重新加载 this.fetch() } ` ### 16·动态生成搜索表单+模糊查询 - 实现搜索功能 Avue>搜索 ,在option字段中加 search:true 并监听, 在avue-crud中添加 @search-change="search" - 模糊搜索 views > ResourceCrud.vue `async search(where,done){ // global.console.log(where) // 模糊匹配 where.name = {$regex:where.name}; this.query.where = where this.fetch() done() } - 区分需要模糊匹配还是精准匹配 - // 首先遍历 where 里面所有的数据 , 然后去字段列的定义里面找到同名的列;如果这一列有属性 regex 为true的则 进行正则表达式的模糊查询 // 即 后台 服务端 有 regex: true 才能进行 模糊匹配 - // 搜索 async search(where,done){ // global.console.log(where) for(let k in where){ const field = this.option.column.find(v => v.prop === k) ; if(field.regex){ where[k] = {$regex:where[k]}; } } // 模糊匹配 > 先遍历查询有没有 regex // where.name = {$regex:where.name}; this.query.where = where this.fetch() done() } ### 17·图片上传和展示 - 本地 - 1·option 》 column 中需要传上文件的那项加上 type:'upload',listType:'picture-img' -` { prop: "cover", label: "课程封面图" ,type:'upload',listType:'picture-img'},` - server >app.controller.ts 中定义文件上传接口 - `// 上传功能接口 @Post('upload') // 拦截器 @UseInterceptors(FileInterceptor('file')) async upload(@UploadedFile('file')file){ return file }` - 在server 》 app.module.ts 中添加 MulterModule 模块,apps同级生成一个uploads文件夹用于存放上传文件 - `MulterModule.register({ // 用于存放上传文件 dest:'uploads' }), ` - server >admin >main.ts 写上静态文件的托管 - `// 静态文件的托管 app.useStaticAssets('uploads',{ // 添加根路径前缀 prefix:'/uploads' })` - 设置文件图片的大小尺寸 course.controller.ts 中一个 width 属性 设置宽度 - 并且在 App.vue中给图片样式的高度设置为自动,统一创建页面和显示页面一致; ### 18·阿里云OSS文件上传 - 为了安全,云存储应该在服务端去做,防止反编译 - 注册使用 【阿里云】 - 对象存储oss : - 安装阿里云的包: - `cd server ` - `npm install --save multer-aliyun-oss` - 在server > app.module.ts中引用包: - `const MAO = require('multer-aliyun-oss');` - 将server 》 app.module.ts 》 MulterModule.regirter 中的本地存储的 dest:'uploads'换成 - storage:MAO({ config: { region: '', accessKeyId: '', accessKeySecret: '', bucket: '' } }) - accessKeyId: '', accessKeySecret: '', 这两项在 阿里云 》 个人账户 》AccessKey管理 - 上传到阿里云,不会占用自己的服务器空间和流量;现在将之前服务器存储图片的文件夹 server > uploads 删除. ### 19·完善课程和课时功能 - server > libs > models >episode.model.ts 完善课时功能 -`// 课时名称 @ApiProperty({description:'课时名称',example:'课时1'}) @prop() name:string // 视频文件的字段 @ApiProperty({description:'课时文件',example:'课时文件1'}) @prop() file:string // 每一个课时应该隶属于一个专栏 // 这里是指明他关联的 course 是什么 @prop({ref:'Course'}) course:Ref ` - 将课程和课时关联: server > admin > episodes.controller.ts -`title: "课时管理", // 解决 $course 问题 translate:false, column: [ // dicData:course 就是选择课时对应的 课程列表 { prop: "course", label: "所属课程",type:'select', dicData:course ,row:true }, { prop: "name", label: "课时名称" ,span:24}, // 上传视频文件 // 单文件上传 listType: 'picture-img', // 图片大小可以用 width属性 更改 { prop: "file", label: "视频文件" ,width:'120px',listType: 'picture-img',type:'upload',action:'/upload'}, ]` ### 20·使用 npm-check 更新项目依赖(swagger , crud ) - [https://www.cnblogs.com/stevexu/archive/2019/04/21/10744765.html] - 安装:npm i -g npm-check - 在项目根目录运行 - npm-check -u - 替换 window+shift+f - 设置快捷键 ### 21·使用@nestjs:config加载环境变量 - 建立一个被忽略的文件,变量从这个文件中去读取; - 安装:npm i --save @nestjs/config : 用于网站的配置 - 创建libs下nest 通用模块 common :nest -g lib common - 在common中可以写两个项目都会用到的模块,比如加载环境变量 - 加载环境变量: - server》libs》common》common.modules.ts - `imports:[ ConfigModule.forRoot({ // 全局任意位置可以使用 isGlobal:true }), // 数据库模块 DbModule, ], ` ### 22·配合环境变量异步注册模块 - server>apps>admin>app.module.ts 应用通用环境变量和.env 完成oss对象存储模块 - `imports: [ CommonModule, // 异步注册 加载 MulterModule.registerAsync({ useFactory(){ return{ storage: MAO({ config: { // oss的 地域节点 region: 'process.env.OSS_REGION', accessKeyId: 'process.env.OSS_ACCESS_KEY_ID', accessKeySecret: 'process.env.OSS_ACCESS_KEY_SECRET', // 存储空间名称 bucket: 'process.env.OSS_BUCKET' } }) } } }), ` - 2·使用 通用模块和 .env 完成端口的自适应选择 - `// 允许跨域 app.enableCors() // 使用swagger 写接口文档 const options = new DocumentBuilder() .setTitle('视频网站-后台管理API') .setDescription('共后台管理界面调用的服务端API') .setVersion('1.0') // .addTag('users') .build(); const document = SwaggerModule.createDocument(app , options) // 接口文档名 api-docs SwaggerModule.setup('api-docs',app,document); const PORT = process.env.ADMIN_PORT || 3002 await app.listen(PORT); console.log(`http://localhost:${PORT}/api-docs`) - 3·server>apps>server 与server>apps>admin的接口同理进行,将 OSS_ADMIN换成OSS_SERVER ### 23·Vue使用环境变量设置接口地址 - 由于后端的接口更改,客户端的部分也需要使用 Vue CLI 中的方法进行改变; - admin 下创建 .env 文件,在admin中不需要忽略 .env - `#如果不行就用3002 VUE_APP_API_URL=http://localhost:3009 ` - 解决报错: - 1·any: admin>tsconfig.json 添加:`"noImplicitAny": false,` ## 2-第二阶段 [前端界面-制作] ### 1·技术选型Nuxt、Vuetify与SEO - Nuxt : Nuxt.js 是一个基于 Vue.js 的轻量级应用框架,可用来创建服务端渲染 (SSR) 应用,也可充当静态站点引擎生成静态站点应用,具有优雅的代码结构分层和热加载等特性。 - SEO :(Search Engine Optimization)即搜索引擎优化。利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。目的是让其在行业内占据领先地位,收获品牌效益。 - Vuetify : Vuetify 是一个 Vue UI 库,包含手工制作的精美材料组件。 - Element UI 的SEO 效果非常不友好,可以适合做后台界面,如果做前端界面会很影响搜索效果; - 在网页源代码必须能够看到所有的文字,需要用到服务端渲染 - ### 2·使用Youtube模板搭建基础页面布局 - 使用 Nust 创建web 项目[https://zh.nuxtjs.org/guide/installation] - 安装:`npx create-nuxt-app <项目名>`(npx在 NPM版本5.2.0默认安装了) - 项目根目录下:`npx create-nuxt-app web`,键入项目名 D_video , 作者名 , 现在包管理 Npm , UI选择 Vuetify.js ,服务端框架 暂时选择不需要(没有 nest) , - nest 的原理就是 :将先渲染前端再通过Axios请求数据进行展示,变成了 先请求数据 ,再展示前端页面;将Axios和PWA、DotEnv都勾选上不用再注释, ESLint 、Prettier , 测试框架暂时不需要, 渲染模式使用 SSR服务端渲染 , jsconfig.json 勾选。 - 启动项目: - `cd ` - `npm run dev` - 使用Vuetify>预制布局》Google Youtube 替换 web>layouts 中的default.vue - 安装插件 prettier 使用这种格式化方式; - 安装图标:vuetify > install icon > install Material Icons 安装到项目中的 nuxt.config.js> head >link : - `link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css?family=Material+Icons', } ] ` - 路由处理: - 1.default.vue : - `items: [ { icon: 'home', text: '首页', link: '/' }, { icon: 'trending_up', text: '热门课程', link: '/courses' }, { icon: 'subscriptions', text: '热门评论', link: '/comments' } ], ` - ` ` - 新建课程列表路由:web>pages>course>index.vue ### 3·初始化课程和评论页面 ### 4·使用dotenv开发课程列表页面 - 使用数据渲染: - `import dotenv from 'dotenv'; dotenv.config(); ` - 安装@nuxtjs/dotenv:`npm i @nuxtjs/dotenv` - 配置接口根地址:web>.nuxt>axios.js配置数据请求接口根地址 localhost:3009 - ### 5·使用路由参数和计算属性开发课程详情页 - 定义详情页路由:` ` - web>courses下新建文件:_id.vue 这个文件表示路由跳转的页面,命名必须以下划线开头 - 在course.model中定义一门课程拥有的课时有哪些 ### 6·完成服务端接口 - server>server 创建courses模块`nest g mo courses` - server>src>server 创建courses控制器`nest g co courses` - `@Crud({ model: Course, // 前端接口是不需要创建、删除和修改接口的,需要自定义将他们关掉 routes:{ create:false, update:false, delete:false } }) @Controller("courses") @ApiTags("课程") export class CoursesController { constructor(@InjectModel(Course) private model) {} } ` - 在前端 .env将接口地址由3009 换成 server>server的3008 ### 7·基于Nestjs和passport策略的用户登录 - 1先做前端的登录:server>server - server>server>src 创建 auth模块,用于用户的登录注册:`nest g mo auth` - server>server>src 创建 auth控制器,用于用户的登录注册:`nest g co auth` - auth.controller.ts -` export class RegisterDto { @ApiProperty() username:string @ApiProperty() password:string } @Controller("auth") @ApiTags("用户") export class AuthController { // 注入用户模型 constructor( // 模型类 @InjectModel(User)private userModel:ReturnModelType ) {} // 注册用户接口 @Post("register") @ApiOperation({ summary: "注册" }) async register(@Body() dto: RegisterDto) { const { username , password } = dto; const user = await this.userModel.create({ // 此处有同名简写 username, password }) return user; } // 用户登录接口 @Post("login") @ApiOperation({ summary: "登录" }) async login(@Body() dto) { return dto; } // 查看用户信息 @Get("user") @ApiOperation({ summary: "获取个人信息" }) async user() { return {}; } } ` - 2散列用户密码 db>user.model.ts - 安装1:server: `npm i bcryptjs` - 安装2:提示文件:`npm i -D @types/bcryptjs` - 散列完密文保存进数据库 - 在user.model 中添加 `select:false,`使用户密码在常规查询时不被展示 - 在typegoose中需要get 和 set 一起使用,只定义 set 会报错; - - 3·用户登录 - node 包 passport 登录策略 - 本地策略: - 安装1:`npm i @nestjs/passport passport passport-local passport-jwt` - 安装2提示文件:`npm i -D @types/passport @types/passport-jwt @types/passport-local` - server>auth下创建 local.strategy.ts 文件 - auth.model.ts 注册 - `@Module({ imports:[PassportModule], controllers: [AuthController], providers:[LocalStrategy] } ` - 客户端需要的是一个 token ,需要使用 jwt 生成 - 安装3:`npm i @nestjs/jwt` - 全局注册这个包:common.model.js - auth.controller.ts - `// 用户登录接口 // 从用户返回的 用户名 和 密码进行校验,然后返回 token @Post("login") @ApiOperation({ summary: "登录" }) // Guard用于授权登录验证的 @UseGuards(AuthGuard("local")) async login(@Body() dto:LoginDto, @Req()req) { return { // 这里的req就是当前的用户 // token用于前端 token: this.jwtService.sign(String(req.user._id)) }; } ` - 此时已经生成了 token - 授权:server>main.ts:添加: `.addBearerAuth()` - 3.获取个人信息 jwt 策略 - jwt策略:server>auth下创建 jwt.strategy.ts 文件: - 取 token : ExtractJwt - @ApiBearerAuth() 出现报错 57:08 - 解决:这是@nestjs/swagger@4.2.0的bug,把包升级就好。 - npm i @nestjs/swagger - 获取原理就是,需要用户登录,将成功登陆后返回的token , 用于验证获取用户信息的接口,如果 token 值正确 则可成功显示用户信息;如果没有 token 或者token 值不正确,则报错 401 ; - 自定义装饰器: - auth 下新建 current-user.decorator.ts ### 8·基于nustjs/auth模块实现的Nuxt登录 - 写用户的前端登录: - 登录表单:Vuetify > 底部表单 - auth 用于做前端登录 - 安装 auth.nuxtjs.org - cd web - npm install @nuxtjs/auth @nuxtjs/axios - store 创建 index.js文件 - 在登录的旁边,如果登录则显示用户的个人信息 - v-if="$store.state.auth.user"用户判断有没有用户信息,有用户信息则会显示用户名。 - 使用 v-if 和 v-else 在default中的登录出进行判断,如果用户没有登录则显示 登录 , 如果用户登录了则显示用户名。 - isShowLoginForm: false, 登录后不默认弹出登录框(default.vue) ### 9.收藏功能多对多建模-数组字段 - 将用户收藏的课程收藏进用户模型的一个字段中 - 存储收藏课程数据 - 查收藏数据 - 取消收藏 - 但是当数量多了之后不行 ### 10·收藏功能多对多建模-中间模型 - 关系型数据库,不推荐用数组存放这种可增长数据 - 新建一个 likes 模型,对应数据库有一个 likes 集合,它会存放我们的数据,当我们点击了收藏之后,把当前的用户user 和当前的课程course 存到like 里面就可以了; - 查询:通过用户id和课程id判断当前用户有没有收藏,如果有则展示 - 取消:把用户id和课程id传到服务器上来,服务器去查一下 likes 表里面有没有 这条数据 ,如果有则删除掉。 - likes(中间表) user course createdAt comment 1 1 2019.1.1 666! 2 1 2019.2.1 666! ## 阿里云 ### 1·linux - ll :查看有哪些文件及目录 - pwd:查看当前在哪个目录 - cd : 切换目录 - `ls -all` 查看当前文件夹有哪些文件 - 蓝色代表文件夹,白色代表文件 - `cd ~`:进入个人文件夹 ### 2·git-bash终端 - 登陆:`$ ssh root@47.115.54.58` - @为分割线,分割用户名和ip - 注意:密码不回显!!!!!! - ### 3·域名解析 - 复制服务器公网ip: `47.115.54.58` - 找到要解析的域名,添加记录 - 域名解析后,通过gitbash登陆: - `ssh root@video.dbc35.top` - 即此时域名等于ip ### 4.Nginx安装和配置 - Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/ POP3/SMTP服务。 - 其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表 现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。 - - 安装(在已经登录服务器下) - 使用 apt 安装软件 - 更新apt:`apt update` - 查看Nginx:`apt show nginx` - 安装nginx:`apt install nginx -y` - 安装完成之后这个域名在浏览器既可以在浏览器打开 nginx 默认页面。 ### 5.MongoDB数据库的安装和配置 - 查看:`apt show mongodb-server` - 安装:`apt install -y mongodb-server` - 键入`mongo`进入数据库 - 查看数据库`show dbs` - 退出数据库:`exit` ### 6.git安装 、 配置ssh-key - 安装git:`apt install -y git` - 生成公钥key:`ssh-keygen`,然后一路回车 - 查看公钥:`cat + 公钥路径`;`cat /root/.ssh/id_rsa.pub` - 复制公钥使用 ### 7.Nodejs安装、配置淘宝镜像 - 安装nodejs:`apt install -y nodejs` - 查看版本:`node -v` :v8.10.0 - 安装npm:`apt install -y npm` - 查看npm:`npm -v` - 配置淘宝镜像:`npm config set registry https://registry.npm.taobao.org` - 安装nrm(用于快速切换NPM镜像):`npm i -g nrm` - 查看当前镜像:`nrm current` - 切换至npm:`nrm use npm` - 切换至taobao:`nrm use taobao` - 升级node的包:`npm i -g n` - 升级至node最新:`n latest` - 退出重新登录服务器查看:`node -v`:v13.11.0 ### 8.拉取代码,安装pm2并启动项目 - 1、将本地代码上传到git平台上:码云(gitee.com) - 2、生成公钥:`ssh-keygen` 查看公钥:`cat ~/.ssh/id_rsa.pub` - 3、在码云上往服务器上拉取代码: - 将服务器上的公钥添加到码云上的部署公钥(权限问题) - 服务器上: - cd / - cd /var/www/ - cd html - mkdir /data - cd data - git clone +码云地址(git clone git@gitee.com:dbc35/Dvideo.git) - cd Dvideo - cd server - 装包:`npm i` - 安装pm2(可以在后台运行项目):`npm i -g pm2` - 启动项目:`pm2 start index.js` ### 9.配置Nginx的反向代理 - 1.vscode安装插件:Romote-SSH - /etc/nginx/ - sites-enabled表示已经启用的站点 - 2.在线自动生成NGINX配置文件网站:`(nginxconfig.io)` - 3.服务器重载:`service nginx reload`