微博用户设置

创建页面

回顾技术方案

设置

查看模板代码

  • src-views-setting.ejs:ejs模板
  • 使用的是bootstrap的模板

开发页面路由

  1. 创建渲染“设置页”的路由:src-routes-view-user.js中,注意需要先使用“登录验证中间件”,如果用户未登录则带着当前url(/setting)跳转到登录页,登录后自动跳转回“设置页”:routes-view-user.js

开发接口

图片上传(文件上传)

回顾技术方案

整体架构设计

formidable-upload-koa工具(文件上传)

  • koa要图片(文件)上传就要借助formidable-upload-koa工具
  • 安装npm i formidable-upload-koa
  • 使用使用
    • 由于该中间件会将图片(文件)保存在本机或服务器的一个临时文件夹中,所以我们需要fse工具将其改成存储在我们指定的文件夹
    • options:配置,不写则使用默认配置
      • uploadDir:图片保存目录
      • keepExtensions:是否保留文件扩展名

fs-extra工具(文件操作)

  • 涉及文件操作就要使用fs-extra工具
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const fse = require('fs-extra')

    //删除filePath路径的文件
    await fse.remove(filePath)
    //将filePath路径的文件移动到distFilePath路径
    await fse.move(filePath, distFilePath)
    //判断文件夹是否存在,DIST_FOLDER_PATH为文件夹路径
    fse.pathExists(DIST_FOLDER_PATH)
    //新建文件夹,在DIST_FOLDER_PATH路径下新建文件夹
    fse.ensureDir(DIST_FOLDER_PATH)

步骤

  1. 安装formidable-upload-koa工具、fs-extra工具:npm i formidable-upload-koa fs-extra --save
  2. 【路由层】创建上传图片的路由,使用formidable-upload-koa工具创建中间件将图片文件上传到服务器/本机的某个临时文件夹中:在前端页面中,用户通过调用/api/utils/upload上传图片,所以在src-routes-api下新建utils.jsutils.js
    1. 修改个人头像和上传微博时都需要上传图片,所以将上传图片的路由抽离到utils.js中,方便复用
    2. 引入formidable-upload-koa工具的koaForm函数创建中间件
    3. 前端上传文件的ajax方法(my-ajax.js)中文件保存在FormData對象的file值中my-ajax.js这个file就对应后端的src-routes-api-utils.js中ctx.req.files['file']的file,要修改的话两边要一起改。FormData 对象的使用FormData使用方法详解
  3. 【controller层】限定文件大小、移动文件存储的位置:在路由层使用formidable-upload-koa工具的中间件时就已经将文件上传至某个临时文件夹,所以现在我们可以将文件移动到我们指定的位置。controller下新建util.js
    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
    /**
    * @description utils controller
    * @author hlz
    */

    const path = require('path')
    const { ErrorModel, SuccessModel } = require('../model/ResModel')
    const { uploadFileSizeFailInfo } = require('../model/ErrorInfo')
    const fse = require('fs-extra')

    // 存储目录
    const DIST_FOLDER_PATH = path.join(__dirname, '..', '..', 'uploadFiles')
    // 文件最大体积 1M
    const MIX_SIZE = 1024 * 1024 * 1024

    // 是否需要创建目录
    fse.pathExists(DIST_FOLDER_PATH).then(exist => {
    if (!exist) {
    fse.ensureDir(DIST_FOLDER_PATH)
    }
    })

    /**
    * 保存文件
    * @param {string} name 文件名
    * @param {string} type 文件类型
    * @param {number} size 文件体积大小
    * @param {string} filePath 文件路径
    */
    async function saveFile({ name, type, size, filePath }) {
    // 文件过大时
    if (size > MIX_SIZE) {
    // 使用fs-extra工具删除文件(以防占用硬盘空间)
    await fse.remove(filePath)
    return new ErrorModel(uploadFileSizeFailInfo)
    }

    // 移动文件(从filePath到distFilePath)
    const fileName = Date.now() + '.' + name // 防止重名
    const distFilePath = path.join(DIST_FOLDER_PATH, fileName) // 目的地
    await fse.move(filePath, distFilePath)

    // 返回信息
    return new SuccessModel({
    url: '/' + fileName
    })
    }

    module.exports = {
    saveFile
    }
    为啥distFilePath中包含文件名: 查看通过formidable-upload-koa工具保存的文件路径可看到是包括到随机生成的文件名的upload _xxx),这个路径是直接可以访问到图片的路径,所以移动的目的路径中也要包含文件名查看打印出来的path
  4. 新建uploadFiles文件夹并先保存一张图片2.png
  5. 【保证controller-util.js中saveFile返回的url可被访问到】:将uploadFiles文件夹设置为静态目录的文件夹=》什么东西放里面都可被访问=》保证controller-util.js中saveFile返回的url可被访问到。app.js中进行设置:app.js设置后,我们可通过访问http://localhost:3000/2.png访问到uploadFiles文件夹下的图片2.png
  6. 【app.js注册路由】app.js
  7. 测试:http://localhost:3000/setting![测试](https://i0.wp.com/ww1.sinaimg.cn/large/005H7IVsgy1gdx1b9n6tzj31050i2jtk.jpg)
  8. 后端筛选文件格式:controller-util.js:controller-util.js
  9. 测试:尝试上传css后缀的文件:测试
  10. 前端筛选文件格式register.ejsaccept 属性只能与 <input type="file"> 配合使用,它规定能够通过文件上传进行提交的文件类型。**image/*表示接受所有的图像文件。**
  11. 前端限定后再选择文件时直接就不给选择css后缀的文件了。

补充:线上图片存储

  • 我们现在是把图片存储在本地的uploadFiles文件夹中,但实际上线时应使用专业的文件服务(比如七牛云等)来保存图片文件,它再返回图片url供程序使用线上图片存储

修改基本信息

  1. 【路由层】创建路由,传递前端数据,调用controller层函数:前端setting.ejs中修改基本信息的路由是**/api/user/changeInfo,传递的前端数据是nickName,city,picture,所以在routes-api-user.js中创建changeInfo路由,将前端获取的数据传递并调用controller层的changeInfo函数**:routes-api-user.js(新建用post,修改用patch)
  2. 【controller层】创建changeInfo函数,调用service层函数更新数据库数据,修改session.userInfo:src-controller-user.js:controller-user.js
  3. 【service层】创建更新数据库中users表(User模型)的方法:src-service-user.js:service-user.js
    • updateData和whereData的属性名需要和de-model-User.js中User模型的属性名对应
  4. 测试测试数据库的users表数据库的users表此时无论怎么刷新页面,都会显示已修改的信息:刷新页面

修改密码

  1. 【路由层】创建路由,传递前端数据,调用controller层函数:前端setting.ejs中修改密码的路由是**/api/user/changePassword,传递的前端数据是password、newPassword,所以在routes-api-user.js中创建changePassword路由,将前端获取的数据传递并调用controller层的changePassword函数**:routes-api-user.js
  2. 【controller层】创建changePassword函数,调用service层函数更新数据库数据,修改session.userInfo:src-controller-user.js:src-controller-user.js
  3. 【service层】还是和修改个人信息一样的方法来更新数据库中users表(User模型)的方法
  4. 测试:测试查看数据库

退出登录

  1. 【路由层】创建路由,调用controller层函数:前端setting.ejs中退出登录的路由是**/api/user/logout,所以在routes-api-user.js中创建logout路由,调用controller层的logout函数**:routes-api-user.js
  2. 【controller层】创建logout函数,删除session.userInfo:src-controller-user.js中,我们判断登录状态时使用的是session.userInfo,删除它自然就退出登录了:src-controller-user.js
    • delete关键词可用于删除ctx.session
  3. 测试:测试1测试2
,