万字长文之 Serverless 实战详细指南

news2024/11/18 7:51:28

目录

前言

简易博客系统功能概要

云函数的初始化与基础配置

Tencent Serverless Toolkit for VS Code

数据库选择和设计

数据库选择

数据库设计

云函数自定义域名与 API 网关映射

域名解析

API 网关映射

云函数中的路由设计

云函数中的代码组织

Controller

Services

Model

View

小结


前言

Serverless = Faas (Function as a service) + Baas (Backend as a service)

Serverless 让我们更专注于业务开发,一些常见的服务端问题, Serverless 都帮我们解决了:

  • Serverless 不需要搭建服务端环境, 下发环境变量,保持各个机器环境一致 (Serverless 的机制天然可复制)

  • Serverless 不需要预估流量, 关心资源利用率, 备份容灾,扩容机器 (Serverless 可以根据流量动态扩容,按真实请求计费)

  • Serverless 不需要关心内存泄露,(Serverless 的云函数服务完后即销毁)

  • Serverless 有完善的配套服务,如云数据库,云存储,云消息队列,云音视频和云 AI 服务等,利用好这些云服务,可以极大得减少我们的工作量

        以上前三点是 Faas 的范畴,第四点是 Baas 的范畴。简单来讲,Serverless 可以理解为有个系统,可以上传或在线编辑一个函数,这个函数的运行环境由系统提供。来一个请求,系统就自动启动一个函数进行服务,我们只需要写函数的代码。提交后,系统根据流量自动扩缩容,而函数里可以调用各种现有的云服务 api 来简化我们的开发与维护成本。

        看了很多关于 Serverless 的文章,大部分都在讲架构,讲 serverless 本身的实现。本篇就以简单明了的例子阐述一个简易博客系统在腾讯云 Serverless 中的落地,期间只会涉及 Faas 和 Baas 的实践部分。

        让我们开始吧~

简易博客系统功能概要

图片

        如上时序图所示,本次实现的简易博客系统,只有博客列表页和博客内容页,不涉及评论,登录。侧重于 Serverless 落地相关的内容,如云函数本身怎么编写,怎么在本地开发,怎么跟自定义域名关联,怎么访问云 MySQL。云函数内的代码,如 Router、Controller、Service、Model 和 View 等怎么组织。

        带着这些疑问, 让我们开始吧~

云函数的初始化与基础配置

访问 https://cloud.tencent.com/product/scf,点击立即使用进入云函数:

图片

        为了让你不感到畏惧,先交个底,腾讯云函数每月有 100 万次调用的免费额度,个人学习使用完全够了。

        好的,我们继续~

        在点击上图的 "立即使用" 后,我们可以看到云函数的概览界面:

图片

点击左侧的函数服务,在出现的界面中,点击新建:

图片

        出现了下方截图的这个页面,输入函数名,选择语言,可以从函数模板中选择一个初始化。这里选了右下角这个 "国庆 SCF 运营推广活动 Demo"。ps:注意这里有很多模板,比如访问数据库,返回页面,图像压缩,视频转码,文件合并等等,降低了我们的入门成本。

图片

选择好模板后,点击下一步,出现的这个界面,设置环境变量和网络环境。

图片

        点击完成,我们的云函数就生成啦。来看一下效果,虽然是云函数,但这里不止一个文件哦,是可以 以多个文件的形式组织起来的:

图片

        细看代码,做的事情很简单,根据云函数标准,暴露了一个 main_handler。里边读取了一个 html 页面模板,通过 render 函数将 html 模板 + 数据解析为 html 字符串,最后返回。

        那我们要怎么才能访问到这个云函数呢?

        答案就是配置触发方式了, 我们将触发方式配置成 API 网关触发, 设置如下:

图片

这里解释一些图中的概念:

  • 定时触发:通常用于一些定时任务,如定时发邮件,跑数据,发提醒等。

  • COS 是腾讯云存储,比如图片,视频就可以用 COS 存储。COS 触发是指文件上传到 COS 后,会触发这个函数,此时这个函数可以用来压缩图片,做视频转码等等。

  • Ckafka 触发,当 Ckafka 消息队列有新数据时触发。

  • API 网关触发,就是有请求过来时,才触发这个函数。

这里我们选择 API 网关触发,也就是有请求过来时,才触发这个函数。

保存后,我们就能看到云函数的访问路径了:

图片

这里贴一下我例子中的访问链接,大家可以体验一下~

        https://service-r3uca4yw-1253736472.gz.apigw.tencentcs.com/release/test

以上就是我们对云函数的初步认识,接下来我们一步步深入,带你打造一个简易博客系统。

Tencent Serverless Toolkit for VS Code

        首先,我们需要一个本地开发环境,虽然线上编辑器的体验与 vscode 已经比较相近了,但毕竟本地代码编辑经过我们配置,还是更好用的。那我们在本地修改了代码,怎么发布云函数呢?

        以 VSCode 为例,我们需要安装 "Tencent Serverless Toolkit for VS Code",可以在 VSCode 的插件里搜索安装,插件首页会有详细地安装说明,这里就不再赘述。

插件界面如图:

图片

安装完后,左侧会多一个云函数的图标。通过这个插件,你可以:

  • 拉取云端的云函数列表,并触发云函数在云端运行。

  • 在本地快速创建云函数项目。

  • 在本地开发、调试及测试您的云函数代码。

  • 使用模拟的 COS、CMQ、CKafka、API 网关等触发器事件来触发函数运行。

  • 上传函数代码到云端,更新函数配置。

        通常前端的代码,需要打包,执行 npm install、npm run build 等。云端函数没有提供这个环境,我们可以在本地打包后,通过这个插件发布代码。当然,我们还可以通过持续集成工具,运行 cli 来发布,这个就不展开说了。

数据库选择和设计

数据库选择

        这里选择的是腾讯云 MySQL 基础版最低配,一个月才 29 元~。当然,自己搭建数据库对外暴露,用于学习也是可以的。不过如果后期要长期使用,为了方便维护和确保数据稳定,建议选择云 MySQL。云 MySQL 不需要我们关心安装和数据因机器挂了而丢失的问题。开箱即用也是 Baas 的特点。

        注意到里边选择的网络是 Default-VPC、Default-Subnet,需要保持跟云函数一致,不然云函数访问不到 MySQL。如图:

图片

激活云 MySQL 后,这里可以看到内网 ip 和端口,云函数可以通过这个 ip 和端口访问到 MySQL:

图片

数据库设计

        因为是一个简易的博客系统,不涉及登录和评论。在满足数据库设计第三范式的基础上,我们只需要设计一张表即可,即博客表本身:

字段名字段类型
id主键
title标题
content文章内容
createdAt创建时间
updatedAt修改时间

        因为我们后边会使用 MySQL 的 Node.js ORM 框架 Sequelize 来操作数据库,数据库表的创建是自动完成的,这里我们就不再说明啦~

        后边会有 Sequelize,还有怎么连接,操作数据库的介绍~

云函数自定义域名与 API 网关映射

域名解析

        前面说到,云函数创建完配置好 API 网关触发器后,就可以在外网访问了,但是默认的 url 完全无法记忆,不利于传播,我们需要一个自定义域名。关于域名如何购买这里就不展开了,大家可以参照官方文档进行购买,便宜的才 5 块钱一年 ~

官方文档: 

        https://cloud.tencent.com/document/product/242/9595

        这里给大家介绍,怎么给云函数绑定自定义域名。在购买域名后,我们需要在域名解析列表里添加域名解析:

图片

        如下图,将 @ 和 www CNAME 到我们的云函数域名,相当于是给云函数的域名起了个别名,访问自定义域名,就可以访问到云函数域名经过解析后的 ip:

图片

        云函数解析细节 注意:记录值只需要填写云函数的域名即可,不需要填路径,也不需要填协议。

API 网关映射

        光是将自定义域名解析到云函数域名是不够的,我们还要映射路径。我们打开 API 网关的服务,点击我们的云函数服务名,打开自定义域名,点击新建:

图片

按照截图中操作后,我们就可以在外网以自己的域名访问到云函数啦~

这里放上本篇文章最终实现的简易博客地址: https://www.momentfly.com/

云函数中的路由设计

        正如我们前面提到的,实现的简易博客系统有两个页面,可以通过两个云函数来对应两个页面,但这种实现不优雅,因为代码复用不了。比如我们写的一些处理页面的公共方法,就得在两个函数里都实现一遍。而且 node_modules 在两个云函数里都得存在,浪费空间。

        所以我们得在一个函数里,将两个页面的代码组织起来,最容易想到的是写一个简单的判断,if 路径为 /,则返回博客列表页。else if 路径为 /post,则返回博客内容页。但这还是不优雅,要获取路径,再写一堆 if else 来做路由,不是很好维护。而且如果要扩展,还得增加 get、post 等请求的判断,再加上路径上的参数也要手工写函数来获取。

        能不能像 Express 或 koa 一样方便地组织代码呢? 答案是肯定的!

        如果对比过 AWS Lambda (亚马逊云 云函数), 会发现腾讯云函数和 AWS Lambda 在入口参数上是一致的,我们可以通过 serverless-http 这个库,实现 koa 的接入。这个库原本是为 AWS lambda 打造的,但可以无缝地在腾讯云函数上使用。

        如上面提到的,云函数的入口代码 main_handler 如下:

exports.main_handler = async (event, context, callback) => {

}

        我们将代码拉到本地,安装 koa、koa-router、serverless-http 后,按照如下方式组织,即可将 koa 无缝接入:

const Koa = require("koa");
const serverless = require("serverless-http");
const app = new Koa();
const router = require('./router');

app
  .use(router.routes())
  .use(router.allowedMethods())

const handler = serverless(app);
exports.main_handler = async (event, context, callback) => {
  return await handler(
    { ...event, queryStringParameters: event.queryString },
    context
  );
}

而我们的 router 文件, 就是 koa 常规的写法了:

const Router = require('koa-router');
const { homeController } = require('../controllers/home')
const { postController } = require('../controllers/post')

const router = new Router();

router
    .get('/', homeController)
    .get('/post', postController)

module.exports = router;

        看到这里,熟悉 koa 的同学已经掌握了该篇的主旨,明白了 Serverless 落地的一种方式。但接下来还是会完整地将这个简易博客系统搭建相关的逻辑讲清楚,感兴趣的同学继续往下看吧~

云函数中的代码组织

        和普通 koa 应用的组织方式一致,为了职责分明,通常会将代码组织为 Router、Controller、Service、Model、View 等。在通过 serverless-http 将 koa 接入进来后,我们的云函数服务组织方式就完全跟传统 koa 应用一致了,我们来看看项目的完整目录:

/blog
├── controllers
|  ├── home
|  |  └── index.js
|  └── post
|     └── index.js
├── index.js
├── model
|  ├── db.js
|  └── index.js
├── package.json
├── router
|  └── index.js
├── services
|  ├── assets
|  |  └── index.js
|  ├── data
|  |  └── index.js
|  ├── home
|  |  └── render.js
|  ├── post
|  |  └── render.js
|  └── response
|     └── index.js
├── template.yaml
├── view
|  ├── github-markdown.css
|  ├── home
|  |  ├── home.css
|  |  └── home.html
|  └── post
|     ├── post.css
|     └── post.html
└── yarn.lock

Controller

        Controller 应该清晰地反应一个请求的处理过程,一些实现细节要封装起来,放在 Service 中,这点在流程复杂的项目中特别重要。

我们两个页面的 Controller 就很简单:

        ·controllers/home/index.js - 博客列表页

const render = require('../../services/home/render');
const { getBlogList } = require('../../services/data')
const { htmlResponse } = require('../../services/response')

exports.homeController = async (ctx) => {
    const blogList = await getBlogList() // 获取数据
    const html = render(blogList) // 数据 + 模板生成 html
    htmlResponse(ctx, html) // 返回 html 的流程
}

        ·controllers/post/index.js - 博客内容页

const render = require('../../services/post/render');
const { getBlogById } = require('../../services/data')
const { htmlResponse } = require('../../services/response')

exports.postController = async (ctx) => {
    const { id } = ctx.query
    const blog = await getBlogById(id)
    const html = render(blog)
    htmlResponse(ctx, html)
}

可以看到,我们的 Controller 都只有三个步骤,即

  1. 获取数据

  2. 数据 + 模板生成 html

  3. 返回 html

我们会在接下来的 Services 里讲清楚这三个步骤的具体实现。

Services

        本篇的简易博客系统,博客列表页和内容页很相似,所以代码也会比较相近,这里就选择博客列表页来讲 Services 啦:

        上边的 Controller 都是先获取数据的,我们来看看 data 这个 services:

/services/data/index.js

const { Blog } = require('../../model')

exports.getBlogList = async () => {
    await Blog.sync({}); // 如果表不存在, 则自动创建, sequelize 的一个特性
    return await Blog.findAll();
}

exports.getBlogById = async (blogId) => {
    await Blog.sync({});
    return await Blog.findOne({
        where: {
            id: blogId,
        }
    })
}

        通过定义好的 Model,也就是 Blog,执行 await Blog.findAll()、await Blog.findOne() 即可获取到博客列表和博客首页。

        数据获取完了,按照上边 Controller 的流程,我们就要执行数据与 html 模板的拼接了,来看 render 的 service:

services/home/render.js

const template = require('art-template');
const marked = require('marked');
const hljs = require('highlight.js');
const { markdownCss, hightlightCss, resolveAssetsFromView } = require('../assets');
const homeHtml = resolveAssetsFromView('./home/home.html');
const homeCss = resolveAssetsFromView('./home/home.css');

module.exports = (blogList) => {
    marked.setOptions({
        highlight: function (code, lang) {
            return hljs.highlight(lang, code).value;
        }
    });

    let html = template.render(homeHtml, {
        blogList: blogList.map((blog) => {
            blog.content = marked(blog.content);
            return blog;
        }),
        markdownCss,
        hightlightCss,
        homeCss,
    })

    return html
}

        这里用了 art-template,是一个高性能模板引擎。

        使用模板引擎来处理 html 模板和数据,没有用 react、vue 的原因是简易博客系统太简单,没必要使用框架。况且这个简易博客系统的初衷侧重于 Serverless 的实践,用 react、vue 或者简单的模板引擎,对 Serverless 实践没有影响。如果换成 react、vue 做 ssr,则需要另外开一个话题阐述了。

  • marked 是将 markdown string 转成 html string 的一个库,如将 # hello 转成 <h1>hello</h1>

  • highlight.js 用于高亮 markdown 中的代码

  • markdownCss、hightlightCss、homeCss 是写好的 css 文件,用 fs 读取出来的文件内容字符串

关键的一句,通过 art-template,将 html 模板,数据 (blogList、css) 渲染成 html

let html = template.render(homeHtml /* 模板 */, { /* 模板变量 */
    // 数据
    blogList: blogList.map((blog) => {
        blog.content = marked(blog.content); // markdown 的处理
        return blog;
    }),
    // 对模板来说, 以下这些也是数据, 只不过数据内容是 css 字符串罢了
    markdownCss,
    hightlightCss,
    homeCss,
});

上面的 markdownCss、hightlightCss、homeCss 是通过 assets 处理出来的,我们来看一下 assets 的处理:

/services/assets/index.js

const fs = require('fs');
const path = require('path');

const hightlightCss = fs.readFileSync(path.resolve(__dirname, '../../node_modules/highlight.js/styles/atom-one-light.css'), {
    encoding: 'utf-8',
})
const markdownCss = fs.readFileSync(path.resolve(__dirname, '../../view/github-markdown.css'), {
    encoding: 'utf-8',
})

const resolveAssetsFromView = (relativePath) => {
    // 辅助函数, 方便从 view 将文件读取为字符串
    const filePath = path.resolve(__dirname, '../../view', relativePath);
    console.log(`filePath: ${filePath}`);
    return fs.readFileSync(filePath, {
        encoding: 'utf-8',
    })
}

module.exports = {
    hightlightCss,
    markdownCss,
    resolveAssetsFromView
}

        通过 fs.readFileSync(),按照 utf-8  的方式读取文件,读取完后连同辅助函数一起暴露出去。

        到了 Controller 的最后一步,即返回 html。我们通过 response service 来实现:

/services/response/index.js

exports.htmlResponse = (ctx, html) => {
    ctx.set('Content-Type', 'text/html');
    ctx.body = html
    ctx.status = 200
}

Model

        上边的 data service,通过 Blog Model 可以轻易的获取数据,那 Blog Model 的实现是怎样的呢? 我们来看一下:

/model/index.js

const { Sequelize, sequelize, Model } = require('./db');

class Blog extends Model { }

Blog.init({
    title: { // 定义 title 字段
        type: Sequelize.STRING, // 字符串类型
        allowNull: false // 不允许为空
    },
    content: {
        type: Sequelize.TEXT('medium'), // mysql 的 MEDIUMTEXT
        allowNull: false // 不允许为空
    }
}, {
    sequelize,
    modelName: 'blog'
});

module.exports = {
    Blog,
}

        我们使用 sequelize 这个 ORM 库来简化 MySQL 的操作,不需要我们手写 SQL 语句,库本身也帮我们做了 SQL 注入的防御。

        Blog.init 初始化了 Blog 这个 Model。id、createdAt、updatedAt 这三个字段不需要我们声明,sequelize 会自动帮我们创建。

来看看 db 的实现

/model/db.js

const Sequelize = require('sequelize');

const sequelize = new Sequelize('blog', 'root', process.env.password, {
    host: '172.16.0.15',
    dialect: 'mysql'
});

const Model = Sequelize.Model;

module.exports = {
    Sequelize,
    sequelize,
    Model,
}

        blog 是数据库的名称,root 是登录的账户,密码存放在环境变量中,通过 process.env.password 获取,也就是前边我们在云函数创建时,填写的环境变量。

View

        这里的 view 层只是 css 和 html 模板,css 就不讲了,这里来看一下 art-template 的模板:

/view/home/home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>serverless blog demo</title>
    <style>
        {{markdownCss}}
        {{hightlightCss}}
        {{homeCss}}
    </style>
</head>
<body>
    <div class="blog-home">
        {{each blogList}}
        <div class="post" onclick="location.href='./post?id={{$value.id}}'">
            <h1>{{$value.title}}</h2>
            <div class="markdown-body">{{@ $value.content}}</div>
        </div>
        {{/each}}
    </div>
</body>
</html>

    {{}} 里是模板变量,前边 render 方法的第二个参数里的字段,就能从 {{}} 中取到。

        以上就是我们简易博客系统的代码逻辑,目前只有两个页面的代码,如果要增加博客创建页面,流程是一致的,增加相关的 Router、Controller、Service 即可。目前笔者是通过腾讯云的数据库操作界面直接写的数据~

        如果要增加评论功能,我们需要新增一个表来存储了,当然后期你可以按照自己的意愿扩展~

实现效果

        https://www.momentfly.com/

图片

小结

        通过搭建简易博客系统,我们了解了 Serverless 的一种实践。期间涉及了如何创建云函数,介绍了本地 VSCode 云函数插件,云函数自定义域名与 API 网关映射,云数据库的创建与连接,云函数的代码组织方式等。整个过程都很轻量,没有太多涉及服务端运维的内容。Serverless 的兴起,会给我们的开发带来很大的便利。后期各大云服务商也必将完善 Serverless 的服务,带来更佳的 DevOps 体验。

最后,让我们一起拥抱 Serverless ,动手实战吧~

完整Demo获取

        Github地址: https://github.com/LuckyWinty/serverless

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

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

相关文章

搭建Django+pyhon+vue自动化测试平台

Django安装 使用管理员身份运行pycharm使用local 1 pip install django -i https://pypi.tuna.tsinghua.edu.cn/simple 检查django是否安装成功 1 python -m django --version 创建项目 1 1 django-admin startproject test cd 切换至创建的项目中启动django项目…

欧拉函数与筛法求欧拉函数

目录 欧拉函数欧拉函数的定义欧拉函数的公式欧拉函数的公式推导欧拉定理典型例题代码实现 筛法求欧拉函数思路分析经典例题代码实现 欧拉函数 欧拉函数的定义 对于任意正整数 n n n,欧拉函数 φ ( n ) φ(n) φ(n) 表示小于或等于 n n n 的正整数中&#xff0c;与 n n n …

企业网盘解析:高效的企业文件共享工具

伴随着信息技术的发展&#xff0c;越来越多的企业选择了基于云存储的企业网盘来进行企业数据存储。那么企业网盘是什么意思呢&#xff1f; 企业网盘是什么意思&#xff1f; 企业网盘&#xff0c;又称企业云盘&#xff0c;顾名思义是为企业提供的网盘服务。除了服务对象不同外&…

【maven】构建项目前clean和不clean的区别

其实很简单&#xff0c;但是百度搜了一下&#xff0c;还是没人能简单说明白。 搬用之前做C项目时总结结论&#xff1a; 所以自己在IDE里一遍遍测试程序能否跑通的时候&#xff0c;不需要clean&#xff0c;因为反正还要改嘛。 但是这个项目测试好了&#xff0c;你要打成jar包给…

全面升级:华为鸿蒙HarmonyOS4正式发布,玩趣个性化,小艺AI升级

8月4日新闻&#xff0c;今天下午&#xff0c;华为正式发布了最新版本的鸿蒙操作系统——HarmonyOS 4&#xff01; 在华为发布会上&#xff0c;鸿蒙HarmonyOS迎来了一系列令人激动的功能升级。其中包括个性化空间、多种生产力工具以及增强的手机AI助手"小艺"。这次更…

Docker入门及安装

文章目录 1.Docker概述:1.什么是docker2.为什么使用docker3.docker优点4.docker资源网址 2.Docker安装1.卸载旧版本dorcker(非必要)2.设置Docker仓库安装docker引擎4.启动验证docker卸载docker 3.Docker底层原理1.docker的结构和基本概念2.docker为什么比虚拟机快 1.Docker概述…

【新版系统架构补充】-传输介质、子网划分

传输介质 双绞线&#xff1a;无屏蔽双绞线UTP和屏蔽双绞线STP&#xff0c;传输距离在100m内 网线安装标准&#xff1a; 光纤&#xff1a;由纤芯和包层组成&#xff0c;分多模光纤MMF、单模光纤SMF 无线信道&#xff1a;分为无线电波和红外光波 通信方式和交换方式 单工…

简单易懂的生鲜蔬果小程序开发指南

随着人们对健康意识的提高&#xff0c;越来越多的人开始注重饮食健康&#xff0c;选择新鲜的果蔬产品。为了满足市场需求&#xff0c;制作一个果蔬配送小程序成为了一个不错的选择。本文将详细介绍如何快速制作一个果蔬配送小程序。 第一步&#xff1a;登录乔拓云网后台&#x…

InterProcessMutex 类的作用和使用

InterProcessMutex 类是Curator框架中的一个分布式锁的实现&#xff0c;用于在分布式环境下实现互斥锁。 InterProcessMutex 的使用步骤如下&#xff1a; 创建 CuratorFramework 客户端实例&#xff0c;并启动客户端连接到 ZooKeeper 服务器。使用 CuratorFramework 的 creat…

leetcode37. 解数独(java)

解数独 解数独题目描述回溯算法代码演示 回溯算法 解数独 难度 困难 leetcode37. 解数独 题目描述 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 1.数字 1-9 在每一行只能出现一次。 2.数字 1-9 在每一列只能出现一次。 3.数字…

2020-2023中国高等级自动驾驶产业发展趋势研究

1.1 概念界定 2020-2023中国高等级自动驾驶产业发展趋势研究Trends in China High-level Autonomous Driving from 2020 to 2023自动驾驶发展过程中&#xff0c;中国出现了诸多专注于研发L3级以上自动驾驶的公司&#xff0c;其在业界地位也越来越重要。本报告围绕“高等级自动…

如何搭建自动化测试框架?资深测试整理的PO模式,一套打通自动化...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Po模型介绍 1、简…

MCU的类型和应用领域简介

MCU&#xff08;Microcontroller Unit&#xff09;根据存储器类型可分为无片内ROM型和带片内ROM型。无片内ROM型的芯片需要外接EPROM才能应用&#xff0c;而带片内ROM型则有不同的子类型&#xff0c;如片内EPROM型、MASK片内掩模ROM型和片内Flash型。 MCU还可以按照用途分为通…

JavaSE程序逻辑控制(三种基本结构(顺序、分支、循环)、输入输出、循环输入)

目录 一、顺序结构 二、分支结构 1、 if 语句 2、switch 语句 与C语言不同&#xff0c;不能作为switch参数的类型&#xff1a;float double long boolean 三、循环结构 1.while循环 2.for循环 四、输入输出 1.输出 - 将结果显示打印到屏幕上 2.输入 3.输入输出综合…

Java的方法怎么用?递归是什么?一篇文章带你醍醐灌顶

目录 1.方法定义 2.实参 形参 3.方法重载 4.递归 1.方法定义 // 方法定义 修饰符 返回值类型 方法名称([参数类型 形参 ...]){ 方法体代码; [return 返回值]; }public static 返回值 方法名(形式参数列表){} 实现一个函数&#xff0c;检测一个年份是否为闰年 public class M…

从零开始yolov5模型训练【绝对能学会】

与其说是学习目标检测任务&#xff0c;不如暂时说成是如何正确运行一个yolo小项目。 一、anaconda 安装&#xff1a; Anaconda安装以及如何创建新环境 安装好了之后打开Anaconda Prompt&#xff1a; anaconda的base环境下&#xff1a; 针对yolov5创建一个自己的环境&#xff…

Spring指定bean在哪个应用加载

1.背景 某项目,spring架构,有2个不同的WebAppApplication入口,大部分service类共用,小部分类有区别,只需要在一个应用中加载,不需要在另一个应用中加载. 2.实现代码 自定义限制注解 package mis.shared.annotation;import java.lang.annotation.ElementType; import java.lan…

【深度学习_TensorFlow】手写数字识别

写在前面 到这里为止&#xff0c;我们已经学习完张量的常用操作方法&#xff0c;已具备实现大部分神经网络技术的基础储备了。这一章节我们将开启神经网络的学习&#xff0c;然而并不需要像学习前面那样了解大量的张量操作&#xff0c;而是将重点转向理解概念知识&#xff0c;…

SQL92 SQL99 语法 Oracle 、SQL Server 、MySQL 多表连接、Natural 、USING

SQL92 VS SQL 99 语法 92语法 内连接 from table1&#xff0c; table2 where table1.col table2.col 外连接 放在 从表 左连接&#xff1a; from table1&#xff0c; table2 where table1.col table2.col() 右连接&#xff1a; from table1&#xff0c; table2 where table…

全网最全最细的jmeter接口测试教程以及接口测试流程详解

一、Jmeter简介 Jmeter是由Apache公司开发的一个纯Java的开源项目&#xff0c;即可以用于做接口测试也可以用于做性能测试。 Jmeter具备高移植性&#xff0c;可以实现跨平台运行。 Jmeter可以实现分布式负载。 Jmeter采用多线程&#xff0c;允许通过多个线程并发取样或通过…