go+mysql+cocos实现游戏搭建

news2025/4/21 7:52:54

盲目的学了一段时间了,刚开始从Box2d开始学习,明白了很多,Box2d是物理模型的基础,是我们在游戏中模拟现实的很重要的一个开源工具。后来在朋友的建议下学习了cocos,也是小程序开发的利器,而golang是一款高效的httprouter服务器,如果考虑安全肯定是没有tcp的安全。用起来太容易了,可以快速的游戏服务。

1.数据库连接:

数据库用的是gorm,连接数据库一个需要

_ "github.com/go-sql-driver/mysql"

"github.com/jinzhu/gorm"

mysql的驱动和gorm库支持。代码如下:

package mysqldb_test

import (
	"fmt"
	"log"
	mymodals "main/modals"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jinzhu/gorm"
	"github.com/userlll1986/main/config"
)

var Db *gorm.DB
var err error

// User 结构体声明
// type User struct {
// 	UserId    int64  `gorm:"primaryKey;autoIncrement"`
// 	UserName  string `gorm:"not null;type:varchar(32)"`
// 	UserPwd   string `gorm:"not null;type:varchar(128)"`
// 	UserPhone string `gorm:"unique;type:varchar(32)"`
// }

// 数据库配置
func InitDb(config *config.Config) {
	url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		config.Data.Username,
		config.Data.Password,
		config.Data.Ip,
		config.Data.Part,
		config.Data.DataBase,
	)
	// 这个地方要注意,不要写称 :=  写成 = 才对
	Db, err = gorm.Open(config.Data.Category, url)

	// 设置表前缀
	gorm.DefaultTableNameHandler = func(db *gorm.DB, defaultTableName string) string {
		//fmt.Println("db.DefaultTableNameHandler", config.Data.Prefix, defaultTableName)
		return config.Data.Prefix + defaultTableName
	}

	if err != nil {
		log.Fatalf("连接数据库【%s:%s/%s】失败, 失败的原因:【%s】", config.Data.Ip, config.Data.Part, config.Data.DataBase, err)
	}

	// db配置输出SQL语句
	Db.LogMode(config.Data.Sql)
	// 使用表名不适用复数
	Db.SingularTable(true)
	// 连接池配置
	Db.DB().SetMaxOpenConns(20)
	Db.DB().SetMaxIdleConns(10)
	Db.DB().SetConnMaxLifetime(10 * time.Second)
	// 判断是否需要用来映射结构体到到数据库
	// fmt.Println(config.Data.Init.Status)
	if config.Data.Init.Status {
		// 自动迁移数据库表结构
		// err := Db.AutoMigrate(&User{})
		// if err != nil {
		// 	fmt.Println("数据库表迁移失败!", err)
		// } else {
		// 	fmt.Println("数据库表迁移成功!")
		// }
		// 插入单条数据
		// var user = User{UserName: "wjj", UserPwd: "123", UserPhone: "111"}
		// Db.Create(&user)
		// var users = []User{
		// 	{UserName: "th", UserPwd: "123", UserPhone: "222"},
		// 	{UserName: "lhf", UserPwd: "123", UserPhone: "333"},
		// 	{UserName: "zcy", UserPwd: "123", UserPhone: "444"},
		// }
		// for _, user := range users {
		// 	Db.Create(&user)
		// }
		// 查询全部记录
		var users []mymodals.User
		Db.Find(&users)
		Db.Where("user_name = ?", "wjj").Find(&users)
		// Db.First(&users)
		// // 打印结果
		// fmt.Println(users)
		// 查询总数
		// var users []User
		// var totalSize int64
		// Db.Find(&users).Count(&totalSize)
		// fmt.Println("记录总数:", totalSize)
		// 查询user_id为1的记录
		// var stu User
		// Db.Where("user_id = ?", 1).Find(&stu)
		// // 修改stu姓名为wjj1
		// stu.UserName = "wjj1"
		// // 修改(按照主键修改)
		// Db.Save(&stu)
		// var stu User
		// Db.Model(&stu).Where("user_id = ?", 1).Update("user_name", "wjj2")
		// var fields = map[string]interface{}{"user_name": "WJJ", "user_pwd": "999"}
		// fmt.Println(fields)
		// Db.Model(&stu).Where("user_id = ?", 1).Updates(fields)
		// // 删除
		// var user = User{UserId: 1}
		// Db.Delete(&user)
		// 按照条件删除
		// Db.Where("user_id = ?", 10).Delete(&User{})
	}

	log.Printf("连接数据库【%s:%s/%s】成功", config.Data.Ip, config.Data.Part, config.Data.DataBase)
}

 代码中注释的部分没有删除,有数据库自迁移和增删改查的基本操作在里面。
 

2.先分享一下主程序,这样看起来比较容易理解。

port := os.Getenv("PORT")

	if port == "" {
		port = "8080"
		log.Printf("Defaulting to port %s", port)
	}

	// 读取配置文件
	myconfig := config.NewConfig()
	myconfig.ReadConfig()
	// 初始化数据库连接
	mysqldb_test.InitDb(myconfig)

	// Starts a new Gin instance with no middle-ware
	r := gin.New()

	// 使用 Recovery 中间件
	r.Use(gin.Recovery())

	// 使用 Logger 中间件
	r.Use(gin.Logger())

	// 使用 CORSMiddleware 中间件
	r.Use(corsMiddleware())

	// 使用限流中间件
	r.Use(limiter.Middleware)

	//使用数据库中间件
	// 将db作为中间件传递给路由处理函数
	r.Use(func(c *gin.Context) {
		c.Set("db", mysqldb_test.Db)

		c.Next()
	})
	// 在路由处理函数中可以通过c.MustGet("db").(*gorm.DB)获取到db对象,然后进行数据库操作

	// 创建Redis客户端
	redisClient := redis.NewClient(&redis.Options{
		Addr:     "127.0.0.1:54372", // Redis服务器地址
		Password: "123456",          // Redis密码
		DB:       0,                 // Redis数据库编号
	})
	// 使用Redis中间件
	r.Use(func(c *gin.Context) {
		// 在Gin的上下文中设置Redis客户端
		c.Set("redis", redisClient)
		// 继续处理后续的请求
		c.Next()
	})
	// 定义路由和处理函数
	r.GET("/get/:key", func(c *gin.Context) {
		// 从上下文中获取Redis客户端
		redisClient := c.MustGet("redis").(*redis.Client)

		// 从URL参数中获取键名
		key := c.Param("key")

		// 使用Redis客户端进行GET操作
		val, err := redisClient.Get(c, key).Result()
		if err == redis.Nil {
			c.JSON(200, gin.H{
				"result": fmt.Sprintf("Key '%s' not found", key),
			})
		} else if err != nil {
			c.JSON(500, gin.H{
				"error": err.Error(),
			})
		} else {
			c.JSON(200, gin.H{
				"result": val,
			})
		}
	})

	// 添加ES中间件,暂不使用
	//r.Use(ElasticSearchMiddleware())

	// 定义路由
	// r.GET("/", func(c *gin.Context) {
	// 	// 从上下文中获取ES客户端
	// 	esClient := c.MustGet("esClient").(*elastic.Client)

	// 	// 使用ES客户端进行查询
	// 	// 这里只是一个示例,具体的ES查询操作可以根据实际需求进行修改
	// 	_, _, err := esClient.Ping().Do(c.Request.Context())
	// 	if err != nil {
	// 		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to ping Elasticsearch"})
	// 		return
	// 	}

	// 	c.JSON(http.StatusOK, gin.H{"message": "Hello from Gin with Elasticsearch middleware!"})
	// })

	// 创建RabbitMQ连接
	conn, err := amqp.Dial("amqp://lafba13j4134:llhafaif99973@localhost:5672/")
	if err != nil {
		fmt.Println("连接RabbitMQ失败:", err)
		return
	}
	defer conn.Close()

	// 添加RabbitMQ中间件
	r.Use(RabbitMQMiddleware(conn, "my_queue"))

这里有数据库中间件(第一部分讲的),日志中间件,限流中间件,rabbitmq中间件等。

下面会每一部分加上代码,这些中间件很容易使用,加一些代码就能直接使用,很方便。

3,下面是跨域请求中间件:

func corsMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 允许所有的跨域请求
		c.Header("Access-Control-Allow-Origin", "*")
		c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization")
		c.Header("Access-Control-Max-Age", "86400") // 预检请求缓存时间,单位为秒

		// 处理预检请求
		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(200)
			return
		}

		// 继续处理其他请求
		c.Next()
	}
}

4,限流中间件

var (
	limiter = NewLimiter(10, 1*time.Minute) // 设置限流器,允许每分钟最多请求10次
)

// NewLimiter 创建限流器
func NewLimiter(limit int, duration time.Duration) *Limiter {
	return &Limiter{
		limit:      limit,
		duration:   duration,
		timestamps: make(map[string][]int64),
	}
}

// Limiter 限流器
type Limiter struct {
	limit      int                // 限制的请求数量
	duration   time.Duration      // 时间窗口
	timestamps map[string][]int64 // 请求的时间戳
}

// Middleware 限流中间件
func (l *Limiter) Middleware(c *gin.Context) {
	ip := c.ClientIP() // 获取客户端IP地址

	// 检查请求时间戳切片是否存在
	if _, ok := l.timestamps[ip]; !ok {
		l.timestamps[ip] = make([]int64, 0)
	}

	now := time.Now().Unix() // 当前时间戳

	// 移除过期的请求时间戳
	for i := 0; i < len(l.timestamps[ip]); i++ {
		if l.timestamps[ip][i] < now-int64(l.duration.Seconds()) {
			l.timestamps[ip] = append(l.timestamps[ip][:i], l.timestamps[ip][i+1:]...)
			i--
		}
	}

	// 检查请求数量是否超过限制
	if len(l.timestamps[ip]) >= l.limit {
		c.JSON(429, gin.H{
			"message": "Too Many Requests",
		})
		c.Abort()
		return
	}

	// 添加当前请求时间戳到切片
	l.timestamps[ip] = append(l.timestamps[ip], now)

	// 继续处理请求
	c.Next()
}

5,redis中间件

// 创建Redis客户端
	redisClient := redis.NewClient(&redis.Options{
		Addr:     "127.0.0.1:54372", // Redis服务器地址
		Password: "123456",          // Redis密码
		DB:       0,                 // Redis数据库编号
	})
	// 使用Redis中间件
	r.Use(func(c *gin.Context) {
		// 在Gin的上下文中设置Redis客户端
		c.Set("redis", redisClient)
		// 继续处理后续的请求
		c.Next()
	})

中间件等使用很简单,直接c.MustGet("redis").(*redis.Client)直接取出来就能使用,c是gin.Context类型,是请求传的参数。

6,go和cocos通讯

在gin端:

func login(c *gin.Context) {
	var req mymodals.AccountServiceRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	if req.Type == "AccountService" && req.Tag == "account_login" {
		if resp, err := myaccount.CallFunc("Account_login", c, req.Type, req.Tag, req.Body); err != nil {
			fmt.Println("Error:", err)
			var resp mymodals.AccountServiceResponse
			resp.Result = "error"
			resp.Body.Length = 1
			resp.Body.Detail = err.Error()
			c.JSON(http.StatusBadRequest, resp)
		} else {
		
			fmt.Println("Result of bar: ", resp[0].Interface())
			c.JSON(http.StatusOK, resp[0].Interface())
		}

	} else if req.Type == "AccountService" {
		if resp, err := myaccount.CallFunc(req.Tag, c, req.Type, req.Tag, req.Body); err != nil {
			fmt.Println("Error:", err)
			var resp mymodals.AccountServiceResponse
			resp.Result = "error"
			resp.Body.Length = 1
			resp.Body.Detail = err.Error()
			c.JSON(http.StatusBadRequest, resp)
		} else {
			fmt.Println("Result of bar:", resp[0].Interface())
			c.JSON(http.StatusOK, resp[0].Interface())
		}
	}
}

CallFunc用的是反射机制,通过传过来的参数调用函数。反射调用的具体函数如下,这里面调用了数据库中间价,做了token验证。

func Account_login(c *gin.Context, Type string, Tag string, Body map[string]interface{}) mymodals.AccountServiceResponse {
	// 这里进行实际的登录验证逻辑
	log.Printf("Account_login: %v,%v,%v", Type, Tag, Body)
	// 例如:检查用户名和密码是否匹配,验证码是否正确等
	var users []mymodals.User
	var db = c.MustGet("db").(*gorm.DB)
	db.Where("user_name = ?", Body["username"].(string)).Find(&users)

	var resp mymodals.AccountServiceResponse
	resp.Type = "AccountService"
	resp.Tag = "account_login"
	//增加token验证
	token, err := authjwt.GenerateToken(Body["username"].(string))

	if err != nil {
		// ctx.JSON(http.StatusInternalServerError, gin.H{
		// 	"code":    500, // Token生成错误
		// 	"message": "请重新登录",
		// })
		var resp mymodals.AccountServiceResponse
		resp.Result = "error"
		resp.Body.Length = 1
		resp.Body.Detail = err.Error()
		// c.JSON(http.StatusBadRequest, resp)
		return resp
	}

	if len(users) > 0 {
		// 验证密码是否正确
		hashedPassword := hashPassword(Body["password"].(string))
		log.Printf("hashedPassword: %s", hashedPassword)

		if users[0].UserPwd == Body["password"].(string) {
			// 登录成功, 记录登录日志
			// c.JSON(http.StatusOK, gin.H{"result": "ok"})
			resp.Result = "ok"
			resp.Body.Length = 1
			resp.Body.Token = token
			// return
		} else {
			resp.Result = "error"
			resp.Body.Length = 1
			resp.Body.Detail = "用户名或密码错误"
		}
	} else {
		resp.Result = "error"
		resp.Body.Length = 1
		resp.Body.Detail = "用户名或密码错误"
	}
	log.Printf("登录响应: %v", resp)
	return resp
	// 将响应数据发送给客户端
	// c.JSON(http.StatusOK, resp)
}

7.cocos端协议的发送和接收

import { _decorator, Component, Node,Button,EventMouse,EditBox,Label } from 'cc';
import { setGlobalData, getGlobalData } from './global';
const { ccclass, property } = _decorator;

@ccclass('login')
export class login extends Component {

    @property(Button)
    private btnLogin: Button | null = null; // 

    @property(Button)
    private btnLogout: Button | null = null; // 

    @property(EditBox)
    private editBoxUsername: EditBox | null = null; // 用户名输入框

    @property(EditBox)
    private editBoxPassword: EditBox | null = null; // 密码输入框

    @property(Label)
    private errorMessage: Label | null = null; // 用于显示错误信息的 Label

    start() {
        if (this.btnLogin) {
            // // 监听鼠标进入 Mask 事件
           
            this.btnLogin.node.on("click", this.onMouseClickMask, this);
           
        }
        if (this.errorMessage) {
            this.errorMessage.node.active = false;
        }
        if (this.btnLogout) {
            this.btnLogout.node.on("click", this.onMouseClickLogout, this);
        }
    }

    private onMouseClickLogout(event: EventMouse) {
        console.log('鼠标点击了 Logout 按钮');
        // 在这里添加你点击后想要执行的逻辑
        // 关闭当前游戏窗口
        cc.director.loadScene("EmptyScene");
        
    }

    update(deltaTime: number) {
        
    }

    private onMouseClickMask(event: EventMouse) {
        console.log('鼠标点击了 Mask 区域');
        // 在这里添加你点击后想要执行的逻辑
        const username = this.editBoxUsername ? this.editBoxUsername.string : "";
        const password = this.editBoxPassword ? this.editBoxPassword.string : "";
        const ip = "127.0.0.1"; // 获取客户端的 IP 地址,这里假设为固定的 IP
        const captcha = "12345"; // 从输入框获取验证码
        const proving = "北京市"; // 从输入框获取省份
        const machineCode = "machine123"; // 获取机器码
        const clientType = "ios"; // 客户端类型
        const data = JSON.stringify({
            type: "AccountService",
            tag: "account_login",
            body: {
                username: username,
                password: password,
                ip: ip,
                captcha: captcha,
                proving: proving,
                machineCode: machineCode,
                client_type: clientType
            }
        });
        fetch('http://localhost:8080/v2/login', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: data,
        })
        .then(response => response.json())
        .then(data => this.handleLoginResponse(data))
        .catch((error) => console.error('Error:', error));
    }

  
    handleLoginResponse(response: any): void {
        if (response.result === "ok") {
            console.log("登录成功",response,response.body.token);
            // 在这里可以进行登录成功的处理逻辑
            setGlobalData(response.body.token); // 获取登录成功后的 Token
            // 例如:跳转到游戏主界面
            cc.director.loadScene("hall");
        } else {
            console.log("登录失败:", response.body.detail);
            // 在这里可以进行登录失败的处理逻辑
            // 例如:显示错误提示
            if (this.errorMessage) {
                this.errorMessage.string = response.body.detail;
                this.errorMessage.node.active = true;
                // 设置 3 秒后自动隐藏错误信息
                setTimeout(() => {
                    this.errorMessage.node.active = false;
                }, 3000);
            }
            // cc.find('Canvas/ErrorMessage').getComponent(cc.Label).string = response.body.detail;
        }
    }
}

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

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

相关文章

【微知】服务器如何获取服务器的SN序列号信息?(dmidecode -t 1)

文章目录 背景命令dmidecode -t的数字代表的字段 背景 各种场景都需要获取服务器的SN&#xff08;Serial Number&#xff09;&#xff0c;比如问题定位&#xff0c;文件命名&#xff0c;该部分信息在dmi中是标准信息&#xff0c;不同服务器&#xff0c;不同os都能用相同方式获…

51c大模型~合集119

我自己的原文哦~ https://blog.51cto.com/whaosoft/13852062 #264页智能体综述 MetaGPT等20家顶尖机构、47位学者参与 近期&#xff0c;大模型智能体&#xff08;Agent&#xff09;的相关话题爆火 —— 不论是 Anthropic 抢先 MCP 范式的快速普及&#xff0c;还是 OpenAI …

Vue3 + TypeScript,关于item[key]的报错处理方法

处理方法1&#xff1a;// ts-ignore 注释忽略报错 处理方法2&#xff1a;item 设置为 any 类型

【记录】服务器用命令开启端口号

这里记录下如何在服务器上开启适用于外界访问的端口号。 方法 1 使用防火墙 1 su &#xff0c;命令 输入密码 切换到root节点 2 开启防火墙 systemctl start firewalld3 配置开放端口 firewall-cmd --zonepublic --add-port8282/tcp --permanent4 重启防火墙 firewall-cmd…

OpenCV基础01-图像文件的读取与保存

介绍: OpenCV是 Open Souce C omputer V sion Library的简称。要使用OpenCV需要安装OpenCV包&#xff0c;使用前需要导入OpenCV模块 安装 命令 pip install opencv-python 导入 模块 import cv2 1. 图像的读取 import cv2 img cv2.imread(path, flag)这里的flag 是可选参数&…

go语言优雅关机和优雅重启笔记

一、优雅关机 生活化例子 餐馆关门&#xff1a;你去餐馆吃火锅&#xff0c;刚坐下点完菜&#xff08;客户端发请求&#xff09;&#xff0c;餐馆老板突然接到通知要停电&#xff08;收到关机指令&#xff09;。老板很贴心&#xff0c;先停止接待新客人&#xff08;停止接收新请…

【算法】计数排序、桶排序、基数排序

算法系列八&#xff1a;非比较排序 一、计数排序 1.实现 1.1步骤 1.2代码 2.性质 2.1稳定性 2.1.1从前往后前始版&#xff1a; 2.1.2从后往前末始版&#xff1a; 2.2复杂度 2.2.1时间复杂度 2.2.2空间复杂度 二、桶排序 1.实现 1.1步骤 1.2代码 2.稳定性 三、…

Halcon应用:相机标定

提示&#xff1a;若没有查找的算子&#xff0c;可以评论区留言&#xff0c;会尽快更新 Halcon应用&#xff1a;相机标定 前言一、Halcon应用&#xff1f;二、应用实战1、图像理解1.1、开始标定 前言 本篇博文主要用于记录学习Halcon中算子的应用场景&#xff0c;及其使用代码和…

【C++ 程序设计】实战:C++ 实践练习题(31~40)

目录 31. 数列&#xff1a;s 1 &#xff0b; 2 &#xff0b; 3 &#xff0b; … &#xff0b; n 32. 数列&#xff1a;s 1 - 2 - 3 - … - n 33. 数列&#xff1a;s 1 &#xff0b; 2 - 3 &#xff0b; … - n 34. 数列&#xff1a;s 1 - 2 &#xff0b; 3 - … &#…

绿幕抠图直播软件-蓝松抠图插件--使用相机直播,灯光需要怎么打?

使用SONY相机进行绿幕抠图直播时&#xff0c;灯光布置是关键&#xff0c;直接影响抠图效果和直播画质。以下是详细的灯光方案和注意事项&#xff1a; 一、绿幕灯光布置核心原则 均匀照明&#xff1a;绿幕表面光线需均匀&#xff0c;避免阴影和反光&#xff08;亮度差控制在0.5…

从外网访问局域网服务器的方法

一、为什么局域网的服务器无法在外网访问&#xff1f; 服务器、电脑之间靠IP地址寻址&#xff0c;目前大部分基于IPV4进行寻址访问。但是因为IPV4的地址数量有限&#xff0c;中国分到的还比较少&#xff0c;所以非常紧缺。 一个解决方案就是在局域网来建立一个内部的网…

机器学习 Day12 集成学习简单介绍

1.集成学习概述 1.1. 什么是集成学习 集成学习是一种通过组合多个模型来提高预测性能的机器学习方法。它类似于&#xff1a; 超级个体 vs 弱者联盟 单个复杂模型(如9次多项式函数)可能能力过强但容易过拟合 组合多个简单模型(如一堆1次函数)可以增强能力而不易过拟合 集成…

交换机与路由器的主要区别:深入分析其工作原理与应用场景

在现代网络架构中&#xff0c;交换机和路由器是两种至关重要的设备。它们在网络中扮演着不同的角色&#xff0c;但很多人对它们的工作原理和功能特性并不十分清楚。本文将深入分析交换机与路由器的主要区别&#xff0c;并探讨它们的工作原理和应用场景。 一、基本定义 1. 交换…

【Oracle专栏】Oracle中的虚拟列

Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.背景 在EXP方式导出时&#xff0c;发现 出现如下提示 EXP-00107: virtual column 不支持&#xff0c;因此采用expdp方式导出。于是本文针对oracle虚拟列进行简单介绍。 2. 相…

2020 年 7 月大学英语四级考试真题(组合卷)——解析版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;目前中南大学MBA在读&#xff0c;也考取过HCIE Cloud Computing、CCIE Security、PMP、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &…

大语言模型的训练、微调及压缩技术

The rock can talk — not interesting. The rock can read — that’s interesting. &#xff08;石头能说话&#xff0c;不稀奇。稀奇的是石头能读懂。&#xff09; ----硅谷知名创业孵化器 YC 的总裁 Gar Tan 目录 1. 什么是大语言模型&#xff1f; 2. 语言建模&#xff…

firewall指令

大家好,今天我们继续来了解服务管理,来看看打开或关闭指定端口,那么话不多说,开始吧. 1.打开或者关闭指定端口 在真正的生产环境,往往需要防火墙,但问题来了,如果我们把防火墙打开,那么外部请求数据包就不能跟服务器监听通讯,这时,需要打开指定的端口,比如80,22,8080等. 2.fi…

【MySQL】MySQL表的增删改查(CRUD) —— 上篇

目录 MySQL表的增删改查&#xff08;CRUD&#xff09; 1. 新增&#xff08;Create&#xff09;/插入数据 1.1 单行数据 全列插入 insert into 表名 values(值, 值......); 1.2 单行数据 指定列插入 1.3 多行数据 指定列插入 1.4 关于时间日期&#xff08;datetime&am…

软考高级系统架构设计师-第15章 知识产权与标准化

【本章学习建议】 根据考试大纲&#xff0c;本章主要考查系统架构设计师单选题&#xff0c;预计考3分左右&#xff0c;较为简单。 15.1 标准化基础知识 1. 标准的分类 分类 内容 国际标准&#xff08;IS&#xff09; 国际标准化组织&#xff08;ISO&#xff09;、国际电工…

Spring Boot 整合 DeepSeek 实现AI对话 (保姆及教程)

文章目录 文章目录 前言 一、创建 spring boot 工程 二、申请key 三、修改配置文件 application.properties 四、编写控制器&#xff08;controller&#xff09; 五、运行调试 前言 提示&#xff1a;随着人工智能的不断发展&#xff0c;ai这门技术也越来越重要&#xff0c;很多…