中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

做色情網(wǎng)站需要種子搜索神器網(wǎng)頁版

做色情網(wǎng)站需要,種子搜索神器網(wǎng)頁版,大學(xué)生網(wǎng)站開發(fā)文檔,孟村住房建設(shè)局網(wǎng)站目錄 前言正文添加依賴安裝MongoDB添加MongoDB相關(guān)配置創(chuàng)建MongoContext類嘗試初始化DB連接實現(xiàn)注冊功能測試注冊功能實現(xiàn)登錄邏輯測試登錄流程 結(jié)語下節(jié)預(yù)告 前言 游戲服務(wù)器中, 很重要的一點就是如何保存玩家的游戲數(shù)據(jù). 當(dāng)一個服務(wù)端架構(gòu)趨于穩(wěn)定且功能全面, 開發(fā)者會發(fā)現(xiàn)服…

目錄

  • 前言
  • 正文
    • 添加依賴
    • 安裝MongoDB
    • 添加MongoDB相關(guān)配置
    • 創(chuàng)建MongoContext類
    • 嘗試初始化DB連接
    • 實現(xiàn)注冊功能
    • 測試注冊功能
    • 實現(xiàn)登錄邏輯
    • 測試登錄流程
  • 結(jié)語
  • 下節(jié)預(yù)告

前言

游戲服務(wù)器中, 很重要的一點就是如何保存玩家的游戲數(shù)據(jù).
當(dāng)一個服務(wù)端架構(gòu)趨于穩(wěn)定且功能全面, 開發(fā)者會發(fā)現(xiàn)服務(wù)端的業(yè)務(wù)開發(fā)基本就圍繞著CRUD來展開,
即業(yè)務(wù)數(shù)據(jù)的創(chuàng)建 \ 查找 \ 更新 \ 刪除.
本節(jié)內(nèi)容我們就將MongoDB作為持久化數(shù)據(jù)庫引入項目中.

正文

添加依賴

在build.gradle中添加依賴

implementation 'org.springframework.data:spring-data-mongodb:4.2.4'
implementation 'org.mongodb:mongodb-driver-sync:5.0.0'

安裝MongoDB

MongoDB的安裝步驟我就不一一解釋了,
讀者可以選擇使用docker快速創(chuàng)建一個MongoDB容器,
也可以使用MongoDB官方提供的免費(fèi)云數(shù)據(jù)庫進(jìn)行練習(xí) https://www.mongodb.com/cloud/atlas/register
也可以在本地運(yùn)行一個MongoDB進(jìn)程

添加MongoDB相關(guān)配置

在common模塊下添加common.conf配置文件以及CommonConfig類.

mongodb.host=mongodb://%s:%s@localhost:27017/%s?retryWrites=true&w=majority
mongodb.user=root
mongodb.password=123456
# 登錄服數(shù)據(jù)庫名
mongodb.login.db=login
@Getter
@Component
@PropertySource("classpath:common.conf")
public class CommonConfig {@Value("${mongodb.host}")String mongoHost;@Value("${mongodb.user}")String mongoUser;@Value("${mongodb.password}")String mongoPassword;@Value("${mongodb.login.db}")String loginDbName;
}

創(chuàng)建MongoContext類

為了管理MongoDB連接, 創(chuàng)建一個MongoContext類用于初始化mongodb連接與管理.

package org.common.mongo;
import ...
/*** Mongo上下文*/
@Slf4j
@Component
public class MongoContext {private MongoClient mongoClient;private MongoTemplate mongoTemplate;public void initMongoContext(String mongoUrl, String user, String password, String dbName) {String url = String.format(mongoUrl, user, password, dbName);log.info(url);MongoClientSettings.Builder settings = MongoClientSettings.builder();settings.applyConnectionString(new ConnectionString(url));MongoClient mongoClient = MongoClients.create(settings.build());mongoTemplate = new MongoTemplate(mongoClient, dbName);log.info("mongo server ok!");}}

其中MongoClient 是 mongodb-driver-sync庫的核心, 用于直接連接和操作 MongoDB 數(shù)據(jù)庫。
而MongoTemplate是spring-data-mongodb庫的核心, 它基于MongoClient進(jìn)行了接口封裝, 提供了比 MongoClient 更豐富的功能,包括更簡潔的查詢構(gòu)建、更強(qiáng)大的映射支持。

在MongoContext外層封裝一層MongoService用來實現(xiàn)Mongo增刪改查相關(guān)接口。

@Slf4j
@Component
public class MongoService {private MongoContext mongoContext;public void initMongoService(String mongoUrl, String user, String password, String dbName) {MongoContext mongoContext = new MongoContext();mongoContext.initMongoContext(mongoUrl, user, password, dbName);this.mongoContext = mongoContext;}public MongoContext getMongoContext() {return mongoContext;}/*** 插入數(shù)據(jù)*/public <T extends BaseCollection> boolean insert(T obj) {mongoContext.getMongoTemplate().insert(obj);return true;}/*** 查詢數(shù)據(jù)*/public <T extends BaseCollection> BaseCollection findById(Object id, Class<T> clz) {T object = mongoContext.getMongoTemplate().findById(id, clz);return object;}public <T extends BaseCollection> T findOneByQuery(Criteria criteria, Class<T> clz) {Query query = Query.query(criteria);T object = mongoContext.getMongoTemplate().findOne(query, clz);return object;}//TODO 刪//TODO 改

先實現(xiàn)了增查,以便我們后面實現(xiàn)賬號注冊登錄功能來舉例。

嘗試初始化DB連接

在LoginServer的initServer下面增加MongoContext的初始化代碼. 然后運(yùn)行.

 @Overrideprotected void initServer() {LoginConfig config = SpringUtils.getBean(LoginConfig.class);// actor初始化AkkaContext.initActorSystem();// netty啟動NettyServer nettyServer = SpringUtils.getBean(NettyServer.class);nettyServer.start(config.getPort());// mongo服務(wù)啟動CommonConfig commonConfig = SpringUtils.getBean(CommonConfig.class);MongoService mongoService = SpringUtils.getBean(MongoService.class);mongoService.initMongoService(commonConfig.getMongoHost(), commonConfig.getMongoUser(), commonConfig.getMongoPassword(), commonConfig.getLoginDbName());log.info("LoginServer start!");}

啟動LoginServer得到結(jié)果:
mongo連接成功

實現(xiàn)注冊功能

上一節(jié)我們使用Protobuf創(chuàng)建了注冊協(xié)議, 從客戶端發(fā)送到了登錄服進(jìn)行解析.
接下來我們將注冊的賬號密碼進(jìn)行入庫以便后續(xù)取出使用.

我們先構(gòu)思一下一個賬號應(yīng)該有的數(shù)據(jù), 創(chuàng)建一個AccountCollection類, 用于映射Mongo數(shù)據(jù)庫中的AccountCollection表.

@Document
public class AccountCollection extends BaseCollection {@Idprivate long accountId;private String accountName;private String password;// getter & setter
}

很好理解, @Document注解表示該類是一個mongo的文檔映射類, @Id表示這個字段作為該文檔的主鍵.
BaseCollection目前就是一個空的Abstract類, 實現(xiàn)了Serializable接口.

public abstract class BaseCollection implements Serializable {
}

接下來修改ConnectActor中的onClientUpMsg方法, 該方法負(fù)責(zé)接收客戶端上行協(xié)議并進(jìn)行解包.

    private Behavior<BaseMsg> onClientUpMsg(ClientUpMsg msg) throws InvalidProtocolBufferException {Pack decode = PackCodec.decode(msg.getData());log.info("receive client up msg. cmdId = {}", decode.getCmdId());byte[] data = decode.getData();if (decode.getCmdId() == ProtoEnumMsg.CMD.ID.PLAYER_REGISTER_VALUE) {// 注冊協(xié)議LoginProtoHandler.onPlayerRegisterMsg(this, PlayerMsg.C2SPlayerRegister.parseFrom(data));}return this;}

我增加了一個LoginProtoHandler類用于處理登錄相關(guān)的業(yè)務(wù)邏輯.
若是將所有的代碼都寫在ConnectActor, 將來這里的代碼會越來越長最終變得不可控.
使用單一職責(zé)的思想, 使ConnectActor只負(fù)責(zé)進(jìn)行協(xié)議的解包, 具體業(yè)務(wù)邏輯由各個功能模塊自己實現(xiàn), 將來游戲服我們也會這么處理, 這里只簡單提一嘴.

@Slf4j
public class LoginProtoHandler {public static void onPlayerRegisterMsg(ConnectActor actor, PlayerMsg.C2SPlayerRegister up) {log.info("player register, accountName = {}, password = {}", up.getAccountName(), up.getPassword());long accountId = 1L;String accountName = up.getAccountName();String password = up.getPassword();AccountCollection accountCollection = new AccountCollection();accountCollection.setAccountId(accountId);accountCollection.setAccountName(accountName);accountCollection.setPassword(password);MongoService mongoService = SpringUtils.getBean(MongoService.class);boolean res = mongoService.insert(accountCollection);log.info("create account collection. accountId = {}, accountName = {}, res = {}", accountId, accountName, res);// 回包PlayerMsg.S2CPlayerRegister.Builder builder = PlayerMsg.S2CPlayerRegister.newBuilder();builder.setSuccess(res);byte[] down = PackCodec.encode(new Pack(ProtoEnumMsg.CMD.ID.PLAYER_REGISTER_VALUE, builder.build().toByteArray()));actor.getCtx().writeAndFlush(down);}}

LoginProtoHandler負(fù)責(zé)處理客戶端上行的關(guān)于賬號登錄相關(guān)的協(xié)議.
onPlayerRegisterMsg負(fù)責(zé)賬號注冊相關(guān)邏輯.
由于賬號Id的生成規(guī)則我還沒想好, 先用一個1L來進(jìn)行測試, 然后我們調(diào)用MongoService的insert方法, 將accountCollection寫入mongo. 并進(jìn)行回包.

修改ClientMain, 使我們在輸入"register"時, 發(fā)送注冊協(xié)議進(jìn)行賬號的注冊.

	@Overrideprotected void handleBackGroundCmd(String cmd) {if (cmd.equals("test")) {channel.writeAndFlush("test".getBytes());} else if (cmd.equals("register")) {PlayerMsg.C2SPlayerRegister.Builder builder = PlayerMsg.C2SPlayerRegister.newBuilder();builder.setAccountName("clintAccount");builder.setPassword("123456");Pack pack = new Pack(ProtoEnumMsg.CMD.ID.PLAYER_REGISTER_VALUE, builder.build().toByteArray());byte[] data = PackCodec.encode(pack);channel.writeAndFlush(data);} else if (cmd.equals("login")) {PlayerMsg.C2SPlayerLogin.Builder builder = PlayerMsg.C2SPlayerLogin.newBuilder();builder.setAccountName("clintAccount");builder.setPassword("123456");Pack pack = new Pack(ProtoEnumMsg.CMD.ID.PLAYER_LOGIN_VALUE, builder.build().toByteArray());byte[] data = PackCodec.encode(pack);channel.writeAndFlush(data);}}

這里順便把登錄的協(xié)議一并附上, 沒啥技術(shù)含量就不多講.

測試注冊功能

啟動登錄服, 啟動客戶端, 客戶端控制臺輸入register.
看看登錄服的打印:
注冊成功
再看看mongo中數(shù)據(jù)是否寫入成功:
db數(shù)據(jù)
可以看到確實寫入了一條AccountCollection文檔, 字段_id為每個collection的主鍵, 他的數(shù)值也就是我們使用@Id注解標(biāo)識的字段, 另外_class是spring-data-mongo庫為我們添加的類名, 用于讀取數(shù)據(jù)時反序列化用. 需要注意的是如果你的AccountCollection類修改了包名或類名, 這里反序列化就會失敗, 需要額外添加處理.

實現(xiàn)登錄邏輯

登錄與注冊相差不大, 只是把添加數(shù)據(jù)修改為查找數(shù)據(jù).
修改LoginProtoHandler, 添加onPlayerLoginMsg

    public static void onPlayerLoginMsg(ConnectActor actor, PlayerMsg.C2SPlayerLogin up) {String accountName = up.getAccountName();String password = up.getPassword();MongoService mongoService = SpringUtils.getBean(MongoService.class);Criteria criteria = Criteria.where("accountName").is(accountName);AccountCollection accountCollection = mongoService.findOneByQuery(criteria, AccountCollection.class);PlayerMsg.S2CPlayerLogin.Builder builder = PlayerMsg.S2CPlayerLogin.newBuilder();if (accountCollection == null) {log.warn("login without account. accountName = {}", accountName);builder.setSuccess(false);} else if( !accountCollection.getPassword().equals(password) ) {log.warn("login password error. accountName = {}", accountName);builder.setSuccess(false);} else {log.info("login success. accountName = {}, accountId = {}", accountName, accountCollection.getAccountId());builder.setSuccess(true);builder.setAccountId(accountCollection.getAccountId());}byte[] down = PackCodec.encode(new Pack(ProtoEnumMsg.CMD.ID.PLAYER_LOGIN_VALUE, builder.build().toByteArray()));actor.getCtx().writeAndFlush(down);}

這里我們使用Criteria創(chuàng)建一個條件, 根據(jù)accountName來查找一條mongo中的文檔, 然后對比密碼是否一致, 來實現(xiàn)登錄流程.
修改ConnectActor使其對Login協(xié)議進(jìn)行解包并分發(fā)到LoginProtoHandler中.

    private Behavior<BaseMsg> onClientUpMsg(ClientUpMsg msg) throws InvalidProtocolBufferException {Pack decode = PackCodec.decode(msg.getData());log.info("receive client up msg. cmdId = {}", decode.getCmdId());byte[] data = decode.getData();if (decode.getCmdId() == ProtoEnumMsg.CMD.ID.PLAYER_REGISTER_VALUE) {// 注冊協(xié)議LoginProtoHandler.onPlayerRegisterMsg(this, PlayerMsg.C2SPlayerRegister.parseFrom(data));} else if (decode.getCmdId() == ProtoEnumMsg.CMD.ID.PLAYER_LOGIN_VALUE) {// 登錄協(xié)議LoginProtoHandler.onPlayerLoginMsg(this, PlayerMsg.C2SPlayerLogin.parseFrom(data));}return this;}

測試登錄流程

啟動登錄服, 啟動客戶端, 客戶端控制臺輸入login.
看看登錄服的打印:
登錄成功

結(jié)語

本節(jié)我們將MongoDB引入到項目中作為我們的持久化數(shù)據(jù)庫來使用, 并通過注冊登錄的兩個小例子, 來展示spring-data-mongo這個庫的用法.
我們只需要定好映射類, 便算是搭建好了一張表結(jié)構(gòu), 使用起來還是很簡單的, 當(dāng)然我們后面還會繼續(xù)對其封裝, 減少業(yè)務(wù)開發(fā)人員對MongoService的直接調(diào)用.
另外, 我們實現(xiàn)的注冊登錄例子十分粗糙, 其實只是做了一次mongo的讀寫, 對于游戲服務(wù)器來說, 注冊登錄功能是重中之重, 它維護(hù)著玩家的賬號安全, 同時也是我們整個游戲的入口.
對于賬號注冊, 我們還需要做 賬號id生成, 賬號名重復(fù)性檢測, accountId與accountName的緩存映射, 后期還有sdk接入等工作.
對于賬號登錄, 我們還需要做 登錄狀態(tài)修改, 多點登錄頂號, 分配游戲服 等工作.
這些我們后面會繼續(xù)優(yōu)化.

下節(jié)預(yù)告

下一節(jié)筆者將會引入redis作為游戲的緩存數(shù)據(jù)庫. 當(dāng)游戲玩家變多, 使用緩存數(shù)據(jù)庫可以大幅減小數(shù)據(jù)庫讀寫壓力. 同時redis的特性可以做很多事情, 比如我們可以用redis的incrby來做賬號的遞增而不怕多進(jìn)程中為玩家分配到同一個id; 還可以用作為分布式鎖來實現(xiàn)一些需要多進(jìn)程同時處理的業(yè)務(wù)功能.

http://www.risenshineclean.com/news/55322.html

相關(guān)文章:

  • 保定網(wǎng)站制作推廣公司網(wǎng)絡(luò)推廣合作協(xié)議
  • wordpress能做外貿(mào)網(wǎng)站推廣聯(lián)盟
  • 凱里網(wǎng)站建設(shè)百度快照網(wǎng)址
  • 請人做彩票網(wǎng)站多少錢推廣引流軟件
  • 網(wǎng)站建設(shè)推廣什么意思百度競價排名醫(yī)院事件
  • 頁面素材北京seo運(yùn)營
  • 怎么做免費(fèi)網(wǎng)站如何讓百度收錄可以放友情鏈接的網(wǎng)站
  • 茂港網(wǎng)站開發(fā)公司武漢網(wǎng)站營銷seo方案
  • 做u盤的老外網(wǎng)站整合營銷方案案例
  • 網(wǎng)站開發(fā)語言更換想做網(wǎng)絡(luò)推廣的公司
  • 怎么做班級網(wǎng)站網(wǎng)絡(luò)公司推廣公司
  • 杭州信用網(wǎng)官網(wǎng)小程序seo推廣技巧
  • ??途W(wǎng)官網(wǎng)電商網(wǎng)站seo優(yōu)化
  • 網(wǎng)站開發(fā)公司銷售總監(jiān)崗位要求seo排名優(yōu)化是什么
  • 地圖網(wǎng)站開發(fā)輿情管理
  • 廣州做網(wǎng)站如何網(wǎng)站如何推廣出去
  • 什么是建設(shè)網(wǎng)站的主題口碑營銷的案例有哪些
  • 網(wǎng)站建設(shè)和數(shù)據(jù)容量整合最新實時大數(shù)據(jù)
  • 怎么做網(wǎng)站淘寶轉(zhuǎn)換工具寧波seo關(guān)鍵詞如何優(yōu)化
  • 商城網(wǎng)站開發(fā)seo公司怎樣找客戶
  • 網(wǎng)站英文版是怎么做的北京優(yōu)化seo
  • 沈陽軟件公司 網(wǎng)站制作廣州網(wǎng)站運(yùn)營
  • 做百度推廣送網(wǎng)站嗎重慶網(wǎng)站設(shè)計
  • 中國建設(shè)銀行股份有限公司廣東seo網(wǎng)站設(shè)計
  • 臨沂網(wǎng)站設(shè)計公司seo是什么意思的縮寫
  • 用me做后綴的網(wǎng)站跨境電商平臺
  • 愛南寧app官方下載搜索引擎優(yōu)化的主題
  • 甘肅商城網(wǎng)站建設(shè)創(chuàng)建網(wǎng)站的流程是什么
  • 做網(wǎng)站有必要?在線推廣網(wǎng)站的方法
  • 怎樣注冊公司流程山西seo優(yōu)化公司