Go-Zero 框架使用 MongoDB,数据采集入库如此简单

目录

引言

环境准备

如何使用

main入口代码实现

实现采集网络接口

总结

其他资源


引言

Go-Zero 是一个高性能、可扩展的微服务框架,专为 Go 语言设计。它提供了丰富的功能,如 RPC、RESTful API 支持、服务发现、熔断器、限流器等,使开发者能够快速构建分布式系统。在众多数据存储选项中,MongoDB 作为一种流行的 NoSQL 数据库,以其灵活性和高性能受到广泛欢迎。本文将介绍如何在 Go-Zero 项目中集成 MongoDB,来看下借助go-zero的goctl工具,实现golang采集网络数据入MongoDB库是多么的简单。

这里以一个小目标任务为例:

采集知乎日报每天的日报数据入MongoDB库(注:仅用于个人学习研究目的,禁止用于其它用途),详细介绍下 Go-Zero 框架集成 MongoDB 数据库的使用。

顺便推荐下go-zero微服务框架,即强大又好用。不但用于微服务,它里面的各个模块也是可以独立拿来用。这里的小任务(采集数据入mongo库),没有使用go-zero的微服务,仅使用了它里面的logx日志模块、httpc客户端模块,config配置文件操作模块和goctl自动化生成 MongoDB的model层代码。

环境准备

goctl:确保你已经安装了 Go-Zero的goctl命令行工具。goctl 是 go-zero 的内置脚手架,是提升开发效率的一大利器,可以一键生成代码、文档、部署 k8s yaml、dockerfile 等。

$ go install github.com/zeromicro/go-zero/tools/goctl@latest

或者手动下载安装:

goctl 安装 | go-zero Documentation

MongoDB:在本地或远程服务器上安装并运行 MongoDB 实例。

MongoDB: The Developer Data Platform | MongoDB

Go:安装最新版本的 Go 语言环境。

https://go.dev/dl/

如何使用

goctl model 为 goctl 提供的数据库模型代码生成指令,目前支持 MySQL、PostgreSQL、Mongo 的代码生成,MySQL 支持从 sql 文件和数据库连接两种方式生成。

Mongo 模型层代码的生成不同于 MySQL,MySQL 可以从 scheme_information 库中读取到一张表的信息(字段名称,数据类型,索引等), 而 Mongo 是文档型数据库,我们暂时无法从 db 中读取某一条记录来实现字段信息获取。

新建一项目目录文件夹,假设为collect。

#进入项目根目录
cd collect
#开始生成
goctl model mongo -t ZhiNews -dir model/zhiNews

各个参数的含义,主要用的是 -t -e -dir

-t是生成文件的前缀名称

-e表示的是生成一个简单的增删改查接口,-dir是生成文档放在的目录

-c是带缓存的 

生成model层代码执行以上命令即可。很简单,不需要提前编写什么模型文件,以上命令将自动在model/zhiNews目录下生成模型框架代码,如果需要扩展其他字段类型,直接修改生成的zhinewstypes.go文件。

zhinewsmodelgen.go 

这个文件是自动生成的,不要修改。

// Code generated by goctl. DO NOT EDIT.
package model

import (
	"context"
	"time"

	"github.com/zeromicro/go-zero/core/stores/mon"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
)

type zhiNewsModel interface {
	Insert(ctx context.Context, data *ZhiNews) error
	FindOne(ctx context.Context, id string) (*ZhiNews, error)
	Update(ctx context.Context, data *ZhiNews) (*mongo.UpdateResult, error)
	Delete(ctx context.Context, id string) (int64, error)
}

type defaultZhiNewsModel struct {
	conn *mon.Model
}

func newDefaultZhiNewsModel(conn *mon.Model) *defaultZhiNewsModel {
	return &defaultZhiNewsModel{conn: conn}
}

func (m *defaultZhiNewsModel) Insert(ctx context.Context, data *ZhiNews) error {
	if data.ID.IsZero() {
		data.ID = primitive.NewObjectID()
		data.CreateAt = time.Now()
		data.UpdateAt = time.Now()
	}

	_, err := m.conn.InsertOne(ctx, data)
	return err
}

func (m *defaultZhiNewsModel) FindOne(ctx context.Context, id string) (*ZhiNews, error) {
	oid, err := primitive.ObjectIDFromHex(id)
	if err != nil {
		return nil, ErrInvalidObjectId
	}

	var data ZhiNews

	err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid})
	switch err {
	case nil:
		return &data, nil
	case mon.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

func (m *defaultZhiNewsModel) Update(ctx context.Context, data *ZhiNews) (*mongo.UpdateResult, error) {
	data.UpdateAt = time.Now()

	res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data})
	return res, err
}

func (m *defaultZhiNewsModel) Delete(ctx context.Context, id string) (int64, error) {
	oid, err := primitive.ObjectIDFromHex(id)
	if err != nil {
		return 0, ErrInvalidObjectId
	}

	res, err := m.conn.DeleteOne(ctx, bson.M{"_id": oid})
	return res, err
}

zhinewstypes.go

在这个文件里根据需要扩展类型字段。

package model

import (
	"time"

	"go.mongodb.org/mongo-driver/bson/primitive"
)

type Stories struct {
	Title  string `bson:"title" json:"title"`
	Url    string `bson:"url" json:"url"`
	Hint   string `bson:"hint" json:"hint"`
	Images string `bson:"images" json:"images"`
	Id     int64  `bson:"id" json:"id"`
}

type TopStories struct {
	Title  string `bson:"title" json:"title"`
	Url    string `bson:"url" json:"url"`
	Hint   string `bson:"hint" json:"hint"`
	Images string `bson:"images" json:"images"`
	Id     int64  `bson:"id" json:"id"`
}

type ZhiNews struct {
	ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
	// TODO: Fill your own fields
	Date      string       `bson:"date" json:"date"`
	Storys    []Stories    `bson:"stories" json:"stories"`
	TopStorys []TopStories `bson:"top_stories" json:"top_stories"`
	UpdateAt  time.Time    `bson:"updateAt,omitempty" json:"updateAt,omitempty"`
	CreateAt  time.Time    `bson:"createAt,omitempty" json:"createAt,omitempty"`
}

 zhinewsmodel.go

注意,那个zhinewsmodelgen.go,文件后带gen的文件是自动生成的,默认提供的接口实现,但肯定不够用,但也不要在这里编辑。可以在zhinewsmodel.go文件中扩展实现

如下所示:

package model

import (
	"context"
	"time"

	"github.com/zeromicro/go-zero/core/stores/mon"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
)

var _ ZhiNewsModel = (*customZhiNewsModel)(nil)

type (
	// ZhiNewsModel is an interface to be customized, add more methods here,
	// and implement the added methods in customZhiNewsModel.
	ZhiNewsModel interface {
		zhiNewsModel
		// 增加 插入重复则更新
		InsertWithUpdate(ctx context.Context, data *ZhiNews) error
		// 增加 根据日期来更新
		UpdateOneByDate(ctx context.Context, data *ZhiNews) (*mongo.UpdateResult, error)
		// 增加 根据日期查找
		FindOneByDate(ctx context.Context, date string) (*ZhiNews, error)
	}

	customZhiNewsModel struct {
		*defaultZhiNewsModel
	}
)

// NewZhiNewsModel returns a model for the mongo.
func NewZhiNewsModel(url, db, collection string) ZhiNewsModel {
	conn := mon.MustNewModel(url, db, collection)
	return &customZhiNewsModel{
		defaultZhiNewsModel: newDefaultZhiNewsModel(conn),
	}
}

func (m *customZhiNewsModel) InsertWithUpdate(ctx context.Context, data *ZhiNews) error {

	err := m.Insert(ctx, data)
	if mongo.IsDuplicateKeyError(err) {
		_, err = m.UpdateOneByDate(ctx, data)
	}
	return err
}

func (m *customZhiNewsModel) UpdateOneByDate(ctx context.Context, data *ZhiNews) (*mongo.UpdateResult, error) {

	dat, err := m.FindOneByDate(ctx, data.Date)
	if err != nil {
		return nil, err
	}
	data.ID = dat.ID
	data.UpdateAt = time.Now()
	res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data})
	return res, err
}

func (m *customZhiNewsModel) FindOneByDate(ctx context.Context, date string) (*ZhiNews, error) {

	var data ZhiNews

	err := m.conn.FindOne(ctx, &data, bson.M{"date": date})
	switch err {
	case nil:
		return &data, nil
	case mon.ErrNotFound:
		return nil, ErrNotFound
	default:
		return nil, err
	}
}

config.yaml:

MongoDB:
  Url: "mongodb://test1:xxxx@175.xxx.126.10:27017/?tls=false&authSource=test1"
  DbName: "test1"
  Collection: "zhiNews"

main入口代码实现

package main

import (
	model "collect/model/zhiNews"
	"context"
	"encoding/json"
	"errors"
	"flag"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/tidwall/gjson"
	"github.com/zeromicro/go-zero/core/conf"
	log "github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/rest/httpc"
)

type Config struct {
	MongoDB struct {
		Url        string `json:",default=mongodb://localhost:27017"`
		DbName     string `json:",default=testdb"`
		Collection string `json:",default=zhiNews"`
	}
}

var f = flag.String("f", "etc/config.yaml", "config file")

func getZhiNews(date string) (resp *model.ZhiNews, err error) {
	url := "https://news-at.zhihu.com/api/4/news/latest"
	parsedDate, err := time.Parse("20060102", date)
	if err != nil {
		log.Errorf("Error parsing date:%s", err)
	}
	now := time.Now().Format("20060102")
	if now != date {
		url = "https://news-at.zhihu.com/api/4/news/before/" + parsedDate.AddDate(0, 0, 1).Format("20060102")
	}
	// 创建一个请求
	r, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	//设置常见的HTTP头
	r.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3")
	//ctx := context.Background()
	//res, err_ := httpc.Do(ctx, http.MethodGet, url, nil)
	res, err_ := httpc.DoRequest(r)
	if err_ != nil {
		log.Error(err_)
		return nil, err
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		log.Errorf("Failed to read response body:%s", err)
		return nil, err
	}
	log.Debug(res.StatusCode)
	var keyVal map[string]interface{}
	err = json.Unmarshal(body, &keyVal)
	if err != nil {
		log.Errorf("Failed to extract key value:%s", err)
	}
	//log.Debugf("keyVal:%v", keyVal)
	if res.StatusCode != 200 {
		log.Errorf("Failed to request,%s", res.Status)
		return nil, errors.New(res.Status)
	}
	var zhi model.Stories
	var responseData []model.Stories
	list_ := gjson.GetBytes(body, "stories").Array()
	for _, item := range list_ {
		zhi.Id = item.Get("id").Int()
		zhi.Title = item.Get("title").String()
		zhi.Images = item.Get("images.0").String()
		zhi.Url = item.Get("url").String()
		zhi.Hint = item.Get("hint").String()
		responseData = append(responseData, zhi)
	}
	var top model.TopStories
	var topData []model.TopStories
	list_1 := gjson.GetBytes(body, "top_stories").Array()
	for _, item := range list_1 {
		top.Id = item.Get("id").Int()
		top.Title = item.Get("title").String()
		top.Images = item.Get("images.0").String()
		top.Url = item.Get("url").String()
		top.Hint = item.Get("hint").String()
		topData = append(topData, top)
	}
	log.Debugf("len list_:%d", len(list_))
	if len(list_) != 0 {
		resp = &model.ZhiNews{
			Storys:    responseData,
			TopStorys: topData,
			Date:      gjson.GetBytes(body, "date").String(),
		}
	} else {
		resp = &model.ZhiNews{
			Storys:    nil,
			TopStorys: nil,
			Date:      date,
		}
	}
	return resp, nil
}

func main() {
	fmt.Printf("collect: %s\n", "start")
	flag.Parse()
	var c Config
	conf.MustLoad(*f, &c)
	log.Info("config: ", c)
	mo := model.NewZhiNewsModel(c.MongoDB.Url, c.MongoDB.DbName, c.MongoDB.Collection)
	ctx := context.Background()

	// 获取今天的日期
	today := time.Now()

	// 设置采集的天数范围
	daysAgo := 49 // 例如,采集从今天往前的7天数据
	for i := 0; i < daysAgo; i++ {
		date := today.AddDate(0, 0, -i).Format("20060102")
		log.Info("date: ", date)
		resp, err := getZhiNews(date)
		if err != nil {
			log.Errorf("getZhiNews error:" + err.Error())
			return
		}
		err = mo.InsertWithUpdate(ctx, resp)
		if err != nil {
			log.Errorf("InsertWithUpdate error: %v", err)
			return
		}
		log.Info("getZhiNews Insert ok")
	}
	fmt.Printf("collect: %s\n", "end")
}

注意,直接使用httpc模块的do方法,可能会被后台认为是机器人操作而直接返回403错误。

//ctx := context.Background()
//res, err_ := httpc.Do(ctx, http.MethodGet, url, nil)

这里使用其支持自定义http报文头的写法:

    // 创建一个请求
	r, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	//设置常见的HTTP头
	r.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3")
	//ctx := context.Background()
	//res, err_ := httpc.Do(ctx, http.MethodGet, url, nil)
	res, err_ := httpc.DoRequest(r)
	if err_ != nil {
		log.Error(err_)
		return nil, err
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		log.Errorf("Failed to read response body:%s", err)
		return nil, err
	}
	log.Debug(res.StatusCode)

model层的代码使用

package main

import (
	model "collect/model/zhiNews"
	"context"
	"errors"
	"flag"
	"fmt"
	"io"
	"net/http"
	"time"

	"github.com/tidwall/gjson"
	"github.com/zeromicro/go-zero/core/conf"
	log "github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/rest/httpc"
)

func main() {
	fmt.Printf("collect: %s\n", "start")
	flag.Parse()
	var c Config
	conf.MustLoad(*f, &c)
	log.Info("config: ", c)
	//mo := model.NewZhiNewsModel("mongodb://test1:psdddd@localhost:27017/?tls=false&authSource=test1", "test1", "zhiNews")
    //model的使用
	mo := model.NewZhiNewsModel(c.MongoDB.Url, c.MongoDB.DbName, c.MongoDB.Collection)
	ctx := context.Background()
    ......
}

实现采集网络接口

知乎日报接口:

#获取最新每日一报
get https://news-at.zhihu.com/api/4/news/latest

###历史日报
get https://news-at.zhihu.com/api/4/news/before/20240617

#curl访问
curl -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3" https://news-at.zhihu.com/api/4/news/before/20240622
func getZhiNews(date string) (resp *model.ZhiNews, err error) {
	url := "https://news-at.zhihu.com/api/4/news/latest"
	parsedDate, err := time.Parse("20060102", date)
	if err != nil {
		log.Errorf("Error parsing date:%s", err)
	}
	now := time.Now().Format("20060102")
	if now != date {
		url = "https://news-at.zhihu.com/api/4/news/before/" + parsedDate.AddDate(0, 0, 1).Format("20060102")
	}
	// 创建一个请求
	r, err := http.NewRequest("GET", url, nil)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	//设置常见的HTTP头
	r.Header.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3")
	//ctx := context.Background()
	//res, err_ := httpc.Do(ctx, http.MethodGet, url, nil)
	res, err_ := httpc.DoRequest(r)
	if err_ != nil {
		log.Error(err_)
		return nil, err
	}
	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)
	if err != nil {
		log.Errorf("Failed to read response body:%s", err)
		return nil, err
	}
	log.Debug(res.StatusCode)
	var keyVal map[string]interface{}
	err = json.Unmarshal(body, &keyVal)
	if err != nil {
		log.Errorf("Failed to extract key value:%s", err)
	}
	//log.Debugf("keyVal:%v", keyVal)
	if res.StatusCode != 200 {
		log.Errorf("Failed to request,%s", res.Status)
		return nil, errors.New(res.Status)
	}
	var zhi model.Stories
	var responseData []model.Stories
	list_ := gjson.GetBytes(body, "stories").Array()
	for _, item := range list_ {
		zhi.Id = item.Get("id").Int()
		zhi.Title = item.Get("title").String()
		zhi.Images = item.Get("images.0").String()
		zhi.Url = item.Get("url").String()
		zhi.Hint = item.Get("hint").String()
		responseData = append(responseData, zhi)
	}
	var top model.TopStories
	var topData []model.TopStories
	list_1 := gjson.GetBytes(body, "top_stories").Array()
	for _, item := range list_1 {
		top.Id = item.Get("id").Int()
		top.Title = item.Get("title").String()
		top.Images = item.Get("images.0").String()
		top.Url = item.Get("url").String()
		top.Hint = item.Get("hint").String()
		topData = append(topData, top)
	}
	log.Debugf("len list_:%d", len(list_))
	if len(list_) != 0 {
		resp = &model.ZhiNews{
			Storys:    responseData,
			TopStorys: topData,
			Date:      gjson.GetBytes(body, "date").String(),
		}
	} else {
		resp = &model.ZhiNews{
			Storys:    nil,
			TopStorys: nil,
			Date:      date,
		}
	}
	return resp, nil
}

设置采集的天数范围,开始采集

   // 获取今天的日期
	today := time.Now()

	// 设置采集的天数范围
	daysAgo := 49 // 例如,采集从今天往前的49天数据
	for i := 0; i < daysAgo; i++ {
		date := today.AddDate(0, 0, -i).Format("20060102")
		log.Info("date: ", date)
		resp, err := getZhiNews(date)
		if err != nil {
			log.Errorf("getZhiNews error:" + err.Error())
			return
		}
		err = mo.InsertWithUpdate(ctx, resp)
		if err != nil {
			log.Errorf("InsertWithUpdate error: %v", err)
			return
		}
		log.Info("getZhiNews Insert ok")
	}

总结

以上完成实现了采集知乎日报的新闻列表信息,采集入mongoDB数据库。使用了go-zero 的goctl工具自动生成操作mongoDB的代码,使用了go-zero框架中的部分模块如日志模块,配置文件操作模块、网络访问模块等。可以看到借助goctl自动生成代码,采集数据入mongoDB数据库是多么的简单方便。再次推荐下go-zero这一优秀的微服务框架。

其他资源

配置文件 | go-zero Documentation

goctl model | go-zero Documentation

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024数据加密神器丨企业级透明加密软件排行榜

透明加密软件通过在操作系统层面进行底层驱动开发&#xff0c;对指定类型的文件进行自动透明加解密。这种加密方式对用户来说是完全透明的&#xff0c;用户在使用加密文件时&#xff0c;不会感到任何不便。同时&#xff0c;由于加密是在文件级别进行的&#xff0c;因此可以有效…

SRS流媒体服务器概述

SRS/5.0(Bee) is a simple, high efficiency and realtime video server, supports RTMP, WebRTC, HLS, HTTP-FLV, SRT, MPEG-DASH and GB28181. 翻译&#xff1a;SRS/5.0(Bee)是一款简洁、高效、实时的视频服务器&#xff0c;支持RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DAS…

vue 启动项目报错Syntax Error: Error: PostCSS received undefined instead of CSS string

启动vue项目然后报错如下图 这个是跟node版本有关系 因为要开发不同的项目使用不同的node版本&#xff0c;所以就用nvm切换&#xff0c;所以导致了node-sass编译问题 执行这个命令就可以 npm install node-sass or npm rebuild node-sass node-sass对于node高版本和低版本切…

我与OceanBase|一位DBA老兵的国产数据库探索之旅

本文作者&#xff1a;尚雷&#xff0c;有超过十年的工作经验&#xff0c;目前就职于南京一家上市互联网企业&#xff0c;担任DBA。Oracle 11g OCM&#xff0c;Oracle及PG的 ACE认证&#xff0c;并有AWS及国产知名数据库等多项认证。他热衷于技术交流与分享&#xff0c;爱交友&a…

C++·栈和队列

栈和队列是什么看这里&#xff1a; 数据结构栈和队列-CSDN博客文章浏览阅读948次&#xff0c;点赞25次&#xff0c;收藏26次。本节讲解了栈和队列的内容&#xff0c;其核心就是栈的特点是后进先出&#xff0c;队列的特点是先进先出。并用C语言实现了栈和队列的结构以及它们的各…

深度解析移动硬盘“函数不正确”错误及高效恢复策略

在数据密集型的社会中&#xff0c;移动硬盘作为移动存储的重要载体&#xff0c;承载着无数用户的个人信息、工作资料及珍贵回忆。然而&#xff0c;当遭遇“函数不正确”的错误时&#xff0c;这些宝贵的数据仿佛被一层无形的屏障所阻隔&#xff0c;让人束手无策。本文将深入探讨…

SiCat:一款多功能漏洞利用管理与搜索工具

关于SiCat SiCat是一款多功能漏洞利用管理与搜索工具&#xff0c;该工具基于纯Python 3开发&#xff0c;旨在帮助广大研究人员有效地识别和收集来自开源和本地存储库的漏洞信息。 SiCat专注于网络安全管理方面的实践工作&#xff0c;允许研究人员快速实现在线搜索&#xff0c;…

关于centos7自带的nginx1.20.1开启https后,XP系统的IE6和IE8无法显示网页的问题

CentOS7自带的nginx-1.20.1是支持HTTP/2和TLS1.3的。 软件包名称&#xff1a;nginx-1.20.1-10.el7.x86_64 CentOS7默认开启了HTTP/2&#xff0c;但没有开启TLS1.3&#xff0c;以及IE6和IE8的https访问。 开启方法&#xff1a; ssl_ciphers HIGH:!aNULL:!MD5;改为ssl_ciphers…

新增多种图表类型,新增插件管理模块,DataEase开源数据可视化分析工具v2.8.0发布

2024年7月8日&#xff0c;人人可用的开源数据可视化分析工具DataEase正式发布v2.8.0版本。 这一版本的功能变动包括&#xff1a;图表方面&#xff0c;新增组合图、热力地图、符号地图、K线图等图表类型&#xff0c;并对已有的仪表盘、明细表、指标卡、富文本等图表类型进行了功…

非参数检测5——双输入检测系统

在很多情况下&#xff0c;信号常常存在于两个带有独立噪声的信道中。所以很有必要研究双输入系统。双输入系统广泛应用于无线电天文学、水下声波检测和地球物理学等领域。

SpringBoot拦截器

目录 一、拦截器快速入门 &#xff08;1&#xff09;什么是拦截器 &#xff08;2&#xff09;拦截器的使用步骤 1、定义拦截器 &#x1f340;preHandle() 方法 &#x1f340;postHandle() 方法 &#x1f340;afterCompletion() 方法 2、注册配置拦截器 二、拦截器详解…

43、nginx的优化、防盗链、重定向、代理

nginx的优化、防盗链、重定向、代理 一、nginx的优化 1.1、隐藏版本号 server_tokens off;隐藏版本号 [roottest1 conf]# vim nginx.confserver_tokens off;[roottest1 conf]# nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok ngin…

顾客排队购买蛋挞问题(算法与数据结构设计)

课题内容和要求 顾客排队买蛋挞问题。有N个顾客排队&#xff0c;每人最多买M个。烘焙员每次烘焙1到K个蛋挞放入盘中&#xff0c;顾客只能购买盘中的蛋挞&#xff0c;未达到M个需重新排队。输出每个顾客购买情况和完成顺序。 例如—— 输入&#xff1a;N9&#xff0c;K5&#x…

Linux安装elasticsearch单机版

一、检查内核 uname -a uname -m 二、下载版本 下载版本选择自己服务器相同的内核版本 我这边是aaech64 ES下载地址 Kibana 下载地址 二、上传服务器解压 tar -xvf elasticsearch-8.14.1-linux-aarch64.tar.gz 三、安装ES 因为ES不能用root用户启动先创建用户 #新增 es …

Django QuerySet对象,all()方法

all()方法 在Django中&#xff0c;all()方法是QuerySet对象的一个方法&#xff0c;用于获取模型的所有实例。 当你调用ModelName.objects.all()时&#xff0c;Django会生成一个SQL查询&#xff0c;从数据库中获取该模型的所有记录&#xff0c;并返回一个QuerySet对象&#xf…

【产品运营】Saas的核心六大数据

国内头部软件公司的一季度表现惨不忍睹&#xff0c;为啥美国的还那么赚钱呢&#xff1f;其实核心是&#xff0c;没几个Saas产品经理是看数据的&#xff0c;也不知道看啥数据。 SaaS 行业&#xff0c;天天抛头露面、名头叫的响的 SaaS 产品&#xff0c;真没有几个赚钱的。 那为…

中国计量大学理学院访问赛氪网:共探校企合作新篇章来

2024年7月5日&#xff0c;中国计量大学理学院代表团莅临环球赛乐&#xff08;北京&#xff09;科技有限公司&#xff0c;进行了一场深入的调研交流活动。代表团成员包括中国计量大学理学院副院长王义康教授、数据科学系副主任刘学艺副教授以及金世举老师。此次访问旨在进一步强…

江洲的《家书》,岂止抵万金

题记 今晨6点钟&#xff0c;像往日一样的背上鱼具包&#xff0c;欲驾乘清凉舒适的晨风&#xff0c;前往味江河堤享受钓翁乐趣。孰料开门一看&#xff0c;朦胧的天空竟下着淅淅沥沥的小雨。 今年的天气异常&#xff0c;是笔者寄居“西川第一天”古镇5年来所未见&#xff1a;再…

stm32——外部中断EXTI

上回书说到定时器的级联&#xff0c;今天来谈谈外部中断EXTI。我使用的是STM32F103C8T6的学习板。仅供大家参考。 什么是中断呢&#xff1f;中断是指计算机在执行程序的过程中&#xff0c;当出现某些异常情况或特殊事件&#xff08;例如外部设备请求、定时时间到达、程序错误等…

YOLOV8花朵实例分割实战

原文:YOLOV8花朵实例分割实战 - 知乎 (zhihu.com) 一、代码: https://github.com/ultralytics/ultralytics​github.com/ultralytics/ultralytics 与先前几个版本相比,YOLOv8 模型更快、更准确,同时为训练模型提供统一框架,以执行以下基本任务: 目标检测;实例分割;图…