nodejs项目

node.js项目

前端项目构建

​ npm install -g gulp-cli

​ gulp -v

​ gulpfile | package.json文件拷贝

​ yarn (安装package.json指明的所有的依赖项)

​ 运行了一下gulp,发现报错了! 原因是因为缺少入口文件!

src/libs  (放置一些插件,例如jquey.min.js)
   /styles (放置一些scss文件,例如app.scss)
   /scripts/app.js (js文件)
   /static  (放置一些静态资源、例如图片、字体文件)
   index.html (静态页面)

后续可以借助 : https://adminlte.io/themes/AdminLTE/starter.html 模板

https://adminlte.io/themes/AdminLTE/documentation/

index.html里面的路径css/js引入正确了。

将app.js文件在index.html中引入。

<!--引入scripts/app.js文件-->
<script src="./scripts/app.js"></script>

app.js

const homeTpl = require("./views/home.html")
// console.log(homeTpl) //"<div>adadsaasd</div>"
$(".content").html(homeTpl) 

报错:

You may need an appropriate loader to handle this file type, currently no loaders are configured to process
this file. See https://webpack.js.org/concepts#loaders

缺少对于以html文件处理的 laoder装载器。

gulpfile.js

 module: {
          rules: [
            {
              test: /\.html$/,  //只要发现以html为后缀名的文件,采用stirng-loader装载器处理
              use: 'string-loader' //就会将hmtl文件处理成字符串
            }
          ]
        }

实现左侧导航点击切换效果:

//点击左侧导航栏实现首页与职位列表页面的切换
$(".sidebar-menu li").on("click",function(){
    $(this).addClass("active").siblings().removeClass("active")
    let linkAttr = $(this).attr("link")  //this.getAttribute("link")
    switch(linkAttr){
        case "home.html":
            $(".content").html(homeTpl)
            break;
        case "position.html":
            $(".content").html(posTpl)
            break;
    }
})

直接将素材/positions.html文件替换到views/positions.html

点击提交:

//点击提交
$(".content").on("click","#possubmit",function(){
    //获取到表单的值  将表单的所有数据序列化成字符串   
    let data = $("#possave").serialize()
    //需要将表单数据进行ajax提交
    $.ajax({
        url:"http://localhost:3000/api/position/add",
        method:"post",
        data,
        success:data=>{
            console.log("data==>",data)
        }
    })
})

后端项目构建

npm install -g express-generator

express -e

yarn

routes/positions.js

const express = require("express")
const router = express.Router()

//创建接口
router.post("/add",(req,res)=>{
    res.send("进入了哦...")
})
 
module.exports = router;

需要在app.js入口文件里面引入Position.js这个路由对象,然后进行注册。

var positionRouter = require("./routes/positions")

app.use("/api/position",positionRouter)

使用postman进行测试:选择post请求: http://localhost:3000/api/position/add

当你请求的时候,就会app.js ===> positionRouter ===> add

后续的实现了mvc分层,业务层放入到controller里面进行处理

routes/posiitons.js

const express = require("express")
const router = express.Router()
const posController = require("../controller/posController")

//创建接口  http://localhost:3000/api/position/add   
router.post("/add",posController.add)
 
module.exports = router;

controller/posController.js

const add = (req,res)=>{
    res.send("进入了哦...")
}

module.exports =  {
    add
}

连接mongodb数据库

yarn add mongoose

utils/db.js

//引入mongoose模块
const mongoose = require("mongoose")

//创建连接  test数据库的名称
mongoose.connect('mongodb://localhost:27017/lagou',{
    useNewUrlParser: true,
    useUnifiedTopology: true 
})

module.exports = mongoose

model/posModel.js

//引入db
const db = require("../utils/db")

//创建约束
const positionSchema = db.Schema({
    companyName:{type:String,required:true},
    positionName:{type:String,required:true},
    city:{type:String,required:true},
    salary:{type:String,required:true}, 
    type:{type:String,required:true},
    experience:{type:String,required:true},
    degree:{type:String,required:true},
    description:{type:String,required:true}
})

//创建集合
const Position = db.model('positions',positionSchema)


//添加职位操作
const save = function(){
    Position.insertMany({
        companyName:"千锋",
        positionName:"讲师",
        city:"北京",
        salary:"30K",
        type:"全职",
        experience:"8年",
        degree:'本科',
        description:'aldjalsd'
    },(err)=>{
        if(!err){
            console.log("插入成功...")
        }
    })
}

module.exports = {
    save
}

posController.js

const posModel = require("../model/posModel")
const add = (req,res)=>{
    //需要调用posModel的save方法,往数据库里面添加职位信息
    posModel.save()

    res.send("进入了哦...")
}

module.exports =  {
    add
}

当你在浏览器:http://localhost:3000/api/position/add

实现添加职位入库操作

// const save = function(data){
//     return Position.insertMany(data,(err)=>{
//         if(!err){
//             console.log("插入成功...")
//             return true
//         }else{
//             console.log("插入失败")
//             return false;
//         }
//     })
// }

发现这种写法在posController中调用获取不到save函数的返回结果,一直是undefined.

Position.insertMany这个方法是异步的,所以内部函数不能获取到异步函数返回的结果,直接一直都是undefined结果。

const save = function(data){
    return Position.insertMany(data)
                   .then(function(res){return true})
                   .catch(err=>false)
}

save方法就会返回一个Promise对象。(因为mongodb数据库操作都是异步的,没有办法直接获取到最终结果)

如何获取到一个处于pengding状态的promise对象的resolve或者reject的结果呢?

可以采用es6中的async函数解决,通过await关键字获取到处于pending状态的promise的结果。

const add = async (req,res)=>{
	//await 经常发现一个promise对象的场景
    const flag = await posModel.save(req.body)  //正在往数据库写入数据的一个状态
    console.log("flag===>",flag)
    res.send("进入了哦...")
}
const add = async (req,res)=>{
    //需要调用posModel的save方法,往数据库里面添加职位信息
    //save方法现在返回一个 Promise { <pending> }
    const flag = await posModel.save(req.body)
    if(flag){ //添加职位成功
        res.send({flag:true,data:{message:'success'}})
    }else{
        res.send({flag:false,data:{message:'fail'}})
    }
}

后续为了统一接口返回结果,最好搞一个ejs模板进行后端接口的返回,目的就是为了方便控制,传递数据。

const add = async (req,res)=>{
    //需要调用posModel的save方法,往数据库里面添加职位信息
    //save方法现在返回一个 Promise { <pending> }
    const flag = await posModel.save(req.body)
    if(flag){ //添加职位成功
        res.render("api.succ.ejs",{ //aaaa是给api.succ.ejs模板传递过去的参数
            aaaa:JSON.stringify({message:'success'})
        })
    }else{
        res.render("api.fail.ejs",{
            aaaa:JSON.stringify({message:'fail'})
        })
    }
}
{
    "flag":true,
    "data":<%-aaaa %>
}

前端提交数据给接口,发现跨域报错了。通过代理的方式解决跨域问题

gulpfile.js

middleware: [
    proxy('/api', {  //http://localhost:3000/api/position/add
        target: 'http://localhost:3000',
        // changeOrigin: true
    })
]

app.js

//点击提交
$(".content").on("click","#possubmit",function(){
    //获取到表单的值
    let data = $("#possave").serialize()
    //需要将表单数据进行ajax提交
    $.ajax({
        url:"/api/position/add",
        method:"post",
        data,
        dataType:"json", //后端给前端返回类型 (后端的ejs模板双引号!)
        success:data=>{ //需要注意,默认data是string类型,所以需要变成object类型。
            if(!data.flag){
                alert("添加职位失败!")
            }else{
                $(".content").html(posTpl)
            }
        }
    })
})

查询所有职位列表


//查询所有职位
function getPosTable(){
    $(".content").html(posTpl)
    //发送ajax 从数据库里面查询职位
    $.ajax({
        url:"/api/position/find",
        dataType:"json",
        success:data=>{
            console.log("查询到的职位:",data)
        }
    })
}

需要制造find接口

router.get("/find",posController.find)

posController.js

//查询职位信息
const find = async (req,res)=>{
    //调用模型层的查询职位方法
    const data = await posModel.find()
    res.render("api.succ.ejs",{
        data:JSON.stringify(data)
    })
}


module.exports =  {
    add,
    find
}

posModel.js

//查询所有的职位信息
const find = function(){
    return Position.find()
}

module.exports = {
    save,
    find
}

实现职位显示:

//查询所有职位
function getPosTable(){
    $(".content").html(posTpl)
    //发送ajax 从数据库里面查询职位
    $.ajax({
        url:"/api/position/find",
        dataType:"json",
        success:data=>{
            if(data.flag){
                const arr = data.data.map(item=>{
                    return `<tr>
                    	<td>${item.companyName}</td>
                        ...........
                    </tr>`
                })
                $(".table").append(arr)
            }
        }
    })
}

但是这种方式会根据查询到的职位数组,动态生成多个tr元素,再去进行append追加操作,效率比较低。

使用artTemplate模板来去进行渲染。

index.html页面:

<!--引入artTemplate模板引擎解决-->
<script src="./libs/template-web.js"></script>

//查询所有职位
function getPosTable(){
    // $(".content").html(posTpl)
    //发送ajax 从数据库里面查询职位
    $.ajax({
        url:"/api/position/find",
        dataType:"json",
        success:data=>{
            if(data.flag){
            	//注意:template的render函数返回一个拼状好的一个新的页面。
                const html = template.render(posTpl,{
                    data:data.data
                })
                $(".content").html(html)
            }
        }
    })
}

Position.html

默认遍历数组,每一项

$value 数组中每一项

$index 数组中下标默认从0开始

{{each data item i}}   
            <tr>
                <td>{{i+1}}</td>
                <td><img width="50" height="50"
                        src="https://www.lgstatic.com/i/image3/M00/12/AF/CgpOIFpu7ROAU0UaAAAvwWv_H_w082.jpg" alt="">
                </td>
                <td>{{item.companyName}}</td>
                <td>{{item.positionName}}</td>
                <td>{{item.city}}</td>
                <td>今天20:22</td>
                <td>{{item.salary}}</td>
                <td>
                    <button class="btn btn-sm btn-primary pos-edit" posid="{{item._id}}"><span
                            class="fa fa-edit"></span> 修改</button>
                    <button class="btn btn-sm btn-danger pos-remove" posid="{{item._id}}"><span class="fa fa-remove"></span> 删除</button>
                </td>
            </tr>
            {{/each}}

修改职位功能

//点击修改
$(".content").on("click",".pos-edit",function(){
    let posId = $(this).attr("posid")
    //根据posId然后进行查询对应的职位信息,进行表单回填操作
    $.ajax({
        url:"/api/position/"+posId,
        dataType:"json",
        success:data=>{
            console.log("data===>",data)
        }
    })
    //跳转到修改页面
    $(".content").html(posUpdateTpl)
})

接下来需要创造 /api/position/:id

router.get("/:id",posController.findById)

posController.js

//根据id查询具体职位信息
const findById = async (req,res)=>{
    const data = await posModel.findById(req.params.id)
    res.render("api.succ.ejs",{
        data:JSON.stringify(data)
    })
}

module.exports =  {
    add,
    find,
    findById
}

posModel.js

//根据传入的id,调用mongoose底层查询具体对象的方法
const findById = function(id){
    return Position.findById(id)
}

module.exports = {
    save,
    find,
    findById
}
//点击修改
$(".content").on("click",".pos-edit",function(){
    let posId = $(this).attr("posid")
    //根据posId然后进行查询对应的职位信息,进行表单回填操作
    $.ajax({
        url:"/api/position/"+posId,
        dataType:"json",
        success:data=>{
            if(data.flag){
                const html = template.render(posUpdateTpl,{
                    data:data.data  //根据id查询的具体职位对象data传递给了posUpdateTpl
                })
                $(".content").html(html)
            }
        }
    })
    //跳转到修改页面
    // $(".content").html(posUpdateTpl)
})

在posUpdate.html页面中对于data对象进行取值,表单回填。

<input value={{data.companyName}} type="text" class="form-control" name="companyName" id="companyName" placeholder="请输入公司名称">

点击修改的提交,发现还是添加数据。

position.add.html

<button from="add" type="button" id="possubmit" class="btn btn-info pull-right">提交</button>

posiiton.update.html

<button from="update" type="button" id="possubmit" class="btn btn-info pull-right">提交</button>
//点击提交
$(".content").on("click","#possubmit",function(){
    //获取到表单的值
    let data = $("#possave").serialize()
    let url = $(this).attr("from") === "add" ? "/api/position/add" : "/api/position/update"
    //需要将表单数据进行ajax提交
    $.ajax({
        url,
        method:"post",
        data,
        dataType:"json", //后端给前端返回类型
        success:data=>{
            if(!data.flag){
                alert("职位操作失败!")
            }else{
                getPosTable()
            }
        }
    })
})

/api/position/update (post请求)

router.post("/update",posController.update)
const update = async (req,res)=>{
    // 需要获取外部传入的id,req.body所有更新的内容
    let flag = await posModel.update(req.body.id,req.body)
    if(flag){ 
        res.render("api.succ.ejs",{
            data:JSON.stringify({message:'success'})
        })
    }else{
        res.render("api.fail.ejs",{
            data:JSON.stringify({message:'fail'})
        })
    }
}

注意:需要前端 position.update.html页面中传入唯一的id给后端才可以

<!--在隐藏域里面将id字段传递给后端-->
<input type="hidden" name="id" value={{data._id}}>
const update = function(id,data){
    // return Position.findOneAndUpdate({_id:id},data)
    return Position.findByIdAndUpdate(id,data)
                   .then(res=>true)
                   .catch(err=>false)
}
module.exports = {
    save,
    find,
    findById,
    update
}

上传企业Logo

选择图片进行上传,发现后端通过req.body获取不到上传的图片logo信息。原因是因为jquery的默认的ajax方法是不支持表单图片上传。

引入插件jquery.form.min.js插件解决这个问题。

index.html文件里面进行插件引入

position.add.html 记住:只要表单上传图片操作,必须设置enctype=‘multipart/form-data’

<form class="form-horizontal" id="possave" action="/api/position/add" method="post" enctype="multipart/form-data">

app.js文件中,通过jquery.form.min.js里面提供的核心方法ajaxSubmit方法实现上传图片操作。

//点击提交
$(".content").on("click","#possubmit",function(){
    let options = {
        dataType:"json",
        success:data=>{
            if(!data.flag){
                alert("职位操作失败!")
            }else{
                getPosTable()
            }
        }
    }
    $("#possave").ajaxSubmit(options)
}

前端已经可以将图片与utf-8数据一起传递给了后端了,但是目前后端没有获取到前端传递来的图片与数据。

后端可以通过multer模块,来去处理前端传递来的图片与utf-8数据。

Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。它是写在 busboy 之上非常高效。

yarn add multer

positions.js

const express = require("express")
const router = express.Router()
const multer = require("multer")
const path = require("path")
const up = path.resolve(__dirname,"../public/upload")
const upload = multer({dest:up})  //指明上传后的图片放入到了public/upload/xxxx
const posController = require("../controller/posController")

router.post("/add",upload.single('companyLogo'),posController.add)

posController的add方法中,可以通过req.body获取utf-8数据,req.file获取到上传的图片信息。

const add = async (req,res)=>{
    console.log("addd=>",req.body,req.file)

    //将上传的图片进行改名操作
    const up = path.resolve(__dirname,"../public/upload") //找到upload所在的文件路径
    const dot = req.file.originalname.lastIndexOf(".")    
    const fileSuffix = req.file.originalname.substr(dot)  //dog.png ==> ".png"
    const prevFilePath = path.resolve(up,req.file.filename) //获取之前的upload里面的图片路径
    const nextFilePath = path.resolve(up,req.file.filename+fileSuffix) //希望变的图片路径
    fs.renameSync(prevFilePath,nextFilePath) //通过fs模块的renameSync方法改名字

    //需要调用posModel的save方法,往数据库里面添加职位信息
    //save方法现在返回一个 Promise { <pending> }
    const flag = await posModel.save(req.body)
    if(flag){ //添加职位成功
        // res.send({flag:true,data:{message:'success'}})
        res.render("api.succ.ejs",{
            data:JSON.stringify({message:'success'})
        })
    }else{
        res.render("api.fail.ejs",{
            data:JSON.stringify({message:'fail'})
        })
    }
}

希望Position.html里面显示upload的图片,如何实现?

 <td><img width="50" height="50"
 	src="http://localhost:3000/upload/{{item.companyLogo}}" alt="">
 </td>

接下来,需要在数据库posModel中存一个数据字段,叫做companyLogo

const positionSchema = db.Schema({
    companyName:{type:String,required:true},
    positionName:{type:String,required:true},
    city:{type:String,required:true},
    salary:{type:String,required:true}, 
    type:{type:String,required:true},
    experience:{type:String,required:true},
    degree:{type:String,required:true},
    description:{type:String,required:true},
    companyLogo:{type:String}
})

点击添加的时候,进入posController的add方法中,需要在req.body上面动态的添加companyLogo

    //将上传的图片进行改名操作
    .......
    //往req.body上面动态的添加一个companyLogo字段
    req.body.companyLogo = req.file.filename + fileSuffix

点击修改:

​ position.update.html

<form class="form-horizontal" id="possave" action="/api/position/update" method="post" enctype="multipart/form-data">

position.js

router.post("/update",upload.single('companyLogo'),posController.update)

后续一样的代码,封装成uploadFile

const uploadFile = (req,res)=>{
    if(req.file){ //上传图片了,再去进行操作
        const dot = req.file.originalname.lastIndexOf(".")
        const fileSuffix = req.file.originalname.substr(dot)  //".png"
        const prevFilePath = path.resolve(__dirname,"../public/upload",req.file.filename) 
        const nextFilePath = path.resolve(__dirname,"../public/upload",req.file.filename+fileSuffix)
        fs.renameSync(prevFilePath,nextFilePath)
        req.body.companyLogo = req.file.filename + fileSuffix
    }else{ //没有上传图片,图片的companyLogo还是用之前
        req.body.companyLogo = req.body.logo
    }
}
const update = async (req,res)=>{
    uploadFile(req,res)
    // 需要获取外部传入的id,req.body所有更新的内容
    let flag = await posModel.update(req.body.id,req.body)
    if(flag){ 
        res.render("api.succ.ejs",{
            data:JSON.stringify({message:'success'})
        })
    }else{
        res.render("api.fail.ejs",{
            data:JSON.stringify({message:'fail'})
        })
    }
}

position.update.html文件中:

<input type="hidden" name='logo' value={{data.companyLogo}}>

目的就是如果不上传图片的话,logo的名字就是数据库中之前的图片的名字,后续进入到posController中update方法的时候,没有上传图片的话就可以将req.body.companyLogo = req.body.logo

前端注册功能实现

//注册登录
let isSignin = false
let greeting = "hello world"

//生成登录注册视图
renderTpl(isSignin,greeting)
function renderTpl(isSignin,greeting){
    let html = template.render(userInfoTpl,{
        isSignin,
        greeting
    })
    $(".user-menu").html(html)
}


//点击注册
$(".navbar-nav").on("click","#btn-signup",function(e){
    $("#user-submit").on("click",async function(){ //点击提交按钮
        //获取输入框的值
        let username = $("#username").val()
        let password = $("#password").val()
        let result = await sign({username,password},"signup")
        console.log("result===>",result)
    })
})


//发起请求给后端
function sign(data,uri){
    return $.ajax({
        url:"/api/user/"+uri,
        data,
        type:"post",
        dataType:"json",
        success:data=>{
            return data
        }
    })
}

需要写后端接口 /api/user/signup 这个注册接口 (post请求)

app.js文件:

app.use('/api/user', usersRouter);

routes/users.js

router.post('/signup', function(req, res, next) {
  res.send("/api/user/signup")
});

routes/users.js

router.post('/signup',userController.signup);

controller/usersController.js

//注册
const signup = async (req,res)=>{
    let flag = await userModel.save(req.body)
    console.log("flag===>",flag) //插入成功为true,插入失败false
    res.send("/api/user/signup!")
}

model/usersModel.js


//引入db
const db = require("../utils/db")

//创建约束
const userSchema = db.Schema({
    username:{type:String,required:true},
    password:{type:String,required:true}
})

//创建集合
const Users = db.model('users',userSchema)


//用户注册的方法
const save = function(data){
    return Users.insertMany(data)
                .then(res=>true)
                .catch(err=>false)
}

module.exports = {
    save
}

插入的时候,发现可以插入多个同名用户,可否根据用户名唯一呢?

model/userModel.js

const findOne = function(data){
    return Users.findOne(data)
}

controller/usersController.js

//注册
const signup = async (req,res)=>{
    let username = req.body.username;
    //根据用户名进行查询,如果返回null说明此用户没有存在数据库中,可以进行插入操作,否则返回具体用户信息
    let flag =  await userModel.findOne({username})
    if(flag){ //数据库里面用此用户名
        res.render("api.fail.ejs",{
            data:JSON.stringify({message:"此用户名已经存在了,请重新注册!"})
        })
    }else{ //数据库里面没有此用户名
        let flag = await userModel.save(req.body)
        flag ? res.render("api.succ.ejs",{
                data:JSON.stringify({message:"恭喜您:注册成功"})   
            })
            :
            res.render("api.fail.ejs",{
                data:JSON.stringify({message:"注册失败!"})
            })
    }
}
//点击注册
$(".navbar-nav").on("click","#btn-signup",function(e){
    $("#user-submit").off("click").on("click",async function(){
        //获取输入框的值
        let username = $("#username").val()
        let password = $("#password").val()
        let result = await sign({username,password},"signup")
        console.log("result===>",result)
        if(!result.flag){
            alert(result.data.message)
        }else{
            alert("注册成功了!")
        }
    })
})

登录功能的实现


//点击登录
$(".navbar-nav").on("click","#btn-signin",function(e){
    $("#user-submit").off("click").on("click",async function(){
        //获取输入框的值
        let username = $("#username").val()
        let password = $("#password").val()
        let result = await sign({username,password},"signin")
        if(result.flag){
            renderTpl(true,"您好!"+result.data.username)
        }else{
            alert(result.data.message)
        }
    })
})

users.js

router.post("/signin",userController.signin)

usersController.js

const signin = async(req,res)=>{
    let flag =  await userModel.findOne(req.body)
    if(flag){
        res.render("api.succ.ejs",{
            data:JSON.stringify({message:"恭喜您:登录成功",username:req.body.username})   
        })
    }else{
        res.render("api.fail.ejs",{
            data:JSON.stringify({message:"用户名或者密码输入错误..."})
        })
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值