当前位置: 首页 > news >正文

手机网站开发c自建网站定位

手机网站开发c,自建网站定位,做策划有帮助的网站,免费物业网站模板目录 前言正文添加依赖安装MongoDB添加MongoDB相关配置创建MongoContext类尝试初始化DB连接实现注册功能测试注册功能实现登录逻辑测试登录流程 结语下节预告 前言 游戏服务器中, 很重要的一点就是如何保存玩家的游戏数据. 当一个服务端架构趋于稳定且功能全面, 开发者会发现服… 目录 前言正文添加依赖安装MongoDB添加MongoDB相关配置创建MongoContext类尝试初始化DB连接实现注册功能测试注册功能实现登录逻辑测试登录流程 结语下节预告 前言 游戏服务器中, 很重要的一点就是如何保存玩家的游戏数据. 当一个服务端架构趋于稳定且功能全面, 开发者会发现服务端的业务开发基本就围绕着CRUD来展开, 即业务数据的创建 \ 查找 \ 更新 \ 删除. 本节内容我们就将MongoDB作为持久化数据库引入项目中. 正文 添加依赖 在build.gradle中添加依赖 implementation org.springframework.data:spring-data-mongodb:4.2.4 implementation org.mongodb:mongodb-driver-sync:5.0.0安装MongoDB MongoDB的安装步骤我就不一一解释了, 读者可以选择使用docker快速创建一个MongoDB容器, 也可以使用MongoDB官方提供的免费云数据库进行练习 https://www.mongodb.com/cloud/atlas/register 也可以在本地运行一个MongoDB进程 添加MongoDB相关配置 在common模块下添加common.conf配置文件以及CommonConfig类. mongodb.hostmongodb://%s:%slocalhost:27017/%s?retryWritestruewmajority mongodb.userroot mongodb.password123456 # 登录服数据库名 mongodb.login.dbloginGetter 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; } 创建MongoContext类 为了管理MongoDB连接, 创建一个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 数据库。 而MongoTemplate是spring-data-mongodb库的核心, 它基于MongoClient进行了接口封装, 提供了比 MongoClient 更丰富的功能包括更简洁的查询构建、更强大的映射支持。 在MongoContext外层封装一层MongoService用来实现Mongo增删改查相关接口。 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;}/*** 插入数据*/public T extends BaseCollection boolean insert(T obj) {mongoContext.getMongoTemplate().insert(obj);return true;}/*** 查询数据*/public T extends BaseCollection BaseCollection findById(Object id, ClassT clz) {T object mongoContext.getMongoTemplate().findById(id, clz);return object;}public T extends BaseCollection T findOneByQuery(Criteria criteria, ClassT clz) {Query query Query.query(criteria);T object mongoContext.getMongoTemplate().findOne(query, clz);return object;}//TODO 删//TODO 改先实现了增查以便我们后面实现账号注册登录功能来举例。 尝试初始化DB连接 在LoginServer的initServer下面增加MongoContext的初始化代码. 然后运行. Overrideprotected void initServer() {LoginConfig config SpringUtils.getBean(LoginConfig.class);// actor初始化AkkaContext.initActorSystem();// netty启动NettyServer nettyServer SpringUtils.getBean(NettyServer.class);nettyServer.start(config.getPort());// mongo服务启动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得到结果: 实现注册功能 上一节我们使用Protobuf创建了注册协议, 从客户端发送到了登录服进行解析. 接下来我们将注册的账号密码进行入库以便后续取出使用. 我们先构思一下一个账号应该有的数据, 创建一个AccountCollection类, 用于映射Mongo数据库中的AccountCollection表. Document public class AccountCollection extends BaseCollection {Idprivate long accountId;private String accountName;private String password;// getter setter }很好理解, Document注解表示该类是一个mongo的文档映射类, Id表示这个字段作为该文档的主键. BaseCollection目前就是一个空的Abstract类, 实现了Serializable接口. public abstract class BaseCollection implements Serializable { }接下来修改ConnectActor中的onClientUpMsg方法, 该方法负责接收客户端上行协议并进行解包. private BehaviorBaseMsg 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) {// 注册协议LoginProtoHandler.onPlayerRegisterMsg(this, PlayerMsg.C2SPlayerRegister.parseFrom(data));}return this;}我增加了一个LoginProtoHandler类用于处理登录相关的业务逻辑. 若是将所有的代码都写在ConnectActor, 将来这里的代码会越来越长最终变得不可控. 使用单一职责的思想, 使ConnectActor只负责进行协议的解包, 具体业务逻辑由各个功能模块自己实现, 将来游戏服我们也会这么处理, 这里只简单提一嘴. 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负责处理客户端上行的关于账号登录相关的协议. onPlayerRegisterMsg负责账号注册相关逻辑. 由于账号Id的生成规则我还没想好, 先用一个1L来进行测试, 然后我们调用MongoService的insert方法, 将accountCollection写入mongo. 并进行回包. 修改ClientMain, 使我们在输入register时, 发送注册协议进行账号的注册. 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);}}这里顺便把登录的协议一并附上, 没啥技术含量就不多讲. 测试注册功能 启动登录服, 启动客户端, 客户端控制台输入register. 看看登录服的打印: 再看看mongo中数据是否写入成功: 可以看到确实写入了一条AccountCollection文档, 字段_id为每个collection的主键, 他的数值也就是我们使用Id注解标识的字段, 另外_class是spring-data-mongo库为我们添加的类名, 用于读取数据时反序列化用. 需要注意的是如果你的AccountCollection类修改了包名或类名, 这里反序列化就会失败, 需要额外添加处理. 实现登录逻辑 登录与注册相差不大, 只是把添加数据修改为查找数据. 修改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创建一个条件, 根据accountName来查找一条mongo中的文档, 然后对比密码是否一致, 来实现登录流程. 修改ConnectActor使其对Login协议进行解包并分发到LoginProtoHandler中. private BehaviorBaseMsg 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) {// 注册协议LoginProtoHandler.onPlayerRegisterMsg(this, PlayerMsg.C2SPlayerRegister.parseFrom(data));} else if (decode.getCmdId() ProtoEnumMsg.CMD.ID.PLAYER_LOGIN_VALUE) {// 登录协议LoginProtoHandler.onPlayerLoginMsg(this, PlayerMsg.C2SPlayerLogin.parseFrom(data));}return this;} 测试登录流程 启动登录服, 启动客户端, 客户端控制台输入login. 看看登录服的打印: 结语 本节我们将MongoDB引入到项目中作为我们的持久化数据库来使用, 并通过注册登录的两个小例子, 来展示spring-data-mongo这个库的用法. 我们只需要定好映射类, 便算是搭建好了一张表结构, 使用起来还是很简单的, 当然我们后面还会继续对其封装, 减少业务开发人员对MongoService的直接调用. 另外, 我们实现的注册登录例子十分粗糙, 其实只是做了一次mongo的读写, 对于游戏服务器来说, 注册登录功能是重中之重, 它维护着玩家的账号安全, 同时也是我们整个游戏的入口. 对于账号注册, 我们还需要做 账号id生成, 账号名重复性检测, accountId与accountName的缓存映射, 后期还有sdk接入等工作. 对于账号登录, 我们还需要做 登录状态修改, 多点登录顶号, 分配游戏服 等工作. 这些我们后面会继续优化. 下节预告 下一节笔者将会引入redis作为游戏的缓存数据库. 当游戏玩家变多, 使用缓存数据库可以大幅减小数据库读写压力. 同时redis的特性可以做很多事情, 比如我们可以用redis的incrby来做账号的递增而不怕多进程中为玩家分配到同一个id; 还可以用作为分布式锁来实现一些需要多进程同时处理的业务功能.
http://www.tj-hxxt.cn/news/141411.html

相关文章:

  • 做网站模板在哪儿找全国免费分类信息发布平台
  • 技术先进的网站建设婚庆公司多少钱
  • 电商网站设计公司只选亿企邦南宁网站开发培训学校
  • 网站作业成品珠海培训网站建设
  • 花木公司网站源码百度正版下载并安装
  • 做网站设计要适配到手机端么广东建设部官方网站
  • 网站自助平台福建网站开发公司电话
  • 开源程序做网站手机有软件做ppt下载网站
  • 建个网站需要多少钱在线做3d交互的网站
  • 网站建设官网分类目录
  • 网站建设完成外网无法访问WordPress文章批量生成器
  • 长沙做痔疮东大医院de网站wordpress5.6
  • 网站品牌建设建议云指官网
  • 给几个手机网站手机网站首页
  • 济宁网站建设软件百度推广登录网站
  • 百度搜索显示网站logo北京网站建设华网天下
  • 该产品在英文站及多语言网站梅州seo
  • 自己制作头像的网站 设计 动漫莆田做网站建设
  • 包头建网站公司哪家强网站优化方案 site ww
  • 大同网站开发广州小程序商城开发公司
  • 导航网站怎么做点击忘记wordpress的账号和密码忘记
  • 网站备案流程解答佛山网站推广seo
  • 嘉兴网站建设公司做网站不赚钱了
  • 西安直播网站开发站长工具国产2023
  • 个人网站备案取消视觉传达设计好找工作吗
  • 简网站建设流程步骤免费商业wordpress主题
  • 徐州 网站建设线上推广活动策划方案
  • 网站建设要哪些人信息备案管理系统官网
  • 邢台哪个公司做网站建个企业网站一年需要多少钱
  • seo网站外包公司环保公司网站模板