IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> node.js学习 | |七天学了个node.js+vue小项目 -> 正文阅读

[JavaScript知识库]node.js学习 | |七天学了个node.js+vue小项目

大家好,历时大概一个星期,终于把黑马程序员老师的大事件后端接口和登录注册页面写好了👉 视频地址,视频很长,前端并没有做完,现只做了注册页和登录页面,希望多多支持!

  • 前端:
    • vue
    • vuex
    • vue-router
    • vuex-persisedstate
  • 后端
    • node.js
    • express
    • express-jwt
    • express-joi
    • body-parser
    • jsonwebtoken
    • cors
    • mysql

后端接口

在这里插入图片描述
在这里插入图片描述

具体后端接口详情请看我的gitee地址👉 https://gitee.com/chuang-bai/api-serve

代码思路

结构代码

把每一个部分分成一个模块,维护时不会很麻烦。

在这里插入图片描述

  • router/user.js中定义登录和注册的路由
// 创建路由
const express = require('express')
const router = express.Router()

// 导入验证数据的中间件
const expressJoi = require('@escook/express-joi')

// 导入需要的验证规则对象
const {reg_login_schema}  = require('../schema/user')

// 导入用户路由处理函数
const routerHandler = require('../router_handler/user.js')

// 注册新用户
router.post('/reguser',expressJoi(reg_login_schema), routerHandler.regUser)


// 登录
router.post('/login',expressJoi(reg_login_schema),routerHandler.login)


// 共享
module.exports = router

在以上代码中expressJoi( )是一个用于验证前端传回来的信息
schema/user.js

//  导入定义验证的包
const joi = require('joi')

// 定义规则
/**
 * string() 字符串
 * alphanum() a-z A-Z 0-9
 * min()  最少
 * max()  最多
 * required()  必需的
 * pattern()   匹配正则表达式
 */
const username = joi.string().alphanum().min(1).max(10).required()
const password = joi.string().pattern(/^[\S]{6,12}$/).required()
// 验证登录规则对象
exports.reg_login_schema = {
    body:{
        username,
        password
    }
    // params
    // query
}
  • router_handler/user.js写路由对应的方法
// 导入mysql模块
const db = require('../db/index.js')

// 导入加密密码模块 bcryptjs
const bcrypt = require('bcryptjs')

// 导入生成token的包
const jwt = require('jsonwebtoken')
const config = require('../config')

// 注册用户的函数
exports.regUser = (req,res)=>{
    // 获取用户提交信息
    const userInfo = req.body
    // 校验用户信息
    // 不合法信息
    // if(!userInfo.username || !userInfo.password){
    //     // return res.send({
    //     //     status:1,
    //     //     message:'用户名或密码不合法!'
    //     // })
    //     return res.cc('用户名或密码不合法!')
    // }
    // 合法
    const sqlStr = 'select * from ev_users where username = ?'
    // 查询数据库内容
    db.query(sqlStr,[userInfo.username],(err,results)=>{
        // 失败
        // if(err) return res.send({status:1,message:err.message});
        if(err) return res.cc(err)
        // 成功
        // 用户名已存在
        if(results.length > 0){
            // return res.send({status:1,message:'用户名已存在'})
            return res.cc('用户名已存在')
        }
        // 用户名不存在
        // 先对密码进行加密 bcrypt.js
        // hashSync(需要加密的内容,随机数 一般为10)
        userInfo.password = bcrypt.hashSync(userInfo.password,10)
        // 插入用户
        const sql = 'insert into ev_users set ?'
        // {username:userInfo.username,password:userInfo.password} 只希望插入username和password 
        // 可能userInfo中还有其他属性
        db.query(sql,{username:userInfo.username,password:userInfo.password},(err,results)=>{
            // 失败
            // if(err) return res.send({status:1,message:err.message})
            if(err) return res.cc(err)
            // 成功
            if(results.affectedRows !== 1){
                // return res.send({status:1,message:'注册失败,请稍后再试'})
                return res.cc('注册失败,请稍后再试')
            }
            // res.send({status:0,message:'注册成功'})
            res.cc('注册成功',0)
        })
    })
}

// 登录的函数
exports.login = (req,res)=>{
    // 获取用户提交的数据
    const userInfo = req.body

    // 定义SQL语句
    const sql = 'select * from ev_users where username = ?'
    db.query(sql,[userInfo.username],(err,results)=>{
        // 错误
        if(err) return res.cc(err)
        // 数据库中没有数据或其他
        if(results.length !== 1) return res.cc('登录失败!')
        // 判断密码
        /**
         *  bcrypt.compareSync(用户提交的密码,数据库中的密码)
         *  返回值(true 一致,false 不一致)
         */
        const compareResult = bcrypt.compareSync(userInfo.password,results[0].password)
        // 密码错误
        if(!compareResult) return res.cc('密码错误')
        // 生成token
        /**
         * 在生成token字符串时, 一定要剔除 密码 和 头像 的值
         * const user = {...results[0],password:'',user_pic:''}
         * 后面定义的会覆盖掉前面的
         */
        const user = {...results[0],password:'',user_pic:''}
        // 加密生成token
        const tokenStr = jwt.sign(user,config.jwtSecretKey,{expiresIn:config.expiresIn})
        // 响应给客户端
        res.send({
            status:0,
            message:'登录成功',
            token:'Bearer ' + tokenStr
        })
    })
}

在处理函数中首先导入需要的包,然后需要先获取前端传过来的参数,经过expressJoi()校验以后,定义相应的sql语句,利用db.query去执行,获取响应结果res,这时有几种情况

  1. 查询出错误
  2. 用户名已存在
  3. 成功👇
  • 先对密码进行加密处理
  • 利用sql语句插入数据库中
  • 失败情况下返回错误信息

登录的情况和注册差不多,主要的是在登录成功以后,需要将重要信息置为 ’ ',例如密码头像,然后加密生成token,在token的基础上加上bearer 空格 并返回给客户端

前端页面

在这里插入图片描述
在这里插入图片描述

和b站老师写的有出处,主要是需要按自己的情况而定👦。

初始化vue项目以后,将初始模板删除例如helloWorld.vue,下面是结构

在这里插入图片描述
前端详情页面代码地址👉https://gitee.com/chuang-bai/hm-toutou

1. 封装axios

util/request.js

import axios from 'axios'

// myAxios请求时 地址baseUrl+url 请求后台 
const myAxios = axios.create({
    baseURL:'http://127.0.0.1:3000'
})

export default myAxios

2. 编写api接口

api/index.js

// 封装具体接口请求方法
// 每个方法值负责请求一个url地址
import request from '@/utils/request'

// 还需要导出接口方法,为了在逻辑页面调用
export const registerAPI = ({username,password})=>{
    // 原地是一个promise对象(内部包含了原生ajax请求)
    // return这个promise对象去逻辑页面 去那里处理结果 
    return request({
        url :'/api/reguser',
        method:'POST',
        // params的对象参数名和值,axios会把参数拼接在url?后面发给后端
        // data的对象名和值,axios会把参数拼接到请求体内
        data:{
            username,
            password
        }
    })
}

/**
 * 登录接口
 * @param {*} {username:用户名,password:密码}
 * @return Promise对象
 */
export const loginAPI = ({username,password})=>{
	return request({
		url:'/api/login',
		method:'POST',
		data:{
			username,
			password
		}
	})
}

3. 编写页面代码

view/login/index.vue

<template>
  <div class="login-container">
		<div class="login-box">
			<div class="title-box"></div>
			<!-- 登录的表单验证 -->
			<el-form :model="loginForm" :rules="loginRules" status-icon ref="loginRef">
				<!-- 用户名 -->
				<el-form-item prop="username">
					<el-input type="text" v-model="loginForm.username"  placeholder="请输入用户名"></el-input>
				</el-form-item>
				<!-- 密码 -->
				<el-form-item prop="password">
					<el-input type="password" v-model="loginForm.password"  placeholder="请输入密码" minlength="6"></el-input>
				</el-form-item>
				<el-form-item>
					<el-button type="primary" class="btn-login" @click="loginFn">登录</el-button>
					<el-link type="info" @click="$router.push('/reg')">去注册</el-link>
				</el-form-item>
			</el-form>	
		</div>
	</div>
</template>

<script>
import { loginAPI } from '@/api'
import {mapMutations} from 'vuex'
export default {
    name:'my-login',
	data(){
		return {
			loginForm:{
				username:'',
				password:''
			},
			loginRules:{
				username:[{required:true,message:'请输入用户名',trigger:'blur'},{min:1,max:10,message:'用户名在1~10个字符串之间',trigger:'blur'}],
				password:[{required:true,message:'请输入密码',trigger:'blur'},{min:6,max:15,message:'密码在6~15字符之间',trigger:'blur'}]
			}
		}
	},
	methods:{
		...mapMutations(['updateToken']),
		loginFn(){
			this.$refs.loginRef.validate(async valid=>{
				if(valid){
					// 通过校验
					const {data:res} = await loginAPI(this.loginForm)
					if(res.status !== 0) return this.$message.error(res.message)
					// 成功
					this.$message.success(res.message)
					this.updateToken(res.token)
				}else{
					return false
				}
			})
		}
	}
}
</script>

<style lang="less" scoped>
.login-container{
	background: url('../../assets/images/login_bg.jpg') center;
	background-size: cover;
	height: 100%;
	.login-box{
		width: 400px;
		height: 290px;
		background-color: #fff;
		box-sizing: border-box;
		border-radius: 3px;
		padding: 0 30px;
		position: absolute;
		left: 50%;
		top: 50%;
		transform: translate(-50%,-50%);
	}
	.title-box{
		background: url('../../assets/images/login_title.png') no-repeat center;
		height: 60px;
	}
	.btn-login{
		width: 100%;
	}
}
</style>

*当写好登录页面以后,发送请求,后端会发送token,如果想要持久化保存,就需要vuex-perstsedstate*插件。

4. 持久化token

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import  createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
	token:'' // 保存token字符串
  },
  getters: {
  },
  mutations: {
	updateToken(state,val){
		state.token = val	
	}
  },
  actions: {
  },
  modules: {
  },
  plugins:[
	  createPersistedState() // 注入持久化插件
  ]
})


// vuex默认是保存在内存中的,所以刷新所有的值会回归初始化(无法做到持久存储)
// vuex插件包 vuex-persistedstate 用于持久化存储vuex

由于学的太多,这几天,一篇写不完,内容有限,具体信息请看gitee主页??🔥

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 12:24:08  更:2022-10-17 12:24:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 19:24:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码