node博客小项目:接口开发、连接mysql数据库

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 【10月更文挑战第14天】node博客小项目:接口开发、连接mysql数据库

简介

本篇文章主要讲解使用NodeJS开发Web服务器(一个小型的博客项目)及NodeJS 如何连接 MySQL。

本文参考:NodeJS 连接 MySQL【NodeJS】_哔哩哔哩_bilibili

node服务器搭建

创建项目文件下,执行如下npm命令

npm init -y
npm i nodemon

创建如下文件夹及文件

image.png

入口文件 www.js

//引入http模块
const http = require('http')
const serverHandler = require('../app.js')
const PORT = 5000
//创建服务器
const server = http.createServer(serverHandler)
server.listen(PORT,() => {
   
    console.log('服务运行在5000端口...');
})

app.js

const serverHandler = (req,res) => {
   
    //设置返回的报文格式
    res.setHeader('Content-Type',"application/json")

    //返回内容
    res.end()
}

module.exports = serverHandler

配置文件package.json

{
   
  "name": "11",
  "version": "1.0.0",
  "description": "",
  "main": "bin/www.js",
  "scripts": {
   
    "test": "echo "Error: no test specified" && exit 1",
    "dev":"nodemon bin/www.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
   
    "nodemon": "^2.0.19"
  }
}

启动项目

npm run dev

路由初始化

创建博客处理模块 根目录 src\routes\blog.js

//处理博客相关路由
const handelBlogRoute = (req,res) => {
   
    //定义路由的处理逻辑
    const method = req.method

    if(method === "GET" && req.path === "/api/blog/list"){
   
        return {
   
            message:"获取博客接口列表"
        }
    }
    if(method === "GET" && req.path === "/api/blog/detail"){
   
        return {
   
            message:"获取博客详情接口"
        }
    }
    if(method === "POST" && req.path === "/api/blog/new"){
   
        return {
   "新建博客接口"
        }
    }
    if(method === "POST" && req.path === "/api/blog/update"){
   
        return {
   
            message:"更新博客接口"
        }
    }
    if(method === "POST" && req.path === "/srcapi/blog/delete"){
   
        return {
   
            message:"删除博客列表接口"
        }
    }
}

module.exports = handelBlogRoute

app.js中优化部分代码

const handelBlogRoute = require("./src/routes/blog")

const serverHandler = (req,res) => {
   
    //设置返回的报文格式
    res.setHeader('Content-Type',"application/json")
    const url = req.url
    req.path = url.split("?")[0]
    let blogData = handelBlogRoute(req,res)
    //返回内容
    if(blogData){
   
        res.end(JSON.stringify(blogData))
    }

    //匹配不到路由时的处理
    res.writeHead(404,{
   'Content-Type':'text/plain'})
    res.write("404 Not FOund")
    res.end()
}

module.exports = serverHandler

开发第一个路由

首先我们开发获取博客列表接口

1.创建src\contrllers\blog.js文件,用于设置返回接口数据

//博客相关方法
const getList = (author , keyword) => {
   
    //从数据库获取数据
    //先返回假数据
    return [
        {
    id:1, title:'标题1', content:"内容2",author:"张三", createAt:123456 },
        {
    id:2, title:'标题1', content:"内容2",author:"张三", createAt:1234567 },
        {
    id:3, title:'标题1', content:"内容2",author:"张三", createAt:12345678 },

    ]
}

module.exports = {
   
    getList
}

这个接口需要参数author , keyword关键词,用来返回匹配的数据。参数author , keyword是通过url的query参数获取的,因此需要解析url的query参数

2.解析url的query参数

app.js中

const handelBlogRoute = require("./src/routes/blog")
//node 原生的属性
const querystring = require("querystring")
//这里主要进行一些服务器的设置
const serverHandler = (req,res) => {
   
    //设置返回的报文格式
    res.setHeader('Content-Type',"application/json")

    //获取path    /api/blog/list
    const url = req.url
    req.path = url.split("?")[0]

    //解析query
    req.query = querystring.parse(url.split("?")[1])

    //路由匹配
    let blogData = handelBlogRoute(req,res)
    //返回内容
    if(blogData){
   
        res.end(JSON.stringify(blogData))
    }else{
   
        //匹配不到路由时的处理
        res.writeHead(404,{
   'Content-Type':'text/plain'})
        res.write("404 Not FOund")
        res.end()
    }  
}

module.exports = serverHandler

3.完善路由内容

src\routes\blog.js

const {
    SuccessModel } = require("../model/responseModel")
const {
    getList } = require("../contrllers/blog")
//处理博客相关路由
const handelBlogRoute = (req,res) => {
   
    //定义路由的处理逻辑
    const method = req.method

    if(method === "GET" && req.path === "/api/blog/list"){
   
        //可能的请求路径 api/blog/list?query=zhangsan&keyword=123

        const author = req.query.author || ""
        const keyword = req.query.keyword || ""
        //根据自定义的关键词,返回列表数据
        const listData = getList(author,keyword)
        //使用模型返回规范的文件格式
        return new SuccessModel(listData)
    }
    if(method === "GET" && req.path === "/api/blog/detail"){
   
        return {
   
            message:"获取博客详情接口"
        }
    }
    if(method === "POST" && req.path === "/api/blog/new"){
   
        return {
   
            message:"新建博客接口"
        }
    }
    if(method === "POST" && req.path === "/api/blog/update"){
   
        return {
   
            message:"更新博客接口"
        }
    }
    if(method === "POST" && req.path === "/srcapi/blog/delete"){
   
        return {
   
            message:"删除博客列表接口"
        }
    }
}

module.exports = handelBlogRoute

注意,为了使返回值更加规范方便,我们创建了一个类。

4.创建返回值模型

src\model\responseModel.js

class BaseModel {
   
    constructor(data,message) {
   
        if(typeof data == "string") {
   
            this.message = data;
            data = null
            message = null
        }
        if(data) {
   
            this.data = data
        }
        if(message) {
   
            this.message = message
        }
    }
}

//成功模型  实例化后 产生一个 {  data:data , errno : 0   }格式的对象
class SuccessModel extends BaseModel {
   
    constructor ( data ,message) {
   
        super(data,message)
        this.errno = 0
    }

}

//失败模型
class ErrorModel extends BaseModel {
   
    constructor ( data ,message) {
   
        super(data,message)
        this.errno = -1
    }

}

module.exports = {
   
     SuccessModel,
     ErrorModel

}

此时,访问接口,是可以获取数据的。

开发获取博客详情接口

逻辑如同获取博客列表

src\contrllers\blog.js

//博客相关方法
const getList = (author , keyword) => {
   
   .......
}

//获取博客详情数据
const getDetail = (id) => {
   
    //先返回假数据
    return  {
    id:1, title:'标题1', content:"内容2",author:"张三", createAt:123456 }
}

module.exports = {
   
    getList,
    getDetail
}

src\routes\blog.js

const {
    SuccessModel } = require("../model/responseModel")
const {
    getList ,getDetail} = require("../contrllers/blog")
//处理博客相关路由
const handelBlogRoute = (req,res) => {
   
    //定义路由的处理逻辑
    const method = req.method
    //获取接口列表    .....
    //获取接口详情
    if(method === "GET" && req.path === "/api/blog/detail"){
   
        const id = req.query.id
        const detailData =  getDetail(id)
        return new SuccessModel(detailData)
    }
    ......
}

module.exports = handelBlogRoute

访问接口

处理post请求

原生node的post请求是一个异步函数

我们需要在app.js中进行post请求处理

const handelBlogRoute = require("./src/routes/blog")
//node 原生的属性
const querystring = require("querystring")

//处理post数据
const getPostData = (req) => {
   
    const promise = new Promise((resolve,reject) => {
   
        if(req.method !== "POST"){
   
            resolve({
   })
            return 
        }
        if(req.headers['conten-type'] !== 'application/json'){
   
            resolve({
   })
            return 
        }
        let postData = ""
        req.on('data',(chunk) => {
   
            postData += chunk.toString()
        })
        req.on('end', ()=> {
   
            if(!postData) {
   
                resolve({
   })
                return 
            }
            resolve(
                JSON.parse(postData)
            )
        })
    })
}

//这里主要进行一些服务器的设置
const serverHandler = (req,res) => {
   
    //设置返回的报文格式
    res.setHeader('Content-Type',"application/json")

    //获取path    /api/blog/list
    const url = req.url
    req.path = url.split("?")[0]

    //解析query
    req.query = querystring.parse(url.split("?")[1])
    //处理post数据
    getPostData(req).then((postData) => {
   
        //将post数据绑定在req的body上
        req.body = postData

        //路由匹配
        let blogData = handelBlogRoute(req,res)
        //返回内容
        if(blogData){
   
            res.end(JSON.stringify(blogData))
            return
        }
        //匹配不到路由时的处理
        res.writeHead(404,{
   'Content-Type':'text/plain'})
        res.write("404 Not FOund")
        res.end()
    })
}

module.exports = serverHandler

完善接口

src\routes\blog.js

const {
    SuccessModel,ErrorModel } = require("../model/responseModel")
const {
    getList ,getDetail,createNewBlog, deleteBlog,updataBlog} = require("../contrllers/blog")
//处理博客相关路由
const handelBlogRoute = (req,res) => {
   
    //定义路由的处理逻辑
    const method = req.method
    const id = req.query.id
    const postData = req.body
    //获取接口列表
    if(method === "GET" && req.path === "/api/blog/list"){
   
        //可能的请求路径 api/blog/list?query=zhangsan&keyword=123
        const author = req.query.author || ""
        const keyword = req.query.keyword || ""
        //根据自定义的关键词,返回列表数据
        const listData = getList(author,keyword)
        //使用模型返回规范的文件格式
        return new SuccessModel(listData)
    }
    //获取接口详情
    if(method === "GET" && req.path === "/api/blog/detail"){
   

        const detailData =  getDetail(id)
        return new SuccessModel(detailData)
    }
    //新建接口
    if(method === "POST" && req.path === "/api/blog/new"){
   

        const newBlogData = createNewBlog(postData)
        return new SuccessModel(newBlogData)
    }
    //更新博客路由
    if(method === "POST" && req.path === "/api/blog/update"){
   
        const updateBlogData = updataBlog(postData)
        if(updateBlogData){
   
            return new SuccessModel("更新博客成功")
        }else{
   
            return new ErrorModel("更新博客失败")
        }
    }
    //删除博客路由
    if(method === "POST" && req.path === "/srcapi/blog/delete"){
   
        const deleteBlogData = deleteBlog(id)
        if(deleteBlogData){
   
            return new SuccessModel("删除博客成功")
        }else{
   
            return new ErrorModel("删除博客失败")
        }
    }
}

module.exports = handelBlogRoute

src\contrllers\blog.js

//博客相关方法
const getList = (author , keyword) => {
   
    //从数据库获取数据
    //先返回假数据
    return [
        {
    id:1, title:'标题1', content:"内容2",author:"张三", createAt:123456 },
        {
    id:2, title:'标题1', content:"内容2",author:"张三", createAt:1234567 },
        {
    id:3, title:'标题1', content:"内容2",author:"张三", createAt:12345678 },
    ]
}

//获取博客详情数据
const getDetail = (id) => {
   
    //先返回假数据
    return  {
    id:1, title:'标题1', content:"内容2",author:"张三", createAt:123456 }
}

//创建新博客
const createNewBlog = (blogData) => {
    return {
    id:1 } }
//更新boke
const updataBlog = (id,blogData = {
   }) => {
     return true }
//删除博客
const deleteBlog = (id) => {
     return true }
module.exports = {
   
    getList,
    getDetail,
    createNewBlog,
    updataBlog,
    deleteBlog
}

使用mysql

1.创建数据库连接

image.png

2.创建myblog数据库,然后创建blogs数据表,表中按如图方式增加字段

image.png

数据表操作

image.png

基本的查找语句为:

SELECT * from blogs

查找时,也可以指定字段

select id,title from blogs

sql语句不区分大小写

注:语句前增加“--”可以注释语句

也可以进行筛选查询

SELECT * from blogs where title='标题1'
SELECT * from blogs where title='标题1' and author='gcshi'
SELECT * from blogs where title='标题1' or author='gcshi'
-- 模糊查询,查询标题包含1的内容
SELECT * from blogs WHERE title like '%1%'
-- 对查找的内容进行排序 默认为正序
SELECT * from blogs WHERE title like '%1%' order by id
-- 对查找的内容进行排序 倒序
SELECT * from blogs WHERE title like '%1%' order by id desc

insert into blogs(title,content,author,createdAt) value ('标题1','内容1','gcshi',1234567890123)

我们可以选择我们的增加语句,然后点击【运行已选择的】

image.png

update blogs set title='11111'

这种方法会将所有数据的标题修改成111

image.png

我们可以增加筛选条件

update blogs set title='222' where content='内容1'

-- 这会删除整张表
delete from blogs

上述命令会删除整张表,这是危险操作。我们应该加上条件

delete from blogs WHERE title='222'

node连接数据库

npm i mysql
├─ mysql-demo
│  └─ index.js
//引入mysql
const mysql = require('mysql')

// 创建连接对象
const connection =  mysql.createConnection({
   
  host:'localhost',
  user:'root',
  password:'root',
  port:3306,
  database:'myblog'
})

//开始连接
connection.connect();

//执行sql语句
const sql = 'select * from blogs'

connection.query(sql,(err,result) => {
   
  if(err){
   
    return console.log(err);
  }
  console.log('reult',result);
})

//关闭连接
connection.end()

我们在mysql-demo文件夹中运行一下 node index.js,可以看到返回的数据结果(一个json数据格式)
image.png

sql语句封装

全局调用sql语句会很乱,我们将sql语句进行封装,便于我们在项目中使用。

src下创建db文件夹,创建mysql.js文件

└─ src
     ├─ config               //数据库配置文件夹
   │  └─ db.js
   ├─ contrllers
   │  └─ blog.js
   ├─ db
   │  └─ mysql.js             
   ├─ model
   │  └─ responseModel.js
   └─ routes
      └─ blog.js
//引入mysql
const mysql = require('mysql')

const {
    MYSQL_CONFIG } = require('../config/db')

// 创建连接对象
const connection =  mysql.createConnection( MYSQL_CONFIG )

//开始连接
connection.connect();

//执行sql语句,封装成一个promise函数
function execSQL(sql) {
   
    const promise = new Promise((resolve, reject) => {
   
        connection.query(sql,(err,result)=>{
   
            if(err){
   
                return reject(err)
            }
            resolve(result)
        })
    })
    return promise
}

module.exports = {
   
    execSQL
}

为了方便数据库不同环境下的配置的修改,我们将其单独配置src\config\db.js

let MYSQL_CONFIG = {
   }

MYSQL_CONFIG = {
   
    host:'localhost',
    user:'root',
    password:'root',
    port:3306,
    database:'myblog'
}

module.exports = {
   
    MYSQL_CONFIG
}

获取博客列表对接Mysql

src\contrllers\blog.js

const {
    execSQL } = require("../db/mysql")

//获取博客列表
const getList = (author , keyword) => {
   
   let sql = "select * from blogs where 1=1 "
   if( author ){
   
       sql += `and author=${
     author} `
   }
   if( keyword ){
   
       sql += `and title like '%${
     keyword}%' `
   }
   return execSQL(sql) 
}

//获取博客详情数据

//创建新博客

//更新boke

//删除博客

module.exports = {
   
    getList,
    getDetail,
    createNewBlog,
    updataBlog,
    deleteBlog
}

src\routes\blog.js

const {
    SuccessModel,ErrorModel } = require("../model/responseModel")
const {
    getList ,getDetail,createNewBlog, deleteBlog,updataBlog} = require("../contrllers/blog")
//处理博客相关路由
const handelBlogRoute = (req,res) => {
   
    //定义路由的处理逻辑
    const method = req.method
    const id = req.query.id
    const postData = req.body
    //获取接口列表
    if(method === "GET" && req.path === "/api/blog/list"){
   
        //可能的请求路径 api/blog/list?query=zhangsan&keyword=123
        const author = req.query.author || ""
        const keyword = req.query.keyword || ""
        //根据自定义的关键词,返回列表数据
        return getList(author,keyword).then(res => {
   
            //使用模型返回规范的文件格式
            return new SuccessModel(res)
        })
    }
    //获取接口详情

    //新建接口

    //更新博客路由

    //删除博客路由
}

module.exports = handelBlogRoute

app.js

const handelBlogRoute = require("./src/routes/blog")
//node 原生的属性
const querystring = require("querystring")

//处理post数据
const getPostData = (req) => {
   
    const promise = new Promise((resolve,reject) => {
   
        if(req.method !== "POST"){
   
            resolve({
   })
            return 
        }
        if(req.headers['conten-type'] !== 'application/json'){
   
            resolve({
   })
            return 
        }
        let postData = ""
        req.on('data',(chunk) => {
   
            postData += chunk.toString()
        })
        req.on('end', ()=> {
   
            if(!postData) {
   
                resolve({
   })
                return 
            }
            resolve(
                JSON.parse(postData)
            )
        })
    })
    return promise
}

//这里主要进行一些服务器的设置
const serverHandler = (req,res) => {
   
    //设置返回的报文格式
    res.setHeader('Content-Type',"application/json")

    //获取path    /api/blog/list
    const url = req.url
    req.path = url.split("?")[0]

    //解析query
    req.query = querystring.parse(url.split("?")[1])
    //处理post数据
    getPostData(req).then((postData) => {
   
        //将post数据绑定在req的body上
        req.body = postData

        //路由匹配
        let promiseBlogData = handelBlogRoute(req,res)
        //返回内容
        if(promiseBlogData){
   
            promiseBlogData.then(promiseBlogData =>{
   
                res.end(JSON.stringify(promiseBlogData))
            })
            return
        }
        //匹配不到路由时的处理
        res.writeHead(404,{
   'Content-Type':'text/plain'})
        res.write("404 Not FOund")
        res.end()
    })
}

module.exports = serverHandler

博客详情、新建博客对接Mysql

src\contrllers\blog.js新建博客

//创建新博客
const createNewBlog = (blogData = {
   }) => {
   
    const title = blogData.title
    const content = blogData.content
    const author = blogData.author
    const createdAt = Date.now()
    const sql = `
        insert into blogs (title, content ,author ,createdAt) values ('${
     title}', '${
     content}', '${
     author}', ${
     createdAt});
    `
    return execSQL(sql).then(res => {
   
        console.log(res);
    })
}

插入成功后的返回结果

因此,我们的更新博客和获取博客详情接口如下

src\contrllers\blog.js


//获取博客详情数据 通过id获取内容
const getDetail = (id) => {
   
    let sql = `select * from blogs where id=${
     id} `
    return execSQL(sql)
}

//创建新博客
const createNewBlog = (blogData = {
   }) => {
   
    const title = blogData.title
    const content = blogData.content
    const author = blogData.author
    const createdAt = Date.now()
    const sql = `
        insert into blogs (title, content ,author ,createdAt) values ('${
     title}', '${
     content}', '${
     author}', ${
     createdAt});
    `
    return execSQL(sql).then(res => {
   
        return {
    id: res.insertId}
    })
}

src\routes\blog.js

    //获取接口详情 g根据id获取内容
    if(method === "GET" && req.path === "/api/blog/detail"){
   
        return getDetail(id).then( res => {
   
            return new SuccessModel(res)
        })
    }
    //新建接口
    if(method === "POST" && req.path === "/api/blog/new"){
   
        return createNewBlog(postData).then(res => {
   
            return new SuccessModel(res)
        })
    }
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
5天前
|
关系型数据库 MySQL 网络安全
DBeaver连接MySQL提示Access denied for user ‘‘@‘ip‘ (using password: YES)
“Access denied for user ''@'ip' (using password: YES)”错误通常与MySQL用户权限配置或网络设置有关。通过检查并正确配置用户名和密码、用户权限、MySQL配置文件及防火墙设置,可以有效解决此问题。希望本文能帮助您成功连接MySQL数据库。
18 4
|
21天前
|
安全 关系型数据库 MySQL
【赵渝强老师】MySQL的连接方式
本文介绍了MySQL数据库服务器启动后的三种连接方式:本地连接、远程连接和安全连接。详细步骤包括使用root用户登录、修改密码、创建新用户、授权及配置SSL等。并附有视频讲解,帮助读者更好地理解和操作。
|
2月前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
20天前
|
SQL 关系型数据库 MySQL
12 PHP配置数据库MySQL
路老师分享了PHP操作MySQL数据库的方法,包括安装并连接MySQL服务器、选择数据库、执行SQL语句(如插入、更新、删除和查询),以及将结果集返回到数组。通过具体示例代码,详细介绍了每一步的操作流程,帮助读者快速入门PHP与MySQL的交互。
34 1
|
22天前
|
SQL 关系型数据库 MySQL
go语言数据库中mysql驱动安装
【11月更文挑战第2天】
36 4
|
2月前
|
存储 关系型数据库 MySQL
Mysql(4)—数据库索引
数据库索引是用于提高数据检索效率的数据结构,类似于书籍中的索引。它允许用户快速找到数据,而无需扫描整个表。MySQL中的索引可以显著提升查询速度,使数据库操作更加高效。索引的发展经历了从无索引、简单索引到B-树、哈希索引、位图索引、全文索引等多个阶段。
66 3
Mysql(4)—数据库索引
|
29天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
163 1
|
1月前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
89 2
|
1月前
|
存储 关系型数据库 MySQL
MySQL vs. PostgreSQL:选择适合你的开源数据库
在众多开源数据库中,MySQL和PostgreSQL无疑是最受欢迎的两个。它们都有着强大的功能、广泛的社区支持和丰富的生态系统。然而,它们在设计理念、性能特点、功能特性等方面存在着显著的差异。本文将从这三个方面对MySQL和PostgreSQL进行比较,以帮助您选择更适合您需求的开源数据库。
125 4
|
16天前
|
运维 关系型数据库 MySQL
安装MySQL8数据库
本文介绍了MySQL的不同版本及其特点,并详细描述了如何通过Yum源安装MySQL 8.4社区版,包括配置Yum源、安装MySQL、启动服务、设置开机自启动、修改root用户密码以及设置远程登录等步骤。最后还提供了测试连接的方法。适用于初学者和运维人员。
125 0