SpringBoot框架:入门指南(二)

17 篇文章 0 订阅

一. RESTful API开发

1. 创建RESTful控制器

在企业级Java开发中,RESTful API扮演着至关重要的角色,为系统提供了灵活、可扩展的接口。下面将详细介绍如何创建高质量的RESTful控制器,充分利用Spring Boot注解。

1.1 RESTful设计原则

RESTful API设计遵循一系列原则,以确保接口的清晰性、可读性和易维护性。这些原则包括:

  • 资源识别与URI设计: 识别业务资源,并采用清晰的URI结构表示。例如,/users/{id}表示单个用户资源。

  • HTTP方法的正确使用: 利用HTTP方法来执行对资源的操作。GET用于获取资源,POST用于创建资源,PUT和PATCH用于更新资源,DELETE用于删除资源。

  • 状态码的合理应用: 使用适当的HTTP状态码表示操作的结果,如200表示成功,404表示未找到,500表示服务器错误等。

1.2 Spring Boot注解的运用

Spring Boot简化了RESTful API的开发过程,通过注解轻松搭建API。以下是一些关键注解的用法:

  • @RestController: 将类标记为RESTful控制器,自动处理HTTP请求。

  • @RequestMapping: 指定URL路径,定义处理请求的方法。

  • @GetMapping/@PostMapping: 指定GET或POST请求的处理方法,简化了代码。

1.3 示例代码

让我们通过一个简单的示例来演示RESTful控制器的创建:

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User createdUser = userService.createUser(user);
        URI location = ServletUriComponentsBuilder.fromCurrentRequest()
                          .path("/{id}")
                          .buildAndExpand(createdUser.getId())
                          .toUri();
        return ResponseEntity.created(location).body(createdUser);
    }
}

在这个示例中,我们使用了Spring Boot的注解,创建了一个处理用户资源的RESTful控制器。通过@GetMapping@PostMapping注解,我们定义了获取用户和创建用户的操作。ResponseBody和ResponseEntity用于处理响应体和状态码。

2. 处理HTTP请求与响应

在RESTful API开发中,深入理解HTTP协议并实现统一的错误处理机制对于构建可靠的API至关重要。下面将详细介绍在Java控制器中如何处理不同类型的HTTP请求,以及如何实现统一的错误处理。

2.1 深入了解HTTP协议

HTTP基础知识

了解HTTP协议的基础知识对于处理请求和响应至关重要。HTTP是一种无状态协议,每个请求都是独立的,不会记住之前的请求。了解HTTP方法(GET、POST、PUT、DELETE等)、头部信息和状态码等是必须的。

控制器中的HTTP请求处理

在Java控制器中,可以使用Spring Boot注解来处理不同类型的HTTP请求。例如:

  • @GetMapping: 处理GET请求
  • @PostMapping: 处理POST请求
  • @PutMapping: 处理PUT请求
  • @DeleteMapping: 处理DELETE请求

通过这些注解,可以轻松定义不同操作的处理方法,确保遵循RESTful设计原则。

2.2 统一的错误处理机制

异常处理

在API开发中,异常处理是不可忽视的一环。通过统一处理异常,可以提高API的可靠性和可维护性。在Spring Boot中,可以使用@ControllerAdvice注解创建全局异常处理器。示例代码如下:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception ex) {
        ErrorResponse errorResponse = new ErrorResponse("Internal Server Error", HttpStatus.INTERNAL_SERVER_ERROR.value());
        return new ResponseEntity<>(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFoundException(ResourceNotFoundException ex) {
        ErrorResponse errorResponse = new ErrorResponse(ex.getMessage(), HttpStatus.NOT_FOUND.value());
        return new ResponseEntity<>(errorResponse, HttpStatus.NOT_FOUND);
    }
}

在这个例子中,@ControllerAdvice标记了全局异常处理器,@ExceptionHandler用于捕获特定类型的异常并返回适当的响应。

自定义错误响应

创建一个自定义的错误响应类(例如ErrorResponse),用于包装错误信息,提供清晰的错误反馈给API的调用者。

public class ErrorResponse {
    private String message;
    private int statusCode;

    // 省略构造方法和getter/setter
}
3. 示例代码
@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable Long id) {
        User user = userService.getUserById(id);
        if (user == null) {
            throw new ResourceNotFoundException("User not found with id: " + id);
        }
        return ResponseEntity.ok(user);
    }

    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        User createdUser = userService.createUser(user);
        URI location = ServletUriComponentsBuilder.fromCurrentRequest()
                          .path("/{id}")
                          .buildAndExpand(createdUser.getId())
                          .toUri();
        return ResponseEntity.created(location).body(createdUser);
    }
}

在这个示例中,通过@GetMapping@PostMapping处理GET和POST请求。如果在GET请求中找不到用户,抛出ResourceNotFoundException,由全局异常处理器捕获并返回适当的错误响应。

  1. 使用Postman进行接口测试
    • 利用Postman进行全面的接口测试,包括请求验证、响应断言等。
    • 掌握Mock Server的使用,模拟接口行为,确保系统在各种情况下都能正常运行。

二. 数据库访问与整合

1. 使用Spring Data JPA进行数据库操作

在企业级Java开发中,与数据库的高效交互是至关重要的一环。Spring Data JPA为我们提供了简化数据库操作的工具,以下是关于使用Spring Data JPA的基本概念和常见操作的介绍。

1.1 JPA基本概念

Java Persistence API (JPA) 是一种用于管理Java应用程序中关系型数据的标准规范。它提供了一种将Java对象映射到数据库表的方法,同时定义了一套查询语言(JPQL)用于数据库查询。

  • 实体类: 通过注解标记Java类,使其成为JPA实体,与数据库表进行映射。
  • Repository接口: 继承JpaRepository接口,通过继承接口的方法实现常见的数据库操作。
1.2 Spring Data JPA的使用

示例:使用Spring Data JPA进行用户管理

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String email;

    // 省略构造方法和getter/setter
}
public interface UserRepository extends JpaRepository<User, Long> {
    // 可通过继承JpaRepository接口实现常见的CRUD操作
    Optional<User> findByUsername(String username);
}
1.3 常见的CRUD操作

使用Spring Data JPA,常见的CRUD操作可以通过继承JpaRepository接口来实现:

  • 保存用户:

    userRepository.save(user);
    
  • 根据ID查询用户:

    Optional<User> userOptional = userRepository.findById(userId);
    
  • 根据用户名查询用户:

    Optional<User> userOptional = userRepository.findByUsername(username);
    
  • 更新用户信息:

    User existingUser = userRepository.findById(userId).orElse(null);
    if (existingUser != null) {
        existingUser.setEmail(newEmail);
        userRepository.save(existingUser);
    }
    
  • 删除用户:

    userRepository.deleteById(userId);
    
1.4 使用JPQL查询语言

除了常见的CRUD操作外,Spring Data JPA还支持使用JPQL进行自定义查询:

public interface UserRepository extends JpaRepository<User, Long> {
    @Query("SELECT u FROM User u WHERE u.email = :email")
    Optional<User> findByEmail(@Param("email") String email);
}

通过@Query注解,可以在Repository接口中定义自定义的JPQL查询方法,以实现更复杂的数据库查询需求。


2. 配置数据源与持久化

在复杂业务场景下,可能需要配置多数据源以处理不同数据库的访问。同时,理解事务管理对于确保数据库操作的一致性至关重要。

2.1 配置多数据源

Spring Boot允许配置多个数据源,可以通过@Primary注解标记主要数据源,通过@Qualifier注解指定使用哪个数据源。

@Configuration
public class DataSourceConfig {

    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource dataSourceSecondary() {
        return DataSourceBuilder.create().build();
    }
}
2.2 事务管理

在涉及到多个数据库操作时,事务管理是确保操作一致性的关键。通过使用@Transactional注解,可以将一系列操作包装在一个事务中,确保它们要么全部成功,要么全部失败。

@Service
public class TransactionalService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private AnotherRepository anotherRepository;

    @Transactional
    public void performTransaction() {
        // 数据库操作
        userRepository.save(new User("John", "john@example.com"));
        anotherRepository.save(new AnotherEntity("Some data"));
    }
}

3. 实现简单的数据库操作

通过实际案例演示数据库操作,包括关联查询、分页查询等,可以更好地理解数据库访问与整合的实际应用。

public interface OrderRepository extends JpaRepository<Order, Long> {

    List<Order> findByUserId(Long userId);

    Page<Order> findByStatus(String status, Pageable pageable);
}

在这个例子中,findByUserId实现了根据用户ID查询订单的操作,而findByStatus实现了根据订单状态进行分页查询的操作。

三. Web开发与Thymeleaf模板引擎

1. 创建Web页面

在Web开发中,使用Spring Boot可以快速创建基本的Web页面。以下是一些步骤和注意事项:

1.1 使用Spring Boot创建Web项目

通过Spring Initializer或使用Spring Boot CLI,创建一个基本的Spring Boot项目,并选择Web作为依赖。

1.2 遵循前后端分离原则

采用前后端分离的原则,前端负责页面的展示和用户交互,后端负责提供数据和处理业务逻辑。前后端之间通过API进行通信,通常使用JSON格式传递数据。

1.3 实现清晰的前后端交互

定义清晰的API接口,确保前端能够方便地调用后端服务。使用RESTful风格的API,明确定义HTTP方法和URI路径。

2. 使用Thymeleaf渲染页面

Thymeleaf是一款强大的Java模板引擎,可用于在Web应用中渲染动态页面。以下是使用Thymeleaf的基本步骤:

2.1 引入Thymeleaf依赖

pom.xml中引入Thymeleaf依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
</dependencies>
2.2 创建Thymeleaf模板

src/main/resources/templates目录下创建Thymeleaf模板文件,例如index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Thymeleaf Example</title>
</head>
<body>
    <h1 th:text="${message}">Hello World!</h1>
</body>
</html>
2.3 在Controller中使用Thymeleaf

在Controller中处理请求时,返回Thymeleaf模板的名称:

@Controller
public class MyController {

    @GetMapping("/hello")
    public String hello(Model model) {
        model.addAttribute("message", "Welcome to Thymeleaf!");
        return "index";
    }
}
2.4 实现动态数据的展示

Thymeleaf支持动态数据的展示,通过在模板中使用${variable}来引用Controller中传递的数据。

3. 实现基本的Web应用

结合RESTful API,构建完整的Web应用。以下是一些建议和步骤:

3.1 使用Ajax等技术实现异步交互

通过Ajax等技术,实现页面的异步加载和交互。这可以提高页面加载速度和用户体验。

3.2 构建完整的Web应用

将前端页面与后端API整合,构建一个完整的Web应用。确保前端能够通过API调用后端服务,并正确处理返回的数据。

3.3 前后端分离的优势

前后端分离可以提高项目的可维护性和灵活性。前端可以独立开发和测试,后端可以专注于业务逻辑和数据处理。

四. 单元测试与集成测试

1. 编写基本的单元测试

编写单元测试是保障代码质量的关键步骤。以下是一些建议和步骤:

1.1 使用JUnit等测试框架

JUnit是Java中广泛使用的测试框架,用于编写和运行单元测试。创建测试类,使用@Test注解标记测试方法,断言方法的预期行为。

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyServiceTest {

    @Test
    public void testAdd() {
        MyService myService = new MyService();
        int result = myService.add(2, 3);
        assertEquals(5, result);
    }
}
1.2 引入Mockito等工具

Mockito是一个用于模拟对象行为的框架,可以帮助我们创建虚拟对象,确保代码的可测试性。使用@Mock@InjectMocks注解,结合whenthenReturn方法,模拟对象的行为。

import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.when;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyServiceTest {

    @Mock
    private MyRepository myRepository;

    @InjectMocks
    private MyService myService;

    @Test
    public void testGetData() {
        when(myRepository.getData()).thenReturn("Mocked Data");
        String result = myService.getData();
        assertEquals("Mocked Data", result);
    }
}

2. 使用Spring Boot Test进行测试

Spring Boot Test是Spring Boot中专门用于测试的模块,它提供了一系列的注解和工具,用于编写和执行各种类型的测试。

2.1 掌握Spring Boot Test的使用

使用@SpringBootTest注解可以加载整个Spring应用程序上下文,方便进行集成测试。

import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class MyIntegrationTest {

    // 测试代码
}
2.2 制定测试策略

在编写测试时,制定测试策略是非常重要的。包括选择适当的测试粒度、定义测试数据、确保测试的独立性等。使用@Transactional注解可以在测试完成后回滚数据库事务,保持数据库的一致性。

import org.springframework.transaction.annotation.Transactional;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
@Transactional
public class MyIntegrationTest {

    // 测试代码
}

3. 编写集成测试

集成测试用于验证系统不同模块的协同工作,确保系统功能完备。以下是一些建议:

3.1 利用集成测试验证系统不同模块的协同工作

编写集成测试时,需要关注系统不同组件之间的协同工作。确保集成测试覆盖了系统的主要功能路径。

3.2 使用真实的依赖

在集成测试中,通常使用真实的依赖(如数据库、消息队列等)而非模拟对象,以更真实地模拟实际系统环境。

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;

@SpringBootTest
@AutoConfigureTestDatabase
public class MyIntegrationTest {

    // 测试代码
}

通过以上步骤,你将能够编写基本的单元测试,使用Mockito等工具模拟对象行为,掌握Spring Boot Test的使用进行集成测试,编写集成测试验证系统不同模块的协同工作。这将有助于确保代码的质量和系统的稳定性。

五. 安全性与身份认证

1. 引入Spring Security

保障系统的安全性是应用程序开发中的一项关键任务。引入Spring Security可以提供全面的安全防护。

1.1 了解常见的安全威胁

在引入Spring Security之前,了解常见的安全威胁是非常重要的。这些威胁包括但不限于:身份伪造、SQL注入、跨站脚本攻击(XSS)、跨站请求伪造(CSRF)等。

1.2 配置基本的身份认证策略

Spring Security提供了强大的身份认证和授权机制。通过配置,可以定义哪些用户能够访问系统的哪些资源。以下是一个简单的示例:

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .logoutUrl("/logout")
                .permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("{noop}password").roles("USER")
                .and()
                .withUser("admin").password("{noop}password").roles("USER", "ADMIN");
    }
}

在上述示例中,配置了基于角色的权限管理,并定义了登录和注销的行为。

2. 配置基本的身份认证

身份认证是保障系统安全性的重要一环。通过Spring Security,可以轻松配置基本的身份认证。

2.1 使用Spring Security配置用户认证和授权

通过实现UserDetailsService接口,可以自定义用户认证和授权的逻辑。以下是一个简单的示例:

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
        return new CustomUserDetails(user);
    }
}
2.2 实现基于角色的权限管理

通过配置角色和权限,可以实现基于角色的权限管理。在上述的Spring Security配置示例中,使用.hasRole("ADMIN")指定了某个URL需要ADMIN角色才能访问。

3. 安全防护措施简介

在开发过程中,需要注意一些常见的安全防护措施,以防止常见的攻击。以下是一些防范措施的简介:

3.1 防止SQL注入

使用预编译语句或ORM框架,避免直接拼接SQL语句。Spring Data JPA等框架提供了防范SQL注入的机制。

3.2 防止跨站脚本攻击(XSS)

对用户输入的内容进行合适的过滤和转义,避免在页面中执行恶意脚本。Thymeleaf等模板引擎可以帮助防范XSS攻击。

3.3 防止跨站请求伪造(CSRF)

使用Spring Security等工具,配置CSRF保护机制。确保每个请求都带有CSRF令牌,防止恶意站点伪造请求。

通过以上步骤,你将能够了解常见的安全威胁,引入Spring Security进行全面的安全防护,配置基本的身份认证策略,确保系统只允

许合法访问。此外,了解安全防护措施,并通过Spring Security等工具来防范常见攻击,将有助于提高系统的安全性。

六. 性能优化与监控

1. 集成Actuator进行监控

Spring Boot Actuator是Spring Boot提供的监控和管理工具。通过集成Actuator,可以方便地监控应用的各项指标,并进行性能分析。

1.1 配置Spring Boot Actuator

pom.xml中引入Actuator依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

application.propertiesapplication.yml中开启Actuator的各项功能:

management:
  endpoints:
    web:
      exposure:
        include: '*'
1.2 利用监控数据进行性能分析

Actuator提供了众多的监控端点,比如/actuator/health/actuator/metrics等。通过访问这些端点,可以获取应用的健康状况和各项指标数据。根据这些数据进行分析,找出潜在的性能瓶颈。

2. 性能优化的基本策略

性能优化是系统开发和维护中的一个重要方面。以下是一些建议和基本策略:

2.1 优化数据库查询
  • 使用合适的索引,加速查询。
  • 考虑使用数据库连接池,减少连接的创建和销毁开销。
  • 尽量避免全表扫描,使用合适的查询条件。
2.2 缓存的合理使用
  • 使用缓存来存储频繁访问的数据,减轻数据库压力。
  • 选择合适的缓存策略,如LRU(Least Recently Used)等。
  • 注意缓存的及时更新和过期机制。
2.3 代码优化
  • 使用合适的数据结构和算法。
  • 避免过多的嵌套循环和递归调用。
  • 尽量减少不必要的对象创建。

3. 使用Spring Boot Admin进行监控

Spring Boot Admin是一个用于监控和管理Spring Boot应用的开源项目。通过引入Spring Boot Admin,可以更直观地监控应用的各项指标。

3.1 引入Spring Boot Admin

pom.xml中引入Spring Boot Admin依赖:

<dependencies>
    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-starter-server</artifactId>
        <version>2.5.1</version>
    </dependency>
</dependencies>
3.2 配置Spring Boot Admin

application.propertiesapplication.yml中配置Spring Boot Admin的端口和上下文路径:

server:
  port: 8081

spring:
  boot:
    admin:
      context-path: /admin
3.3 启动Spring Boot Admin Server
import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableAdminServer
@SpringBootApplication
public class AdminApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminApplication.class, args);
    }
}

启动应用后,访问http://localhost:8081/admin即可查看Spring Boot Admin的监控界面。

通过以上步骤,你将能够配置Spring Boot Actuator进行监控,利用监控数据进行性能分析,了解性能优化的基本策略,以及引入Spring Boot Admin实现更直观的应用监控和管理。这将有助于提高系统的性能和稳定性。

七. 部署与运维

1. 打包与部署Spring Boot应用

1.1 使用Maven或Gradle进行项目打包

通过Maven或Gradle等构建工具,可以方便地对Spring Boot应用进行打包。在项目根目录下执行以下命令:

使用Maven:

mvn clean package

使用Gradle:

./gradlew clean build
1.2 部署应用到不同的环境

部署Spring Boot应用时,通常会涉及到不同的环境,如开发环境、测试环境和生产环境。使用不同的配置文件或环境变量,确保应用在不同环境中的配置灵活性。

2. Docker容器化

2.1 Docker化Spring Boot应用

Docker是一种轻量级的容器技术,可以实现跨平台部署。通过创建Docker镜像,可以将应用与其依赖打包在一起,实现一次构建,随处运行。

创建Dockerfile:

FROM openjdk:11-jre-slim
COPY target/my-spring-boot-app.jar /app.jar
CMD ["java", "-jar", "/app.jar"]

构建Docker镜像:

docker build -t my-spring-boot-app .
2.2 使用Docker Compose管理多容器应用

Docker Compose是用于定义和运行多容器Docker应用的工具。通过编写docker-compose.yml文件,可以定义应用的各个组件,实现一键启动。

version: '3'
services:
  my-spring-boot-app:
    image: my-spring-boot-app
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=production
  database:
    image: mysql:latest
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=mydb

运行Docker Compose:

docker-compose up

3. 使用Heroku进行云端部署

3.1 介绍Heroku云平台

Heroku是一种云平台服务,支持多种编程语言,提供简单而高效的云端部署。通过Heroku,可以轻松地将应用部署到云上,无需关心基础设施。

3.2 利用Heroku提供的服务

Heroku提供了多种服务,如数据库、缓存、日志等。通过添加相应的插件,可以扩展应用的功能。

在项目根目录创建Procfile文件,指定启动命令:

web: java -jar target/my-spring-boot-app.jar

部署到Heroku:

heroku create
git push heroku master

通过以上步骤,你将能够使用Maven或Gradle进行项目打包,部署应用到不同的环境,将Spring Boot应用Docker化,使用Docker Compose管理多容器应用,以及通过Heroku进行简单而高效的云端部署。这将有助于实现应用的灵活部署和运维。

  • 23
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

星光闪闪k

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

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

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

打赏作者

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

抵扣说明:

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

余额充值