SpringBoot企业级开发资料入门教程
本文详细介绍了SpringBoot的基础知识及其优势,涵盖了快速入门、核心功能详解、企业级开发实践等多个方面,提供了丰富的示例和配置指南,旨在帮助开发者全面掌握SpringBoot的企业级开发。
SpringBoot简介SpringBoot是什么
SpringBoot是由Pivotal团队在2013年开发的一个基于Spring框架的开源项目,旨在简化新Spring应用的初始搭建以及开发过程。SpringBoot通过约定优于配置的方式,帮助开发者快速构建独立的、生产级别的基于Spring的应用程序。
SpringBoot的优势
- 简化项目搭建: SpringBoot提供了一系列的默认配置,简化了Spring应用的初始搭建以及开发过程。
- 开箱即用: SpringBoot内置了Tomcat、Jetty、Undertow等Web服务器,无需手动配置。
- 自动配置: 通过自动化配置,开发者只需要提供必要的配置信息,而不需要手动配置大量的XML或注解。
- 简化Maven/Gradle配置: 自动化依赖管理和资源管理,减少了项目配置的复杂度。
- 支持嵌入式Servlet容器: 项目可以直接运行,无需外部容器支持。
- 集成第三方库: 提供了对各种技术的内置支持,如缓存、邮件、任务调度等。
- 无代码生成要求: 传统Spring项目需要大量的配置,而SpringBoot不需要编写大量的XML或注解配置。
- 全面的文档和示例: 丰富的文档和示例代码,帮助开发者快速上手。
SpringBoot的使用场景
- 快速原型开发: 对于需要快速搭建的原型项目,SpringBoot提供了快速的开发环境。
- 微服务开发: SpringBoot天然支持微服务架构,配合SpringCloud可以实现服务发现、负载均衡等。
- 企业应用开发: 对于企业级应用开发,SpringBoot提供了丰富的组件支持,如数据库集成、缓存、日志等。
- 简化大型应用的开发: 大型应用需要大量的配置和组件集成,SpringBoot简化了这些过程。
- 简化测试: 提供了SpringBoot测试框架,使得单元测试和集成测试更加简单。
- 分布式系统: 在分布式系统中,SpringBoot可以与其他微服务框架(如Spring Cloud)无缝集成。
创建第一个SpringBoot项目
创建SpringBoot项目首先需要安装Java开发环境(JDK 8及以上版本)和IDE(如IntelliJ IDEA、Eclipse等)。接下来,可以通过Spring Initializr官网或使用Maven/Gradle来创建一个新的SpringBoot项目。
使用IDE创建项目
- 打开IntelliJ IDEA,选择File -> New -> Project。
- 在弹出的窗口中选择Spring Initializr,点击Next。
- 选择Java版本和项目类型(例如,Java项目),填写项目名(如
hello-springboot
),点击Next。 - 在弹出的窗口中选择Java版本和项目依赖,点击Next。
- 选择Spring Web和Spring Starter Test依赖,点击Finish。
- IDEA将自动创建项目结构,并下载必要的依赖。
使用Maven创建项目
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>hello-springboot</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
项目创建完成后,可以编写第一个SpringBoot应用程序。在src/main/java/com/example/hello
目录下创建一个包hello
,并在包下创建一个名为HelloApplication.java
的类。
package com.example.hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
@RestController
class HelloController {
@GetMapping("/")
public String hello() {
return "Hello, Spring Boot!";
}
}
}
运行应用程序:在IDE中右键点击HelloApplication.java
,选择Run即可。
SpringBoot的自动配置
SpringBoot的自动配置功能体现在它能够根据类路径下的依赖来自动配置应用程序。例如,当项目中引入了spring-boot-starter-web
依赖时,SpringBoot会自动配置一个嵌入式的Tomcat服务器,以及Spring MVC。
自动配置的过程
在SpringBoot项目中,自动配置通过spring.factories
文件实现,该文件位于每个依赖的META-INF
目录下。
例如,在spring-boot-starter-web
依赖中,可以通过以下代码查看自动配置:
@Configuration
@ConditionalOnWebApplication
@Import({DispatcherServletAutoConfiguration.class, WebServerFactoryAutoConfiguration.class})
public class WebMvcAutoConfiguration {
// 自动配置相关的bean
}
SpringBoot的依赖管理和项目构建
依赖管理
SpringBoot支持使用Maven或Gradle进行依赖管理和构建。通过spring-boot-starter-parent
作为父POM,可以简化依赖版本的管理。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
</parent>
项目构建
SpringBoot项目可以通过Maven或Gradle进行构建。以下是一个简单的Maven构建命令:
mvn clean package
构建后的可执行jar文件可以在target
目录下找到。
配置文件管理
SpringBoot配置文件主要包含application.properties
和application.yml
两种格式。默认情况下,SpringBoot会从src/main/resources
目录中读取配置文件。配置文件可以用于定义应用程序的各种属性,如数据库连接信息、端口、日志配置等。
配置文件示例
# application.properties
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/dbname
spring.datasource.username=root
spring.datasource.password=root
# application.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/dbname
username: root
password: root
使用配置文件可以调整应用程序的行为,例如设置数据库连接信息,调整端口号等:
# 使用配置文件调整端口号
server:
port: 8081
数据库集成与事务管理
SpringBoot集成了多种数据库的访问方式,支持JDBC、JPA(如Hibernate)、MyBatis等。以下是一个简单的JPA数据库集成示例。
JPA数据库集成
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
- 配置数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/dbname
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
- 创建实体类
package com.example.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// getters and setters
}
- 创建Repository接口
package com.example.repository;
import com.example.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
- 创建Service和Controller
package com.example.service;
import com.example.entity.User;
import com.example.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public List<User> findAll() {
return userRepository.findAll();
}
}
package com.example.controller;
import com.example.entity.User;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public List<User> findAll() {
return userService.findAll();
}
}
处理数据库异常
在实际应用中,经常需要处理数据库连接异常和事务回滚等场景。以下是一个简单的异常处理示例:
package com.example.service;
import com.example.entity.User;
import com.example.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Transactional
public void saveUserWithExceptionHandling(User user) {
try {
userRepository.save(user);
} catch (Exception e) {
System.out.println("Database connection failed: " + e.getMessage());
}
}
}
RESTful API开发
SpringBoot基于Spring MVC提供了对RESTful API的支持。
创建一个简单的RESTful API
- 创建实体类
package com.example.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
// getters and setters
}
- 创建Repository接口
package com.example.repository;
import com.example.entity.Product;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
}
- 创建Service和Controller
package com.example.service;
import com.example.entity.Product;
import com.example.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ProductService {
private final ProductRepository productRepository;
@Autowired
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public List<Product> findAll() {
return productRepository.findAll();
}
}
package com.example.controller;
import com.example.entity.Product;
import com.example.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/products")
public class ProductController {
private final ProductService productService;
@Autowired
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping
public List<Product> findAll() {
return productService.findAll();
}
}
RESTful API最佳实践
- 使用HTTP方法:使用正确的HTTP方法(GET、POST、PUT、DELETE)来操作资源。
- 统一返回格式:使用统一的返回格式,以便客户端更容易解析。
- 错误处理:提供统一的错误处理机制,确保客户端能够理解错误信息。
- 条件查询:支持条件查询,允许客户端根据条件过滤资源。
- 分页查询:支持分页查询,允许客户端根据需要获取资源的一部分。
日志管理与监控
SpringBoot集成了多种日志框架的支持,包括Logback、Log4j2等。默认情况下,SpringBoot使用Logback作为日志框架,并通过application.properties
或application.yml
文件配置日志输出。
配置日志输出
# application.properties
logging.file.name=logs/app.log
logging.level.root=INFO
# application.yml
logging:
file:
name: logs/app.log
level:
root: INFO
日志监控
SpringBoot还提供了一个内置的Actuator端点,可以用来监控应用的运行状态,包括日志、健康检查、系统信息等。可以通过添加spring-boot-starter-actuator
依赖来启用这些端点。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
启用Actuator端点
management:
endpoints:
web:
exposure:
include: "*"
安全性与权限管理
SpringBoot集成了Spring Security,可以方便地进行安全性配置。以下是一个简单的安全性配置示例。
配置安全性
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- 配置Security
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Override
@Bean
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
集成OAuth2
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
- 配置OAuth2
spring:
security:
oauth2:
client:
registration:
github:
client-id: your-github-client-id
client-secret: your-github-client-secret
scope: read:user
provider:
github:
authorization-uri: https://github.com/login/oauth/authorize
token-uri: https://github.com/login/oauth/access_token
user-info-uri: https://api.github.com/user
user-name-attribute: login
分布式与微服务架构
SpringBoot非常适合微服务架构。配合Spring Cloud可以实现服务发现、负载均衡、断路器等功能。
使用Spring Cloud
- 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 配置Eureka客户端
spring:
application:
name: service-1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
- 启用Eureka客户端
package com.example.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@Configuration
@EnableDiscoveryClient
public class EurekaConfig {
}
服务提供者和服务消费者之间可以通过Eureka实现服务发现。服务提供者注册到Eureka服务器上,服务消费者通过Eureka服务器获取服务实例列表,从而实现服务调用。
企业级案例分析
假设有一个电商系统,包含商品服务、订单服务、用户服务等多个微服务。每个服务都有自己的数据库,通过Eureka进行服务注册和发现,使用Ribbon实现负载均衡,通过Hystrix实现服务熔断。
商品服务
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 配置数据库和Eureka
spring:
datasource:
url: jdbc:mysql://localhost:3306/products
username: root
password: root
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
订单服务
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
.
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 配置数据库和Eureka
spring:
datasource:
url: jdbc:mysql://localhost:3306/orders
username: root
password: root
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
用户服务
- 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- 配置数据库和Eureka
spring:
datasource:
url: jdbc:mysql://localhost:3306/users
username: root
password: root
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
SpringBoot常用插件与工具
单元测试与集成测试
SpringBoot提供了丰富的测试支持,包括单元测试和集成测试。单元测试通常使用内置的@SpringBootTest
注解,集成测试可以使用@SpringBootTest
和@WebMvcTest
注解。
单元测试示例
package com.example.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import static org.mockito.Mockito.when;
import static org.junit.jupiter.api.Assertions.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserService userService;
@MockBean
private UserRepository userRepository;
@Test
public void testFindAll() {
User user = new User();
user.setName("Alice");
when(userRepository.findAll()).thenReturn(List.of(user));
List<User> users = userService.findAll();
assertEquals(1, users.size());
assertEquals("Alice", users.get(0).getName());
}
}
单元测试与集成测试对比
单元测试主要关注单个组件的功能,而不依赖于外部环境或数据库。而集成测试则测试多个组件之间的交互,通常需要一个运行的应用程序和一个数据库。
集成测试示例
package com.example.test;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(UserController.class)
public class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testFindAll() throws Exception {
mockMvc.perform(get("/users"))
.andExpect(status().isOk())
.andExpect(content().string("[]"));
}
}
常用开发工具介绍
- IDEA: IntelliJ IDEA是开发SpringBoot应用推荐的IDE,提供了丰富的插件支持,如Spring Boot插件、Lombok插件等。
- Maven/Gradle: Maven和Gradle是常用的构建工具,可以简化项目的依赖管理、构建和发布过程。
- Postman: Postman是测试API的工具,可以方便地发送HTTP请求,查看响应结果。
- Swagger: Swagger是一个API文档生成工具,可以帮助开发者自动生成API文档。
- Docker: Docker是一种容器技术,可以将应用及其依赖打包在一起,方便部署和迁移。
- IDE插件: IntelliJ IDEA提供了许多插件,如Spring Initializr、Lombok插件、Maven/Gradle插件等,这些插件可以简化开发过程。
部署与运行环境配置
- Docker部署: 使用Docker可以将SpringBoot应用及其依赖打包成一个镜像,通过Docker Compose可以管理多个容器的启动和停止。
- Kubernetes部署: Kubernetes是一个容器编排工具,可以管理多个容器的部署、扩展和运维。
- 云平台部署: 可以将SpringBoot应用部署到各大云平台,如阿里云、腾讯云、AWS等。
Docker部署示例
- 创建Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/hello-springboot.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
- 构建和运行
docker build -t hello-springboot .
docker run -p 8080:8080 hello-springboot
Kubernetes部署示例
- 创建Dockerfile
FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/hello-springboot.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
- 创建Kubernetes Deployment文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-springboot
spec:
replicas: 3
selector:
matchLabels:
app: hello-springboot
template:
metadata:
labels:
app: hello-springboot
spec:
containers:
- name: hello-springboot
image: hello-springboot:latest
ports:
- containerPort: 8080
- 创建Kubernetes Service文件
apiVersion: v1
kind: Service
metadata:
name: hello-springboot
spec:
selector:
app: hello-springboot
ports:
- name: http
protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer
SpringBoot常见问题与解决方案
常见错误及其解决方法
- 缺少依赖: 如果应用程序缺少某些依赖,可能会导致启动失败。检查
pom.xml
或build.gradle
文件,确保所有必要的依赖都已添加。 - 配置错误: 如果配置文件中的属性设置错误,可能会导致应用程序无法启动或运行。检查配置文件,确保所有属性设置正确。
- 内存溢出: 如果应用程序内存溢出,可以尝试增加JVM堆内存大小。在启动命令中添加
-Xms
和-Xmx
参数,例如java -Xms256m -Xmx512m -jar app.jar
。
解决内存溢出问题
- 检查
pom.xml
或build.gradle
文件,确保已添加JVM参数。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<jvmArguments>
-Xms256m -Xmx512m
</jvmArguments>
</configuration>
</plugin>
</plugins>
</build>
解决内存泄露问题
- 检查是否有未释放的资源或引用。例如,在SpringBoot应用中,确保所有的线程池和连接池都已正确关闭。
- 使用内存分析工具(如VisualVM、JProfiler)来分析内存使用情况,找出内存泄露的根源。
性能优化与调试技巧
- 使用Profiler工具: 可以使用Profiler工具(如VisualVM、JProfiler等)来分析应用程序的性能瓶颈。
- 优化代码: 通过优化代码结构、减少冗余操作等方式提高程序性能。
- 配置优化: 通过调整SpringBoot的配置参数,如线程池大小、连接池大小等,来提高程序性能。
使用Profiler工具
- 使用VisualVM分析JVM性能。
jvisualvm
- 在VisualVM中,可以查看CPU使用率、内存使用情况、线程状态等指标,帮助定位性能瓶颈。
性能优化案例
- 优化数据库查询: 使用索引、优化查询语句,减少数据库访问次数。
- 优化缓存策略: 使用如Redis、Ehcache等缓存工具,减少数据库访问压力。
- 优化网络请求: 减少不必要的网络请求,使用HTTP缓存等技术。
文档与社区资源推荐
- 官方文档: SpringBoot官方文档提供了详细的API、配置和示例,是学习SpringBoot的最佳资源。
- Stack Overflow: Stack Overflow是一个问答社区,可以在这里找到许多关于SpringBoot的问题和答案。
- GitHub: GitHub上有许多开源的SpringBoot项目,可以从中学习和借鉴。
- 慕课网: 慕课网提供大量的SpringBoot课程和视频教程,是学习SpringBoot的好地方。
通过上述指南,您可以快速入门SpringBoot,并掌握企业级开发所需的知识和技能。希望这些内容对您有所帮助。
共同学习,写下你的评论
评论加载中...
作者其他优质文章