商业化游戏好友系统模块架构分析

实现一个高扩展、高性能、高可配置的C#语言商业化射击游戏好友系统模块,需要考虑多个方面,包括系统架构、数据存储、网络通信、安全性、性能优化等。以下是一个详细的架构分析:

1. 系统架构

1.1 分层架构
  • 表示层(Presentation Layer):负责用户界面和用户交互。
  • 业务逻辑层(Business Logic Layer):处理好友系统的业务逻辑。
  • 数据访问层(Data Access Layer):负责与数据库的交互。
  • 网络层(Network Layer):处理客户端与服务器之间的通信。
1.2 微服务架构
  • 好友服务(Friend Service):专门处理好友相关的操作,如添加好友、删除好友、获取好友列表等。
  • 用户服务(User Service):处理用户的基本信息和认证。
  • 通知服务(Notification Service):处理好友请求和通知。

2. 数据存储

2.1 数据库选择
  • 关系型数据库(如MySQL、PostgreSQL):用于存储用户和好友关系数据。
  • NoSQL数据库(如Redis):用于缓存和快速查询。
2.2 数据库设计
  • 用户表(Users):存储用户的基本信息。
  • 好友关系表(Friendships):存储用户之间的好友关系。
  • 好友请求表(FriendRequests):存储好友请求信息。

3. 网络通信

3.1 通信协议
  • HTTP/HTTPS:用于客户端与服务器之间的通信。
  • WebSocket:用于实时通信,如即时消息和通知。
3.2 API设计
  • 添加好友POST /api/friends
  • 删除好友DELETE /api/friends/{friendId}
  • 获取好友列表GET /api/friends
  • 发送好友请求POST /api/friend-requests
  • 接受/拒绝好友请求PUT /api/friend-requests/{requestId}

4. 安全性

4.1 身份验证
  • JWT(JSON Web Token):用于用户身份验证和授权。
4.2 数据加密
  • SSL/TLS:用于加密网络通信。
  • 数据库加密:对敏感数据进行加密存储。

5. 性能优化

5.1 缓存
  • Redis:用于缓存好友列表和好友请求,减少数据库查询次数。
5.2 异步处理
  • 异步编程(async/await):提高系统的并发处理能力。
  • 消息队列(如RabbitMQ):用于处理异步任务,如发送通知。

6. 高可配置性

6.1 配置管理
  • 配置文件(如appsettings.json):存储系统配置。
  • 环境变量:用于存储敏感配置,如数据库连接字符串。
6.2 动态配置
  • 配置中心(如Consul、Etcd):实现配置的动态更新。

7. 示例代码

以下是一个简单的示例代码,展示如何实现好友系统的部分功能:

// FriendService.cs
public class FriendService
{
    private readonly IUserRepository _userRepository;
    private readonly IFriendRepository _friendRepository;

    public FriendService(IUserRepository userRepository, IFriendRepository friendRepository)
    {
        _userRepository = userRepository;
        _friendRepository = friendRepository;
    }

    public async Task AddFriendAsync(Guid userId, Guid friendId)
    {
        var user = await _userRepository.GetUserByIdAsync(userId);
        var friend = await _userRepository.GetUserByIdAsync(friendId);

        if (user == null || friend == null)
        {
            throw new Exception("User not found");
        }

        await _friendRepository.AddFriendAsync(userId, friendId);
    }

    public async Task RemoveFriendAsync(Guid userId, Guid friendId)
    {
        await _friendRepository.RemoveFriendAsync(userId, friendId);
    }

    public async Task<IEnumerable<User>> GetFriendsAsync(Guid userId)
    {
        return await _friendRepository.GetFriendsAsync(userId);
    }
}

// FriendController.cs
[ApiController]
[Route("api/[controller]")]
public class FriendController : ControllerBase
{
    private readonly FriendService _friendService;

    public FriendController(FriendService friendService)
    {
        _friendService = friendService;
    }

    [HttpPost]
    public async Task<IActionResult> AddFriend([FromBody] AddFriendRequest request)
    {
        await _friendService.AddFriendAsync(request.UserId, request.FriendId);
        return Ok();
    }

    [HttpDelete("{friendId}")]
    public async Task<IActionResult> RemoveFriend(Guid friendId)
    {
        var userId = GetUserIdFromToken();
        await _friendService.RemoveFriendAsync(userId, friendId);
        return Ok();
    }

    [HttpGet]
    public async Task<IActionResult> GetFriends()
    {
        var userId = GetUserIdFromToken();
        var friends = await _friendService.GetFriendsAsync(userId);
        return Ok(friends);
    }

    private Guid GetUserIdFromToken()
    {
        // 从JWT Token中获取用户ID
        return Guid.Parse(User.Claims.First(c => c.Type == "id").Value);
    }
}

// AddFriendRequest.cs
public class AddFriendRequest
{
    public Guid UserId { get; set; }
    public Guid FriendId { get; set; }
}

8. 总结

通过以上架构分析和示例代码,我们可以实现一个高扩展、高性能、高可配置的C#语言商业化射击游戏好友系统模块。这个系统可以处理好友的添加、删除、获取好友列表等功能,并且通过缓存、异步处理和安全措施来提高系统的性能和安全性。

9. 详细模块设计

为了更好地实现高扩展、高性能和高可配置的好友系统,我们需要进一步细化各个模块的设计。

9.1 用户服务(User Service)

职责:处理用户的基本信息和认证。

主要功能

  • 用户注册
  • 用户登录
  • 获取用户信息
  • 更新用户信息

示例代码

// UserService.cs
public class UserService
{
    private readonly IUserRepository _userRepository;
    private readonly IPasswordHasher _passwordHasher;
    private readonly ITokenService _tokenService;

    public UserService(IUserRepository userRepository, IPasswordHasher passwordHasher, ITokenService tokenService)
    {
        _userRepository = userRepository;
        _passwordHasher = passwordHasher;
        _tokenService = tokenService;
    }

    public async Task<User> RegisterAsync(string username, string password)
    {
        var hashedPassword = _passwordHasher.HashPassword(password);
        var user = new User { Username = username, PasswordHash = hashedPassword };
        await _userRepository.AddUserAsync(user);
        return user;
    }

    public async Task<string> LoginAsync(string username, string password)
    {
        var user = await _userRepository.GetUserByUsernameAsync(username);
        if (user == null || !_passwordHasher.VerifyPassword(user.PasswordHash, password))
        {
            throw new Exception("Invalid username or password");
        }
        return _tokenService.GenerateToken(user);
    }

    public async Task<User> GetUserByIdAsync(Guid userId)
    {
        return await _userRepository.GetUserByIdAsync(userId);
    }

    public async Task UpdateUserAsync(User user)
    {
        await _userRepository.UpdateUserAsync(user);
    }
}
9.2 好友服务(Friend Service)

职责:处理好友相关的操作,如添加好友、删除好友、获取好友列表等。

主要功能

  • 添加好友
  • 删除好友
  • 获取好友列表
  • 发送好友请求
  • 接受/拒绝好友请求

示例代码

// FriendService.cs
public class FriendService
{
    private readonly IFriendRepository _friendRepository;
    private readonly INotificationService _notificationService;

    public FriendService(IFriendRepository friendRepository, INotificationService notificationService)
    {
        _friendRepository = friendRepository;
        _notificationService = notificationService;
    }

    public async Task SendFriendRequestAsync(Guid userId, Guid friendId)
    {
        await _friendRepository.AddFriendRequestAsync(userId, friendId);
        await _notificationService.SendNotificationAsync(friendId, "You have a new friend request");
    }

    public async Task AcceptFriendRequestAsync(Guid requestId)
    {
        var request = await _friendRepository.GetFriendRequestByIdAsync(requestId);
        if (request == null)
        {
            throw new Exception("Friend request not found");
        }
        await _friendRepository.AddFriendAsync(request.UserId, request.FriendId);
        await _friendRepository.RemoveFriendRequestAsync(requestId);
    }

    public async Task<IEnumerable<User>> GetFriendsAsync(Guid userId)
    {
        return await _friendRepository.GetFriendsAsync(userId);
    }
}
9.3 通知服务(Notification Service)

职责:处理好友请求和通知。

主要功能

  • 发送通知
  • 获取通知列表

示例代码

// NotificationService.cs
public class NotificationService
{
    private readonly INotificationRepository _notificationRepository;

    public NotificationService(INotificationRepository notificationRepository)
    {
        _notificationRepository = notificationRepository;
    }

    public async Task SendNotificationAsync(Guid userId, string message)
    {
        var notification = new Notification { UserId = userId, Message = message, Timestamp = DateTime.UtcNow };
        await _notificationRepository.AddNotificationAsync(notification);
    }

    public async Task<IEnumerable<Notification>> GetNotificationsAsync(Guid userId)
    {
        return await _notificationRepository.GetNotificationsByUserIdAsync(userId);
    }
}

10. 数据库设计

10.1 用户表(Users)
字段名数据类型描述
IdGUID用户唯一标识
UsernameVARCHAR用户名
PasswordHashVARCHAR密码哈希
EmailVARCHAR邮箱
CreatedAtDATETIME创建时间
UpdatedAtDATETIME更新时间
10.2 好友关系表(Friendships)
字段名数据类型描述
IdGUID关系唯一标识
UserIdGUID用户ID
FriendIdGUID好友ID
CreatedAtDATETIME创建时间
10.3 好友请求表(FriendRequests)
字段名数据类型描述
IdGUID请求唯一标识
UserIdGUID发送请求的用户ID
FriendIdGUID接收请求的用户ID
StatusINT请求状态
CreatedAtDATETIME创建时间
10.4 通知表(Notifications)
字段名数据类型描述
IdGUID通知唯一标识
UserIdGUID接收通知的用户ID
MessageVARCHAR通知内容
TimestampDATETIME通知时间

11. 性能优化

11.1 缓存

使用Redis缓存好友列表和好友请求,减少数据库查询次数。

示例代码

// FriendService.cs
public class FriendService
{
    private readonly IFriendRepository _friendRepository;
    private readonly ICacheService _cacheService;

    public FriendService(IFriendRepository friendRepository, ICacheService cacheService)
    {
        _friendRepository = friendRepository;
        _cacheService = cacheService;
    }

    public async Task<IEnumerable<User>> GetFriendsAsync(Guid userId)
    {
        var cacheKey = $"friends_{userId}";
        var cachedFriends = await _cacheService.GetAsync<IEnumerable<User>>(cacheKey);
        if (cachedFriends != null)
        {
            return cachedFriends;
        }

        var friends = await _friendRepository.GetFriendsAsync(userId);
        await _cacheService.SetAsync(cacheKey, friends, TimeSpan.FromMinutes(10));
        return friends;
    }
}
11.2 异步处理

使用异步编程提高系统的并发处理能力。

示例代码

// FriendService.cs
public async Task SendFriendRequestAsync(Guid userId, Guid friendId)
{
    await _friendRepository.AddFriendRequestAsync(userId, friendId);
    await _notificationService.SendNotificationAsync(friendId, "You have a new friend request");
}
11.3 消息队列

使用消息队列(如RabbitMQ)处理异步任务,如发送通知。

示例代码

// NotificationService.cs
public class NotificationService
{
    private readonly IMessageQueue _messageQueue;

    public NotificationService(IMessageQueue messageQueue)
    {
        _messageQueue = messageQueue;
    }

    public async Task SendNotificationAsync(Guid userId, string message)
    {
        var notification = new Notification { UserId = userId, Message = message, Timestamp = DateTime.UtcNow };
        await _messageQueue.PublishAsync("notifications", notification);
    }
}

12. 高可配置性

12.1 配置管理

使用配置文件和环境变量管理系统配置。

示例代码

// appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;"
  },
  "JwtSettings": {
    "SecretKey": "your_secret_key",
    "Issuer": "your_issuer",
    "Audience": "your_audience"
  }
}
12.2 动态配置

使用配置中心(如Consul、Etcd)实现配置的动态更新。

示例代码

// Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddConsulConfig(Configuration);
    // 其他服务配置
}

13. 总结

通过以上详细的模块设计、数据库设计、性能优化和高可配置性实现,我们可以构建一个高扩展、高性能、高可配置的C#语言商业化射击游戏好友系统模块。这个系统可以处理好友的添加、删除、获取好友列表等功能,并且通过缓存、异步处理和安全措施来提高系统的性能和安全性。

14. 详细实现与集成

在实际开发中,我们需要将各个模块集成在一起,并确保它们能够协同工作。以下是一些关键步骤和示例代码,展示如何实现和集成这些模块。

14.1 用户服务实现

用户存储库接口

// IUserRepository.cs
public interface IUserRepository
{
    Task AddUserAsync(User user);
    Task<User> GetUserByIdAsync(Guid userId);
    Task<User> GetUserByUsernameAsync(string username);
    Task UpdateUserAsync(User user);
}

用户存储库实现

// UserRepository.cs
public class UserRepository : IUserRepository
{
    private readonly DbContext _context;

    public UserRepository(DbContext context)
    {
        _context = context;
    }

    public async Task AddUserAsync(User user)
    {
        await _context.Users.AddAsync(user);
        await _context.SaveChangesAsync();
    }

    public async Task<User> GetUserByIdAsync(Guid userId)
    {
        return await _context.Users.FindAsync(userId);
    }

    public async Task<User> GetUserByUsernameAsync(string username)
    {
        return await _context.Users.SingleOrDefaultAsync(u => u.Username == username);
    }

    public async Task UpdateUserAsync(User user)
    {
        _context.Users.Update(user);
        await _context.SaveChangesAsync();
    }
}
14.2 好友服务实现

好友存储库接口

// IFriendRepository.cs
public interface IFriendRepository
{
    Task AddFriendAsync(Guid userId, Guid friendId);
    Task RemoveFriendAsync(Guid userId, Guid friendId);
    Task<IEnumerable<User>> GetFriendsAsync(Guid userId);
    Task AddFriendRequestAsync(Guid userId, Guid friendId);
    Task<FriendRequest> GetFriendRequestByIdAsync(Guid requestId);
    Task RemoveFriendRequestAsync(Guid requestId);
}

好友存储库实现

// FriendRepository.cs
public class FriendRepository : IFriendRepository
{
    private readonly DbContext _context;

    public FriendRepository(DbContext context)
    {
        _context = context;
    }

    public async Task AddFriendAsync(Guid userId, Guid friendId)
    {
        var friendship = new Friendship { UserId = userId, FriendId = friendId, CreatedAt = DateTime.UtcNow };
        await _context.Friendships.AddAsync(friendship);
        await _context.SaveChangesAsync();
    }

    public async Task RemoveFriendAsync(Guid userId, Guid friendId)
    {
        var friendship = await _context.Friendships.SingleOrDefaultAsync(f => f.UserId == userId && f.FriendId == friendId);
        if (friendship != null)
        {
            _context.Friendships.Remove(friendship);
            await _context.SaveChangesAsync();
        }
    }

    public async Task<IEnumerable<User>> GetFriendsAsync(Guid userId)
    {
        return await _context.Friendships
            .Where(f => f.UserId == userId)
            .Select(f => f.Friend)
            .ToListAsync();
    }

    public async Task AddFriendRequestAsync(Guid userId, Guid friendId)
    {
        var request = new FriendRequest { UserId = userId, FriendId = friendId, Status = RequestStatus.Pending, CreatedAt = DateTime.UtcNow };
        await _context.FriendRequests.AddAsync(request);
        await _context.SaveChangesAsync();
    }

    public async Task<FriendRequest> GetFriendRequestByIdAsync(Guid requestId)
    {
        return await _context.FriendRequests.FindAsync(requestId);
    }

    public async Task RemoveFriendRequestAsync(Guid requestId)
    {
        var request = await _context.FriendRequests.FindAsync(requestId);
        if (request != null)
        {
            _context.FriendRequests.Remove(request);
            await _context.SaveChangesAsync();
        }
    }
}
14.3 通知服务实现

通知存储库接口

// INotificationRepository.cs
public interface INotificationRepository
{
    Task AddNotificationAsync(Notification notification);
    Task<IEnumerable<Notification>> GetNotificationsByUserIdAsync(Guid userId);
}

通知存储库实现

// NotificationRepository.cs
public class NotificationRepository : INotificationRepository
{
    private readonly DbContext _context;

    public NotificationRepository(DbContext context)
    {
        _context = context;
    }

    public async Task AddNotificationAsync(Notification notification)
    {
        await _context.Notifications.AddAsync(notification);
        await _context.SaveChangesAsync();
    }

    public async Task<IEnumerable<Notification>> GetNotificationsByUserIdAsync(Guid userId)
    {
        return await _context.Notifications
            .Where(n => n.UserId == userId)
            .ToListAsync();
    }
}
14.4 缓存服务实现

缓存服务接口

// ICacheService.cs
public interface ICacheService
{
    Task<T> GetAsync<T>(string key);
    Task SetAsync<T>(string key, T value, TimeSpan expiration);
}

缓存服务实现

// RedisCacheService.cs
public class RedisCacheService : ICacheService
{
    private readonly IConnectionMultiplexer _redis;

    public RedisCacheService(IConnectionMultiplexer redis)
    {
        _redis = redis;
    }

    public async Task<T> GetAsync<T>(string key)
    {
        var db = _redis.GetDatabase();
        var value = await db.StringGetAsync(key);
        if (value.IsNullOrEmpty)
        {
            return default;
        }
        return JsonConvert.DeserializeObject<T>(value);
    }

    public async Task SetAsync<T>(string key, T value, TimeSpan expiration)
    {
        var db = _redis.GetDatabase();
        var json = JsonConvert.SerializeObject(value);
        await db.StringSetAsync(key, json, expiration);
    }
}
14.5 消息队列服务实现

消息队列接口

// IMessageQueue.cs
public interface IMessageQueue
{
    Task PublishAsync<T>(string queueName, T message);
}

消息队列实现

// RabbitMQService.cs
public class RabbitMQService : IMessageQueue
{
    private readonly IConnection _connection;

    public RabbitMQService(IConnection connection)
    {
        _connection = connection;
    }

    public async Task PublishAsync<T>(string queueName, T message)
    {
        using (var channel = _connection.CreateModel())
        {
            channel.QueueDeclare(queue: queueName, durable: false, exclusive: false, autoDelete: false, arguments: null);
            var body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));
            channel.BasicPublish(exchange: "", routingKey: queueName, basicProperties: null, body: body);
        }
        await Task.CompletedTask;
    }
}

15. 集成与测试

15.1 集成

在实际项目中,我们需要将各个服务和存储库集成在一起,并在启动时进行配置。

Startup.cs

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 配置数据库上下文
        services.AddDbContext<DbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        // 配置存储库
        services.AddScoped<IUserRepository, UserRepository>();
        services.AddScoped<IFriendRepository, FriendRepository>();
        services.AddScoped<INotificationRepository, NotificationRepository>();

        // 配置服务
        services.AddScoped<UserService>();
        services.AddScoped<FriendService>();
        services.AddScoped<NotificationService>();

        // 配置缓存
        services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(Configuration.GetConnectionString("Redis")));
        services.AddSingleton<ICacheService, RedisCacheService>();

        // 配置消息队列
        services.AddSingleton<IConnection>(sp => {
            var factory = new ConnectionFactory() { Uri = new Uri(Configuration.GetConnectionString("RabbitMQ")) };
            return factory.CreateConnection();
        });
        services.AddSingleton<IMessageQueue, RabbitMQService>();

        // 配置控制器
        services.AddControllers();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}
15.2 测试

为了确保系统的稳定性和可靠性,我们需要进行单元测试和集成测试。

单元测试示例

// FriendServiceTests.cs
public class FriendServiceTests
{
    private readonly Mock<IFriendRepository> _friendRepositoryMock;
    private readonly Mock<INotificationService> _notificationServiceMock;
    private readonly FriendService _friendService;

    public FriendServiceTests()
    {
        _friendRepositoryMock = new Mock<IFriendRepository>();
        _notificationServiceMock = new Mock<INotificationService>();
        _friendService = new FriendService(_friendRepositoryMock.Object, _notificationServiceMock.Object);
    }

    [Fact]
    public async Task SendFriendRequestAsync_ShouldAddFriendRequestAndSendNotification()
    {
        // Arrange
        var userId = Guid.NewGuid();
        var friendId = Guid.NewGuid();

        // Act
        await _friendService.SendFriendRequestAsync(userId, friendId);

        // Assert
        _friendRepositoryMock.Verify(r => r.AddFriendRequestAsync(userId, friendId), Times.Once);
        _notificationServiceMock.Verify(n => n.SendNotificationAsync(friendId, "You have a new friend request"), Times.Once);
    }
}

集成测试示例

// FriendControllerTests.cs
public class FriendControllerTests : IClassFixture<WebApplicationFactory<Startup>>
{
    private readonly HttpClient _client;

    public FriendControllerTests(WebApplicationFactory<Startup> factory)
    {
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task AddFriend_ShouldReturnOk()
    {
        // Arrange
        var request = new AddFriendRequest { UserId = Guid.NewGuid(), FriendId = Guid.NewGuid() };
        var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, "application/json");

        // Act
        var response = await _client.PostAsync("/api/friends", content);

        // Assert
        response.EnsureSuccessStatusCode();
    }
}

16. 部署与运维

16.1 部署

在部署阶段,我们需要确保系统能够在生产环境中稳定运行。可以使用容器化技术(如Docker)和编排工具(如Kubernetes)来简化部署过程。

Dockerfile

# 使用官方的 .NET Core SDK 镜像作为基础镜像
FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /app

# 复制项目文件并还原依赖项
COPY *.csproj ./
RUN dotnet restore

# 复制其余文件并构建项目
COPY . ./
RUN dotnet publish -c Release -o out

# 使用官方的 .NET Core 运行时镜像作为基础镜像
FROM mcr.microsoft.com/dotnet/aspnet:5.0
WORKDIR /app
COPY --from=build /app/out .

# 暴露端口
EXPOSE 80

# 运行应用程序
ENTRYPOINT ["dotnet", "YourApp.dll"]

Kubernetes Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: friend-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: friend-service
  template:
    metadata:
      labels:
        app: friend-service
    spec:
      containers:
      - name: friend-service
        image: your-docker-repo/friend-service:latest
        ports:
        - containerPort: 80
        env:
        - name: ConnectionStrings__DefaultConnection
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: connectionString
        - name: JwtSettings__SecretKey
          valueFrom:
            secretKeyRef:
              name: jwt-credentials
              key: secretKey
16.2 运维

在运维阶段,我们需要监控系统的运行状态,并及时处理异常情况。可以使用监控工具(如Prometheus、Grafana)和日志管理工具(如ELK Stack)来实现。

Prometheus配置

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'friend-service'
    static_configs:
      - targets: ['friend-service:80']

Grafana配置

在Grafana中添加Prometheus数据源,并创建仪表盘监控系统的关键指标,如请求数、响应时间、错误率等。

17. 总结

通过以上详细的实现与集成步骤,我们可以构建一个高扩展、高性能、高可配置的C#语言商业化射击游戏好友系统模块。这个系统可以处理好友的添加、删除、获取好友列表等功能,并且通过缓存、异步处理和安全措施来提高系统的性能和安全性。通过单元测试和集成测试,我们可以确保系统的稳定性和可靠性。最后,通过容器化和编排工具,我们可以简化部署过程,并通过监控工具和日志管理工具实现系统的运维。

  • 12
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛掰是怎么形成的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值