Node.js--》简易资金管理系统后台项目实战(后端)

news2024/11/18 2:47:38

        今天开始使用 node + vue3 + ts搭建一个简易资金管理系统的前后端分离项目,因为前后端分离所以会分两个专栏分别讲解前端与后端的实现,后端项目文章讲解可参考:前端链接,我会在前后端的两类专栏的最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关注本专栏,学习更多前端node知识,然后开篇先简单介绍一下本项目用到的技术栈都有哪几个方面(阅读本文章能够学习到的技术):

node:基于Chrome V8引擎的开源、跨平台的JavaScript运行环境。

express:基于node.js的Web应用框架,帮助开发者快速构建可靠、高效的Web应用程序。

pm2:针对node应用生产环境进程管理工具,可帮助简化应用程序部署运行和监视等工作。

MongoDB:面向文档的NoSQL数据库系统,它可以灵活地存储非结构化数据。

Apifox:易用界面和功能,帮助开发人员和团队更高效地创建、设计和管理 RESTful API。

jwt:用于定义在网络上传输的信息安全可验证和可信任的方式,用于身份验证和授权机制。

目录

express搭建服务器

连接MongoDB数据库

搭建注册接口

搭建登录接口

获取登录信息

添加和获取信息

编辑和删除信息


express搭建服务器

首先我们需要创建一个文件夹用于存放后端项目,然后将文件夹拖到编辑器vscode当中,接下来需要打开终端执行 npm init 初始化package.json文件,相关步骤如下:

接下来开始装载 express 框架,终端执行如下命令:

npm install express

接下来我们在项目文件夹中创建入口文件 server.js 然后开始使用 express 框架:

const express  = require("express")
const app = express()
// 设置路由
app.get('/', (req,res) =>{
  res.send('hello world')
})
// 设置端口号
const post = process.env.PORT || 8080
app.listen(post, () => {
  console.log(`Server is running on port ${post},url: http://127.0.0.1:${post}`)
})

为了方便代码的执行,这里我们采用 pm2 进程管理工具进行使用,关于pm2的安装和具体的使用教程可以参考我之前的文章:深入理解 PM2:Node.js 应用部署和管理利器 ,为了方便简介,这里我们可以直接在package.json文件中设置一下我们的命令,如 下:

pm2进程管理工具是不会随着你将终端关闭而停止运行的,如果是第一次运行项目的话,可以根据我们上面设置的命令执行:npm run start 即可,如果想关闭项目的话,执行 pm2 stop 加项目名称就行了,如果实时查看日志,执行 pm2 log 即可,具体的实操自己体会,这里不再赘述。

接下来我们打开我们本地的 5000 端口,可以看到我们后端运行的项目了:

连接MongoDB数据库

接下来我们在本地创建一个 MongoDB数据库,用来后面后端编写相应接口所需要存放的数据,如果不了解MongoDB的朋友推荐可以参考一下我之前的文章:MongoDB数据库 ,接下来我们需要开始执行 node 连接MongoDB数据库了。

启动MongoDB服务

点击win键输入cmd,点击以管理员身份运行

执行 net start MongoDB 命令,运行MongoDB数据库服务:

创建MongoDB数据库

使用 Navicat 图形化管理工具,创建数据库。点击新建连接,选择 MongoDB

配置相应参数,连接直接默认即可,一般情况下,我们连接只需要连接主库查数据,所以选择独立的这个连接方式就可以,填写好常规参数可以点击测试连接是否正常,即可连接!因为是个人测试嘛,使用的是本地的localhost:

出现如下界面说明连接成功,我们直接点击确定即可。 

注意:进入到数据库之后,我们删除默认的数据库,重新创建一个名为 node_fund 名称的数据库

连接MongoDB数据库

接下来我们需要借助vscode工具来连接mongodb数据库,首先终端执行如下命令安装相应的包:

npm install mongoose

安装完成之后,我们在server.js中执行如下命令进行验证是否连接数据库成功:

// 引入 express 服务框架
const express  = require("express")
// 引入 mongoose 数据库服务
const mongoose = require("mongoose")
const app = express()
// 连接数据库的 URL
const MongoUrl = 'mongodb://localhost:27017/node_fund'
// 连接数据库
mongoose.connect(MongoUrl).then(() => {
  console.log('连接成功')
}).catch((err) => {
  console.log('连接失败', err)
})
// 设置路由
app.get('/', (req,res) =>{
  res.send('hello world')
})
// 设置端口号
const post = process.env.PORT || 5000
app.listen(post, () => {
  console.log(`Server is running on port ${post},url: http://127.0.0.1:${post}`)
})

当我们执行 pm2 log 查看日志的时候可以看到,我们的终端打印了连接成功的字眼:

当我们更改 MongoUrl 的默认url的时候,终端就会打印出相应的连接失败以及相应报错:

搭建注册接口

接下来我们需要开始搭建真正的接口了,首先我们需要在项目根目录下创建相关文件夹编写接口:

在编写接口之前,我们需要先安装 body-parser ,为了方便地在node中处理 POST 请求的请求体数据,从而更轻松地进行数据处理和响应,终端执行如下命令进行安装:

npm install body-parser

安装完成之后,我们还需要在入口文件 server.js 中使用它来解析请求体:

const express  = require("express")
const bodyParser = require("body-parser")
const app = express()

// 使用 body-parser 中间件
app.use(bodyParser.urlencoded({ extended: false })) // 解析表单数据
app.use(bodyParser.json()) // 解析 JSON 格式的请求体

插件安装完成之后,我们还需要在项目根目录下创建一个models文件,用于存放从数据库获取数据所需要的数据及其相应的类型,这里需要借助 Schema 属性:

const mongoose = require('mongoose')

// 定义模式,用于指定数据的结构和字段。
const Schema = mongoose.Schema
// 使用Schema变量来定义具体的数据模型
const userSchema = new Schema({
  name: {
    type: String,
    required: true
  },
  email: {
    type: String,
    required: true
  },
  password: {
    type: String,
    required: true
  },
  avatar: {
    type: String,
  },
  identity: {
    type: String,
    required: true
  },
  date: {
    type: Date,
    default: Date.now
  },
})
/** 
 * 创建了一个名为users的MongoDB集合,并使用userSchema指定了集合中文档的结构
 * 将前一步创建的模型赋值给一个变量User,使其成为我们操作users集合的接口。
 */
module.exports = User = mongoose.model('users', userSchema)

定义完相应的注册登录接口所需类型之后,接下来就需要正式在user.js文件中编写相应的注册接口,代码如下:

// 用户登录 / 注册相关的内容
const express = require('express')
const router = express.Router()

// 引入具体的数据类型
const User = require('../../models/User')

/**
 * 注册接口
 * POST api/users/register 
 */
router.post('/register', (req,res) => {
  // 查询数据库中是否拥有邮箱
  User.findOne({ email: req.body.email }).then((user) => {
    if (user) {
      return res.status(400).json({ email: '邮箱已被注册' })
    } else {
      // 注册新邮箱
      const newUser = new User({
        name: req.body.name,
        email: req.body.email,
        avatar,
        password: req.body.password,
        identity: req.body.identity
      })
    }
  })
})

module.exports = router

因为密码是至关重要的数据,所以这里我们需要对用户的密码进行一个加密,终端执行如下命令:

npm install bcrypt

下载成功之后,导入 bcrypt 然后对数据进行相应的hash加密,修改后的代码如下:

// 用户登录 / 注册相关的内容
const express = require('express')
const router = express.Router()
const bcrypt = require("bcrypt")

// 引入具体的数据类型
const User = require('../../models/User')

/**
 * 注册接口
 * POST api/users/register 
 */
router.post('/register', (req,res) => {
  // 查询数据库中是否拥有邮箱
  User.findOne({ email: req.body.email }).then((user) => {
    if (user) {
      return res.status(400).json({ email: '邮箱已被注册' })
    } else {
      // 注册新邮箱
      const newUser = new User({
        name: req.body.name,
        email: req.body.email,
        avatar,
        password: req.body.password,
        identity: req.body.identity
      })
      // 进行密码加密
      bcrypt.genSalt(10, (err, salt) => {
        bcrypt.hash(newUser.password, salt, (err, hash) => {
          if (err) throw err
          newUser.password = hash
          newUser.save().then(user => res.json(user)).catch(err => console.log(err))
        })
      })
    }
  })
})

module.exports = router

写完相应代码之后,这里我们还需要将该路由代码在入口文件 server.js 中进行一个引入:

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

// 引入user.js
const users = require('./routes/api/user')
// 使用routes
app.use('/api/users', users)

接下来我们需要借助接口测试工具 Apifox 进行相应的接口测试,如果不了解 Apifox 的朋友,可以参考我之前的文章:Apifox:详细使用教程,带你轻松拿捏 ,为了便于测试,我们先把 avatar 图像参数先删除,先测试一下其他参数。当我们输入相关路径及其参数点击发送之后:

当我们再次点击发送之后,就会出现当前的邮箱已被注册,符合逻辑规律:

接下来我们需要处理 avatar 头像参数,需要将图片数据保存到数据库中,可以使用 Buffer 对象来处理二进制数据,并将其存储为 Buffer 类型的字段。这里我们需要安装如下的这个插件进行处理

npm install multer

然后代码进行如下方式的修改:

// 用户登录 / 注册相关的内容
const express = require('express')
const router = express.Router()
const bcrypt = require("bcrypt")
const multer = require('multer');
const jwt = require("jsonwebtoken")
const passport = require("passport")

// 引入具体的数据类型
const User = require('../../models/User')

// 配置 multer
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, 'public/images') // 设置图片保存的路径
  },
  filename: function (req, file, cb) {
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9)
    cb(null, file.fieldname + '-' + uniqueSuffix + '.' + file.mimetype.split('/')[1]) // 设置图片的文件名
  }
})
const upload = multer({ storage: storage })

/**
 * 注册接口
 * POST api/users/register 
 */
router.post('/register', upload.single('avatar'), (req,res) => {
  // 查询数据库中是否拥有邮箱
  User.findOne({ email: req.body.email }).then((user) => {
    if (user) {
      return res.status(400).json('邮箱已被注册')
    } else {
      const avatarUrl = req.protocol + '://' + req.get('host') + '/images/' + req.file.filename;
      // 注册新邮箱
      const newUser = new User({
        name: req.body.name,
        email: req.body.email,
        avatar: avatarUrl, // 使用上传的图片的文件名作为 avatar 字段的值
        password: req.body.password,
        identity: req.body.identity
      })
      // 进行密码加密
      bcrypt.genSalt(10, (err, salt) => {
        bcrypt.hash(newUser.password, salt, (err, hash) => {
          if (err) throw err
          newUser.password = hash
          newUser.save().then(user => res.json(user)).catch(err => console.log(err))
        })
      })
    }
  })
})

接下来进行Apifox接口测试之后,得到的结果如下:

如果想访问图片资源的话,这里我们还需要在入口文件出将静态资源设置为可访问:

app.use(express.static('public'));

当我们打开 Navicat 可视化管理工具之后,找到我们创建的对应数据,打开集合就能看到我们在测试工具Apifox生成的数据,在数据库当中也呈现出来了:

搭建登录接口

和注册接口一样,原理就是我们拿到用户请求过来的email和password之后,进行数据库的一个查询,如果查询当前数据库没有用户传递过来的email数据,就返回用户不存在,否则的话就开始比较密码进行相应的匹配得到对应的结果:

/**
 * 登录接口
 * POST api/users/login
 */
router.post('/login', (req,res) => {
  const email = req.body.email
  const password = req.body.password
  // 查询数据库
  User.findOne({ email }).then(user => {
    if (!user) {
      return res.status(404).json({ email: '用户不存在!' })
    }
    // 密码匹配
    bcrypt.compare(password, user.password).then(isMatch => {
      if (isMatch) {
        res.json({ msg: 'success' })
      } else {
        return res.status(400).json({ password: '密码错误!' })
      }
    })
  })
})

比如说我们拿一下数据库当中真实存在的数据进行测试一下,得到的结果肯定是 success :

如果说我们随便输入密码或者用户名可能不是success了,举个例子改一下密码:

接下来我们需要给登录成功的 success 返回相应的token,终端执行如下命令按照相应包:

npm install jsonwebtoken

在导入 const jwt = require("jsonwebtoken") 之后,在密码匹配的地方执行jwt设置一个标记,过期时间我们设置了一个小时,然后token的话和前面的字符串进行了一个拼接:

在Apifox接口测试工具进行测试得到的相应结果如下:

获取登录信息

登录的接口写完,我们还需要写一个获取登录信息的接口函数,首先判断我们是否登录成功即需要验证一下我们当前登录的token是否存在且正确,所以这里我们需要借助 passport-jwt等工具进行:

npm install passport-jwt passport

接下来我们需要在入口文件 server.js 中初始化passport,然后将逻辑代码单独抽离出来:

// passport初始化
app.use(passport.initialize())
// 引入passport逻辑功能代码
require("./config/passport")(passport)

在抽离出来的config文件夹下的passport文件,这里我们开始书写真正的token校验:

const JwtStrategy = require("passport-jwt").Strategy
ExtractJwt = require("passport-jwt").ExtractJwt
const mongoose = require("mongoose")
const User = mongoose.model("users")

const opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken()
opts.secretOrKey = 'secret'

module.exports = passport => {
  passport.use(new JwtStrategy(opts, (jwt_payload, done) => {
    User.findById(jwt_payload.id).then(user => {
      if (user) {
        return done(null, user)
      }
      return done(null, false)
    }).catch((err) => {
      console.log(err)
    })
  }))
}

在user.js路由文件夹下,我们开始书写获取登录信息的接口了,这里我们仍然将图片资源进行应该路径的拼接:

/**
 * 获取登录信息
 * POST api/users/current
 */
router.get('/current', passport.authenticate("jwt", { session: false }), (req,res) => {
  res.json({
    id: req.user.id,
    name: req.user.name,
    email: req.user.email,
    avatar: req.user.avatar,
    identity: req.user.identity
  })
})

通过Apifox得到的结果如下:

添加和获取信息

注册和登录的功能写完之后,接下来需要我们开始编写添加和获取信息的接口,这里我们要在api文件夹下再新建一个 profile 文件,以及在模型models文件夹下新建 Profile文件:

创建的两个文件都要在入口文件 server.js 中进行引入:

// 引入profile.js
const profile = require('./routes/api/profile')
// 使用routes
app.use('/api/profile', profile)

接下来我们先编写数据模型文件的代码,具体代码如下:

const mongoose = require('mongoose')

// 定义模式,用于指定数据的结构和字段。
const Schema = mongoose.Schema
// 使用Schema变量来定义具体的数据模型
const ProfileSchema = new Schema({
  type: {
    type: String,
  },
  describe: {
    type: String,
  },
  income: {
    type: String,
    required: true
  },
  expend: {
    type: String,
    required: true
  },
  cash: {
    type: String,
    required: true
  },
  remark: {
    type: String,
  },
  date: {
    type: Date,
    default: Date.now
  },
})
/** 
 * 创建了一个名为users的MongoDB集合,并使用userSchema指定了集合中文档的结构
 * 将前一步创建的模型赋值给一个变量User,使其成为我们操作users集合的接口。
 */
module.exports = Profile = mongoose.model('profile', ProfileSchema)

根据上面讲解的编写接口的经验,我们很容易就写出添加和获取信息的即可,如下:

// 用户登录 / 注册相关的内容
const express = require('express')
const router = express.Router()
const passport = require("passport")

// 引入具体的数据类型
const Profile = require('../../models/Profile')

/**
 * 创建信息接口
 * POST api/profiles/add
 */
router.post("/add", (req, res, next) => {
  passport.authenticate("jwt", { session: false }, (err, user, info) => {
    // 判断错误情况
    if (err) return res.status(500).json({ error: "Internal Server Error" });
    if (!user) return res.status(401).json({ error: "Unauthorized" });
    const profileFields = {};
    if (req.body.type) profileFields.type = req.body.type;
    if (req.body.describe) profileFields.describe = req.body.describe;
    if (req.body.income) profileFields.income = req.body.income;
    if (req.body.expend) profileFields.expend = req.body.expend;
    if (req.body.cash) profileFields.cash = req.body.cash;
    if (req.body.remark) profileFields.remark = req.body.remark;
    new Profile(profileFields).save().then((profile) => {
        res.json(profile);
      }).catch(err => {
        res.status(500).json(err);
      })
  })(req, res, next);
})

/**
 * 获取所有信息
 * POST api/profiles
 */
router.get( '/', passport.authenticate('jwt', { session: false }), (req, res) => {
  Profile.find().then((profiles) => {
      if (!profiles || profiles.length === 0) return res.status(404).json({ error: '数据为空!' })
      const profileData = { profiles: profiles }
      res.json(profileData)
    }).catch((err) => res.status(404).json(err));
  }
);
module.exports = router

获取单个信息的接口也很简单,只需要在路径拼接上id,id后面前端传递给我们即可:

/**
 * 获取单个信息
 * POST api/profiles/:id
 */
router.get('/:id', passport.authenticate('jwt', { session: false }), (req, res) => {
  Profile.findOne({ _id: req.params.id }).then((profile) => {
    if (!profile) return res.status(404).json({ error: '数据为空!' });
    res.json(profile);
  }).catch((err) => res.status(404).json(err));
});

通过Apifox测试的结果如下:

编辑和删除信息

编辑信息接口和添加信息接口写法大体一致,如下:

/**
 * 编辑信息接口
 * POST api/profiles/edit
 */
router.post(
  "/edit/:id", 
  passport.authenticate("jwt", { session: false }), 
  (req, res) => {
    const profileFields = {};
    if (req.body.type) profileFields.type = req.body.type;
    if (req.body.describe) profileFields.describe = req.body.describe;
    if (req.body.income) profileFields.income = req.body.income;
    if (req.body.expend) profileFields.expend = req.body.expend;
    if (req.body.cash) profileFields.cash = req.body.cash;
    if (req.body.remark) profileFields.remark = req.body.remark;
    Profile.findOneAndUpdate(
      { _id: req.params.id },
      { $set: profileFields },
      { new: true }
    ).then(profile => res.json(profile))
  }
)

删除信息的接口也很简单:

/**
 * 删除信息
 * POST api/profiles/:id
 */
router.delete(
  '/delete/:id', 
  passport.authenticate('jwt', { session: false }), 
  (req, res) => {
    Profile.findOneAndDelete({ _id: req.params.id }).then(profile => {
      res.json(profile);
    }).catch(err => res.status(404).json('删除失败'));    
});

表示删除成功!

ok!后端的一些基础代码已经写完了,下一篇将借助这些接口开始前端页面的书写了,等前后端项目全部写完,我再将源码开源出来,敬请期待!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1121115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

arduino 记录

​ 知识整理 Arduion U8G2简要说明 u8g2显示分为全页显示与分页显示和U8X8的无ram显示 全页显示需要单片机提供1024字节的ram,分页显示分为需要256字节和125字节的ram U8X8不需要ram,但不可画图,只能显示文字 全页使用 clearbuff senddbuff 分页…

javaweb中的转发与重定向

2023.10.22 在一个web应用中应该如何完成资源的跳转? 转发重定向 转发和重定向有什么区别? 转发是由服务器端进行的页面跳转,而重定向是由浏览器端进行的页面跳转。 ①代码上的区别: 转发: // 获取请求转发器对象…

Sublime Text forMac/Windows:高效代码编辑器的终极指南

你是否曾为寻找一款高效、强大且用户友好的代码编辑器而感到困扰?现在,让我们一起探索Sublime Text的魅力。Sublime Text是一款流行的代码编辑器,以其强大的功能和简洁的设计赢得了开发者的喜爱。本文将带你了解Sublime Text的各项特性&#…

1、VMware虚拟机及网络配置

一、VMware虚拟网络编辑器 1、选择NAT模式并配置子网 2、进入NAT设置,配置网关 3、宿主机网络适配器设置 二、创建虚拟机 在这里插入图片描述 三、开启虚拟机,安装操作系统 在该网段内配置静态ip,指定网关为前面NAT配置的网关地址…

游戏找不到msvcr100dll怎么办,分享5个有效修复方法

一、游戏找不到msvcr100dll会造成的困扰 在当今的数字时代,电子游戏已经成为了我们生活中不可或缺的一部分。它们为我们提供了娱乐和放松的机会,让我们能够在忙碌的生活中找到乐趣。然而,当我们在玩游戏时,可能会遇到一些技术问题…

【性能测试】MySQL慢查询原因/排查思路+SQL优化与性能定位思路...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 Mysql慢查询现象、…

十四天学会C++之第八天:文件操作

1. 文件的打开和关闭 文件操作的基本概念。打开文件:使用fstream库打开文件以供读写。关闭文件:确保文件在使用完毕后正确关闭。 文件的打开和关闭:C 文件操作入门 在C编程中,文件操作是一项重要的任务,可以读取和写…

Java日志系统之Log4j2

Log4j2介绍 Log4j2是Log4j的升级版,参考Logback的优秀设计并修复了一些问题。主要优点有: 异常处理,在logback中,Appender中的异常不会被应用感知到,但是在log4j2中,提供了一些异常处理机制。性能提升&am…

Java高级编程----集合

集合 集合概述Collection接口List接口简介ArrayList集合Set接口简介Hash Set接口简介Map接口简介TreeMap集合Properties集合 集合概述 为了在程序中可以保存数目不确定的对象,Java提供了一系列特殊类,这些类可以存储任意类型的对象,并且长度…

使用java mail SMTPTransport发送邮箱,本地秒到,一上服务器就20-30s左右,生产环境直接发送失败。

一、代码 pom文件 <dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!--pom.xml添加javax.mail的引用&#xff0c;或者项目引入…

【最短路径算法】一文掌握Dijkstra算法,详解与应用示例+代码

目录 1 Dijkstra算法 2 Dijkstra算法的步骤 3 Dijkstra算法python实现 4 Dijkstra算法应用示例详解 1 Dijkstra算法 Dijkstra算法&#xff08;迪杰斯特拉算法&#xff09;是一种用于在加权图中查找从一个起始节点到所有其他节点的最短路径的算法。该算法最初由荷兰计算机科…

JVM 基础篇:类加载器

一.了解JVM 1.1什么是JVM JVM是Java Virtual Machine&#xff08;Java虚拟机&#xff09;的缩写&#xff0c;是一个虚构出来的计算机&#xff0c;是通过在实际的计算机上仿真模拟计算机功能来实现的&#xff0c;JVM屏蔽了与具体操作系统平台相关的信息&#xff0c;Java程序只需…

通讯录和内存动态管理

目录 (通讯录)动态增长版 实现效果 找单身狗 题目 源码 思路 三个内存函数的模拟实现 模拟实现strncpy 模拟实现strncat 模拟实现atoi (通讯录)动态增长版 该版本通讯录在原版的基础上增加了检查容量函数&#xff0c;实现了通讯录的动态…

在PS中轻松实现肖像磨皮,感受Imagenomic Portraiture 4的强大

每个人都希望自己的肖像照片看起来漂亮、清晰并且光滑。然而&#xff0c;在处理肖像照片时&#xff0c;要达到这些效果通常需要花费大量时间和精力。如果您正在寻找一种简单快捷的方法来优化您的肖像照片&#xff0c;那么Imagenomic Portraiture 4插件将是您的理想选择。 Imag…

单接口的批量测试如何实现

一、痛点&#xff1a;一条测试数据对应一个测试方法 前面的章节中我们已经写代码实现了登录接口的处理调用&#xff0c;但是一个接口往往是需要多条测试用例才能完整的覆盖到每一种情况&#xff0c;针对于单接口多条测试用例需要执行的情况&#xff0c;该如何处理呢&#xff0…

uboot移植之mx6ull_alientek_nand.h文件详解一

一. 简介 mx6ull_alientek_nand.h文件是 开发板的 uboot的一个配置文件。每个开发板都有一个 .h的配置文件。 mx6ull_alientek_nand.h文件其实是 之前针对正点原子ALPHA开发板移植的 Uboot配置文件。 本文简单分析一下 针对正点原子ALPHA开发板的 配置文件&#xff1a; mx6u…

STL模拟实现—vector

引言&#xff1a;本篇文章主要是模拟实现vector&#xff0c;但不同于stl中vector的成员变量都是迭代器&#xff0c;这个自定义的vector是一个T* 的数据变量和一个int类型的size和int类型的capacity。&#xff08;有时间再写三个迭代器的版本吧&#xff01;&#xff09; 首先来看…

Redis学习(第八章缓存策略)

目录 RdisExample 课程介绍 1.Redis介绍 2.Redis 安装 3. Redis的数据结构 4. Redis缓存特性 5. Redis使用场景 6. Redis客户端-Jedis 7. Jedis Pipeline 8. Redis缓存策略 学习资料 QA 相关问题 http, socket ,tcp的区别 RdisExample 项目代码地址&#xff1a;htt…

Leetcode—104.二叉树的最大深度【简单】

2023每日刷题&#xff08;六&#xff09; Leetcode—104.二叉树的最大深度 递归实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/int maxDepth(struct TreeNode* root){…

2017年高热度编程语言简介

世上语言千千万&#xff0c;我却独爱这一种!”这句话用来形容程序员和编程语言之间的爱恨情仇实在是再精准不过了。根据GitHub 2016年的开源报告&#xff0c;其上所有开源项目共包含了316种编程语言&#xff0c;这是一个什么概念呢?举个例子来说&#xff0c;世界上共有226个国…