node+layui红叶博客项目

简介

node作为新兴的技术(对比java)其有许多还需要完善的地方,虽然定位为快速开发服务端,但是Java也有springboot框架可以实现,快速开发,其次定位为处理高并发,这个作为轻量级服务端还是有一定作用的。其扩展性较高,使得许多大厂也使用.项目源码https://github.com/yp1919597583/node-

环境配置

要想使用node开发就得先配置相应的环境,首先根据自己电脑在官网Node.js下载对应的版本,这里笔者使用的是64位,下载完成后安装

第一步:

第二步:

项目结构:

 数据库表创建

1.创建node_js数据库

 2.创建user表如图

 3.建立博客表如图

 

接口开发

创建数据库配置文件

//导入mysql
const mysql=require("mysql");
const db=mysql.createPool({
    host:"127.0.0.1",
    user:"root",
    password:"yp18783819559",
    database:"nodejs"
})



//向外界暴露db,供使用
module.exports=db;

配置全局路由

const express=require("express");
const app=express();
const joi=require("joi");

//静态资源托管,让用户可以访问服务器资源

app.use(express.static('page'))
app.use(express.static('layui'))
app.use(express.static('img'))
app.use(express.static('js_tool'))
//导入cors对象
    const cors= require("cors");
    app.use(cors());

    //配置解析表单数据的中间件
    app.use(express.urlencoded({extended:false}))//只能解析x-www-form-url编码的格式\
    
    //封装cc函数
    app.use((req,res,next)=>{
       
        res.cc=function(err,status=1){
            //status 默认为1失败
            //err的值可能是错误对象,也可能是错误信息字符串
            res.send({
                status,
                message: err instanceof Error ? err.message:err
            })
        }
        next();
    })


    //配置解析token的中间件(一定要在路由之前配置)
    const expressJwt= require("express-jwt");
    const config=require("./config");
    app.use(expressJwt({secret:config.jwtScrectKey}).unless({path:[/^\/api/]}))//配置全局中间件解密token并排除以/api开头的路由,不需要身份验证


 
 

//导入并使用用户路由
    const userRouter= require("./router/user")
    app.use('/api',userRouter)//今后访问/user时都必须在访问前加上/api
//导入并使用博客路由
    const articRouter=require('./router/boke')
    app.use('/myArtic',articRouter)
//导入并使用用户信息的模块
    const userInfoRouter=require("./router/userinfo");
    app.use('/my',userInfoRouter);//挂载到全局并加上/my前缀

//在路由之后定义错误级别的中间件(错误中间件必须写next)
    app.use((err,req,res,next)=>{
        if(err instanceof joi.ValidationError){
            //验证失败的错误
            res.cc(err);
        }
        //token验证失败
        if(err.name==="UnauthorizedError"){
            return res.cc("身份认证失败!");
        }
        //未知错误
    res.cc(err);//貌似现在可以不用  return 嘿嘿! 笔者未报错
    })
    app.listen(8080,function(){
        console.log("api 服务器启动 http://localhost:8080");
    })

创建登录注册接口

1.创建schem验证规则

//导入定义验证规则的包
const joi= require("joi");


//定义用户名,密码,邮箱的验证规则(注意:此处定义的变量名必须与参数上的一致)

const userName=joi.string().min(1).max(12).required()//.alphanum()限制必须是字母与数字

const password=joi.string().alphanum().pattern(/^[\S]{6,12}$/).required()//定义正则表达式

const email=joi.string().email();



//定义,id nickname,email 验证规则

const id=joi.number().integer().min(1).required();
const nickName=joi.string().required();


//定义验证头像的验证规则


const avatar=joi.string().dataUri().required();//dataUri() 表示必须是base64的字符串



//向外暴露一个用来验证的规则

//定义验证注册和登录表单验证的规则
exports.reg_login_schems={
    body:{
        userName,
        password,
        email
    },

}


//更新用户信息验证

exports.update_userinfo_schema={
    //需要对req.body的数据验证
    body:{
        id:id,
        nickName:nickName,
        email:email
    }
}

//更新密码验证

exports.update_password_schema={
    body:{
        oldPwd:password,
        newPwd:joi.not(joi.ref('oldPwd')).concat(password) 

        /*
        
        1.joi.ref('oldPwd')表示 新密码与旧密码一致
        2.joi.not(joi.ref('oldPwd'))表示 新密码与旧密码不一致
        3.concat(password) 表示合并password验证规则
        
        
        */
    }

}

//向外共享,验证头像的规则

exports.update_avatar_schema={
    //验证body中数据的合法性
    body:{
        avatar,//参数名,与验证规则名重名可省略
    }

}

2.创建全局token加密解密秘钥(对称加密)

module.exports={
    //加密,解密token的秘钥
    jwtScrectKey:'yangpengkl',
    expiresIn:'10h'//指定token有效期

}

 3.创建user登录/注册路由

const express=require("express");
const router=express.Router();
//导入用户路由处理函数
const userHandel= require("../router_handler/user");
//1.导入用户验证的中间件

const express_jio=require("@escook/express-joi");

//2.导入需要的验证规则对象
const {reg_login_schems}=require("../schems/user")//得到对象中的一个属性 {reg_login_schems}

//注册
router.post("/reguser",express_jio(reg_login_schems),userHandel.regUser)//相当于类
//登录
router.post("/login",express_jio(reg_login_schems),userHandel.login)//验证通过之后才会继续调用userHandel.login
//获取用户名,头像,作品,用于展示
// router.get("/get_other_info",userHandel.getSomeInfo)
module.exports=router

4.创建登录/注册路由处理函数

//处理user请求

//导入数据库操作模块
  const db=require("../db/index")
//导入加密密码模块
  const bcryptjs=require("bcryptjs");
const { off } = require("../db/index");

//导入生成token的包
    const jwt=require("jsonwebtoken");

//导入秘钥
   const config=require("../config");

//导入文件回传模块

    const fs=require("fs");
const { url } = require("inspector");
const router = require("../router/user");





//注册新用户的处理函数
exports.regUser=(req,res)=>{
    //获取用户提交信息
    const userinfo=req.body
    
    //检验表单有无空数据
    // if(!userinfo.userName || !userinfo.password){
    //         return res.send({
    //             status:1,
    //             message:"注册失败用户名或密码为空"
    //         })
    // }

    
    //1.定义sql语句查询,查询用户名或邮箱是否存在
    const sql="select * from ev_user where username=?"
     //检查邮箱是否已经存在
        const sql_byEmail="select * from ev_user where email=?"
    db.query(sql,userinfo.userName,function(err,results){
        // if(err){
        //     return res.send({status:1,message:err.message})//执行sql失败
        // }

        //执行成功,判断用户名是否被占用
        if(results.length>0){
           
            return res.send({status:1,message:"用户名已存在!"});

        }else if(results.length <=0){

            db.query(sql_byEmail,userinfo.email,(err2,result2)=>{
                // if(err2){
                    
                //     return res.send({status:1,message:err2.message})
                // }
    
                if(result2.length>0){
                    return res.send({status:1,message:"邮箱已被使用!"});
    
                }




                   //用户名邮箱都可以使用
        //1.对密码加密,再存入数据库(使用bcryptjs包)先安装 npm i bcryptjs@2.4.3
        //2.调用bcryptjs.hashSync() 加密
        userinfo.password= bcryptjs.hashSync(userinfo.password,10)
        // console.log(userinfo.password);//(明文密码,随机盐长度)
         //插入新用户
         const sql_into="insert into ev_user set?";
         db.query(sql_into,{username:userinfo.userName,passwor:userinfo.password,email:userinfo.email},(err,result)=>{
             if(err){
                 return res.send({status:1,message:err.message})
             }
             //判断影响行数是否为一,不为一则失败
             if(result.affectedRows !=1){
                 return res.send({status:1,message:"注册用户失败,稍后再试"});
 
             }
             res.send({status:0,message:"注册成功!"})
 
         });




            })

        }

        
     
        
      
    })



    
}


//登录的处理函数
exports.login=(req,res)=>{
    //接收表单数据
    const userinfo=req.body;
    //1.定义sql
    const sql="select * from ev_user where username=?"
    //2.执行sql
    db.query(sql,userinfo.userName,(err,result)=>{
        //执行失败
        if(err){
            return res.cc(err);
        }
        //没查到用户数据
        if(result.length !==1){
            return res.cc("登录失败,没有此用户!");
        }
        //判断密码是否正确,调用bcryptjs.compareSync()
        const comperResult= bcryptjs.compareSync(userinfo.password,result[0].passwor);
        if(!comperResult){
            return res.cc("登录失败,密码错误");
        }

        //在服务端生成token字符串(生成token时要剔除敏感信息,比如密码等)
        //利用es6的高级语法(展开运算符)清空  const user={...result[0],password:'',user_pic:''}
        const user={...result[0],passwor:'',email:'',user_pic:''};
        //加密用户信息生成token
        const tokenStr=jwt.sign(user,config.jwtScrectKey,{expiresIn:config.expiresIn});
       // console.log(tokenStr);
        //将token响应客户端  
        res.send({
            status:0,
            message:"登陆成功",
            token:'Bearer '+tokenStr,//加上前缀方便客户端使用(前缀是固定写法)
           
        });
       
     

    })

    
}


创建用户信息操作接口

1.创建获取信息,更改信息路由

const express= require("express");

 const router= express.Router();

 //导入验证数据的中间件

 const expressjoi=require("@escook/express-joi");

 //导入验证更新用户信息的规则

 const {update_userinfo_schema,update_password_schema,update_avatar_schema}=require("../schems/user");



 //挂载路由

//导入路由处理函数模块
    const uerinfo_handle=require("../router_handler/userinfo");
//获取用户信息路由
    router.get('/userinfo',uerinfo_handle.getUserinfo);

//更新用户数据路由

    router.post('/userinfo',expressjoi(update_userinfo_schema),uerinfo_handle.updateUserInfo);

//更新密码的路由
    
    router.post('/updatapwd',expressjoi(update_password_schema),uerinfo_handle.update_password);

//更换头像的路由

    router.post('/update/avatar',expressjoi(update_avatar_schema),uerinfo_handle.updateAvatar);

 module.exports=router;

2.创建操作用户信息路由处理函数

//导入大数据库操作模块
const db=require("../db/index");

//导入比较加密密码的模块

const bcryptjs= require("bcryptjs");

//获取用户信息的路由模块,处理函数
exports.getUserinfo=(req,res)=>{

//定义sql
const sql="select id,username,nickName,email,user_pic from ev_user where id=?"
//调用db.qurey()查询
db.query(sql,req.user.id,(err,result)=>{
    if(err){

        //执行sql失败

        return res.cc(err);
    }
    //执行sql成功,但是查询结果不唯一
    if(result.length !=1){
        return res.cc("获取用户信息失败!");
    }
    //用户信息获取成功!
   
    res.send({
        status:0,
        message:"获取用户信息成功!",
        data:result[0]   // 用户信息
    })
});



   
}

//更新用户基本信息

exports.updateUserInfo=(req,res)=>{
    //定义sql语句
    const sql_update="update ev_user set ? where id=?"
    //调用db.query()执行
    db.query(sql_update,[req.body,req.body.id],(err,result)=>{

        //执行sql失败
        if(err){
            return res.cc(err);
        }
        //执行成功但是影响行数不唯一
        if(result.affectedRows !=1){
            return res.cc("修改信息失败!")

        }
        res.send({
            status:0,
            message:"更新成功!"})
    })

  

}

//更新密码
    exports.update_password=(req,res)=>{
       
      
        //定义sql语句
        const sql_update_password_select="select * from ev_user where id=?"
        //执行sql
        db.query(sql_update_password_select,req.user.id,(err,result)=>{
        //sql执行失败
            if(err){
                return res.cc(err);
            }
        //执行sql成功,但是影响行数不唯一
            if(result.length !=1){
                return res.cc("修改密码失败,用户不存在!");
            }

        //判断旧密码是否正确
             
        let compareResult=bcryptjs.compareSync(req.body.oldPwd,result[0].passwor);//不能直接用==判断(加密了)
      
        if(compareResult==false){
               
         return   res.cc("旧密码输入错误!");

        }
        
        //将密码加密后更新到数据库

        const sql_update_password_update="update ev_user set passwor=? where id=?"

        //对新密码加密

        const newPwd=bcryptjs.hashSync(req.body.newPwd,10);
        db.query(sql_update_password_update,[newPwd,req.user.id],(err,result)=>{

            //sql执行失败

            if(err){
             return   res.cc(err);
            }
            //执行sql成功但是影响行数不为一
            if(result.affectedRows !=1){
                
             return   res.cc("修改密码失败!");

            }

            res.send("修改成功!");
        })
        
               
        });
    }

    
//更换头像的处理函数

exports.updateAvatar=(req,res)=>{
    //定义sql
    const sql="update ev_user set user_pic=? where id=?"

    //执行sql

    db.query(sql,[req.body.avatar,req.user.id],(err,result)=>{
        //注:avatar必须与验证规则里面的验证参数同名
    //执行sql失败
        if(err){
            return res.cc(err);
        }
    
    //执行sql成功,但影响行数不为1

        if(result.affectedRows !==1){

            return res.cc("更新头像失败!");

        }
    
    //更新成功

        res.send({
            status:0,
            message: "头像更新成功!"
            
        });

    });

}

创建博客处理接口

1.创建博客操作路由(创建,删除,获取)

const express= require('express')
const router=express.Router()
//导入路由处理函数
const articHandel=require('../router_handler/artic')

//引入验证规则
const schem_artic=require('../schems/artic')

//导入验证插件
const express_jio=require('@escook/express-joi')
//发布博客路由
router.post('/create_artic',express_jio(schem_artic.reg_artic),articHandel.save_artic)

//获取用户博客信息路由
router.get('/get_my_artic',articHandel.get_artic);

//获取一个种类的所有博客
router.get('/get_allartic_byclass',articHandel.grt_all_artic_byclass);

//删除博客路由
router.post('/delete_artic',articHandel.delete_artic)
module.exports=router;

2.创建博客路由处理函数

//导入数据库库操作模块
const db=require('../db/index')
//导入加密文章模块
const bcryptjs=require('bcryptjs')
//保存文章路由处理函数
exports.save_artic=(req,res)=>{
    
    const artic_imfomation=req.body;
    
    //对文章内容加密(应该不用加密)
  //  artic_imfomation.alias=bcryptjs.hashSync(artic_imfomation.alias,10);
    //定义sql
    const sql="INSERT INTO ev_article_cate  set ? "
    //执行sql
    db.query(sql,{name:artic_imfomation.name,alias:artic_imfomation.alias,username:req.user.username,artic_title:artic_imfomation.artic_title},(err,result)=>{
        
        //sql执行失败
        if(err){
            return res.cc(
                {
                std_flag:1,
                message:err.message});
        }
        //sql执行成功,但是影响行数不为一
        if(result.affectedRows !=1){
            return res.cc("发布博客失败!");
        }
        res.send({
            status:0,
            message:'发布成功!'
        })
    })
}



//获取用户博客信息处理函数

exports.get_artic=function(req,res){
    //定义查询博客信息的sql
    const sql="SELECT * FROM ev_article_cate WHERE username=?"
    //执行sql
    db.query(sql,req.user.username,(err,result)=>{
        if(err){

            return res.cc(err.message);
           
        }
        
        res.send({
            code:0,
            msg:"成功",
            data:result});
        
    })


}


//删除博客的处理函数
exports.delete_artic=function(req,res){
    //定义sql
    const sql="DELETE FROM ev_article_cate WHERE id=?";
    //执行sql失败
    db.query(sql,req.body.Id,(err,result)=>{
        if(err){
            return res.cc(err.message);
        }
        if(result.affectedRows !=1){
            return res.cc("删除失败!");
        }

        res.send({
            status:0,
            message:"删除成功!"
        })
        

    })

    

}
//获取一种博客的所有
    exports.grt_all_artic_byclass=function(req,res){
        //定义sql
        const sql=`SELECT * FROM ev_article_cate WHERE NAME=?`
     
        //执行sql
        db.query(sql,req.query.name,(err,result)=>{
            //sql执行失败
            if(err){

                return res.cc(err.message);

            }
            //sql执行成功
            
            res.send({
                status:0,
                boke:result
            })

        })
    }

总结

到此为止后端代码就基本完成,前端代码过于简单,笔者就不在这里赘述了,感兴趣的可以去笔者的github仓库自行下载,项目完全开源,如有不足的地方还希望大佬指正。 笔者的学习心得,对于此类新的事物我们应该抱有探索的精神去学习,喜欢的可以收藏加关注,笔者后续会继续更新Java项目,如果有技术上的错误,还望在评论区指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值