为了账号安全,请及时绑定邮箱和手机立即绑定

Spring Boot项目实战:新手入门到初级应用教程

标签:
SpringBoot
概述

Spring Boot项目实战涵盖了从环境搭建到项目部署的全过程,详细介绍了Spring Boot的核心特性和配置方法。文章通过创建RESTful API和数据库集成等实战案例,帮助开发者快速掌握Spring Boot项目的开发和部署技巧。

Spring Boot简介与环境搭建

Spring Boot简介

Spring Boot是基于Spring框架的开源框架,旨在简化应用的初始搭建和开发过程。Spring Boot通过约定优于配置的方式,减少了开发中的配置工作量,使得开发者能够快速地创建独立的、生产级别的应用。Spring Boot允许开发者通过简单的配置来集成常用的库和技术。Spring Boot的核心价值在于:

  1. 减少配置:通过约定优于配置的方式,减少开发中大量的配置。
  2. 嵌入式容器:内置了Tomcat、Jetty或者Undertow等Web服务器,不需要额外配置web.xml。
  3. 自动化配置:提供默认配置支持,使得大多数配置一次设定后,不再需要修改。
  4. 依赖管理:自动管理依赖,仅需添加相应的依赖即可。
  5. 启动器:提供非常方便的Maven和Gradle启动器,使得项目依赖管理更加简单。
  6. 集成测试:支持Spring Boot Actuator,可以轻松地监控应用的运行状态。

开发环境搭建

开始使用Spring Boot前,需要搭建合适的开发环境。以下是搭建步骤:

  1. 安装Java环境:确保你的机器上安装了JDK,JDK版本建议使用JDK 8或更高版本。
  2. 安装Maven或Gradle:选择使用Maven或Gradle作为构建工具。Maven和Gradle是流行的构建工具,可以管理项目的构建、依赖关系和项目信息。推荐使用Maven,因为它更受Spring Boot社区的支持。
  3. 安装IDE:选择合适的集成开发环境(IDE)。常见的IDE包括Spring Tool Suite(STS)、IntelliJ IDEA、Eclipse等。
  4. 配置环境变量:配置环境变量,保证Java运行时能够访问所需的库和工具。例如,设置JAVA_HOME环境变量:
    export JAVA_HOME=/path/to/java
    export PATH=$JAVA_HOME/bin:$PATH
  5. Spring Boot插件:在IDE中安装Spring Boot插件,以获得更好的开发体验。例如,Eclipse中有Spring IDE插件,IntelliJ IDEA中有Spring Boot插件。

快速入门第一个Spring Boot项目

创建Spring Boot项目

  1. 使用Spring Initializr:前往Spring Initializr网站,选择你的Java版本(建议使用Java 8或以上),项目打包类型(Maven或Gradle),以及应用的基本配置(如Spring Boot版本、语言等)。
  2. 下载并导入项目:下载生成的项目压缩包,解压缩后导入到你的IDE中。
  3. 项目结构:项目结构通常包括以下几个部分:
    • src/main/java:存放源代码和配置类。
    • src/main/resources:存放配置文件(如application.properties或application.yml)。
    • src/test/java:存放单元测试代码。
    • pom.xml(对于Maven项目)或build.gradle(对于Gradle项目):项目配置文件,管理项目依赖和构建过程。

编写第一个应用

创建一个简单的Spring Boot应用,首先在src/main/java目录下创建一个主类HelloWorldApplication

package com.example.demo;

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 HelloWorldApplication {

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

@RestController
class HelloWorldController {
    @GetMapping("/")
    public String helloWorld() {
        return "Hello, World!";
    }
}

运行应用

  1. 在IDE中运行HelloWorldApplication类中的main方法;
  2. 应用启动后,访问http://localhost:8080/,可以看到输出“Hello, World!”。
项目结构与基本配置

项目目录结构解析

一个典型的Spring Boot项目目录结构如下:

src
├── main
│   ├── java
│   │   └── com.example.demo
│   │       ├── HelloWorldApplication.java
│   │       └── HelloWorldController.java
│   └── resources
│       ├── application.properties
│       └── static
│           └── index.html
└── test
    └── java
        └── com.example.demo
            └── HelloWorldApplicationTests.java
  • java目录:存放应用程序的Java类。
  • resources目录:存放静态资源文件(如index.html)、配置文件(如application.properties)和国际化文件。
  • test目录:存放单元测试类。

核心配置文件详解

Spring Boot项目的配置主要通过application.propertiesapplication.yml文件实现。以下是一些常见的配置项:

  • 基本配置

    • spring.application.name: 应用名称。
    • server.port: 服务器端口,默认为8080。
    • spring.profiles.active: 激活的配置文件,如devprod
  • 数据库配置

    • spring.datasource.url: 数据库连接URL。
    • spring.datasource.username: 数据库用户名。
    • spring.datasource.password: 数据库密码。
    • spring.datasource.driver-class-name: 驱动类名。
  • 日志配置

    • logging.level.root: 设置根日志级别。
    • logging.level.com.example.demo: 设置特定包的日志级别。
    • logging.file.name: 日志文件路径。
  • Spring配置

    • spring.jpa.hibernate.ddl-auto: 数据库表行为(create、update、none)。
    • spring.jpa.show-sql: 是否显示SQL语句。

自动配置原理简介

Spring Boot通过约定优于配置的方式进行配置,它通过自动配置来简化开发流程。自动配置的关键在于@SpringBootApplication注解,它结合了@Configuration@EnableAutoConfiguration@ComponentScan注解的功能。

  • @Configuration:标记配置类。
  • @EnableAutoConfiguration:允许Spring Boot根据类路径中的依赖进行自动配置。
  • @ComponentScan:扫描指定包下的组件(如控制器、服务等)。
创建RESTful API服务

使用Spring Boot构建RESTful API

Spring Boot为构建RESTful API提供了强大的支持。REST(Representational State Transfer)是一种软件架构风格,基于HTTP协议,用于构建可扩展、易于维护的Web服务。

创建控制器(Controller)

控制器用于处理HTTP请求,返回HTTP响应。例如:

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {
    @GetMapping("/")
    public String helloWorld() {
        return "Hello, World!";
    }
}

处理GET请求

使用@GetMapping注解处理GET请求。

@GetMapping("/users")
public List<User> getUsers() {
    return userService.getAllUsers();
}

处理POST请求

使用@PostMapping注解处理POST请求。

@PostMapping("/users")
public User createUser(@RequestBody User user) {
    return userService.createUser(user);
}

处理PUT和DELETE请求

分别使用@PutMapping@DeleteMapping注解处理PUT和DELETE请求。

@PutMapping("/users/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
    return userService.updateUser(id, user);
}

@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable Long id) {
    userService.deleteUser(id);
}
``

### 控制器(Controller)的编写

控制器是Spring Boot中用于处理HTTP请求的组件。每个控制器都由`@Controller`或`@RestController`注解标记,并且可以包含多个处理方法,每个方法都有对应的HTTP请求类型和路径。

- **基本控制器定义**

  ```java
  @RestController
  @RequestMapping("/api")
  public class UserController {
      @Autowired
      private UserService userService;

      @GetMapping("/users")
      public List<User> getUsers() {
          return userService.getAllUsers();
      }

      @PostMapping("/users")
      public User createUser(@RequestBody User user) {
          return userService.createUser(user);
      }

      @PutMapping("/users/{id}")
      public User updateUser(@PathVariable Long id, @RequestBody User user) {
          return userService.updateUser(id, user);
      }

      @DeleteMapping("/users/{id}")
      public void deleteUser(@PathVariable Long id) {
          userService.deleteUser(id);
      }
  }
  • 请求参数绑定

    使用@RequestParam@PathVariable注解绑定请求参数。

    @GetMapping("/users/{userId}")
    public User getUserById(@PathVariable Long userId) {
      return userService.getUserById(userId);
    }

    使用@RequestBody注解绑定请求体数据。

    @PostMapping("/users")
    public User createUser(@RequestBody User user) {
      return userService.createUser(user);
    }

实战:用户管理接口的创建

创建一个简单的用户管理接口,包括用户列表查询、用户创建、用户更新和用户删除操作。

  1. 定义User实体

    package com.example.demo;
    
    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
       public Long getId() {
           return id;
       }
    
       public void setId(Long id) {
           this.id = id;
       }
    
       public String getName() {
           return name;
       }
    
       public void setName(String name) {
           this.name = name;
       }
    
       public String getEmail() {
           return email;
       }
    
       public void setEmail(String email) {
           this.email = email;
       }
    }
  2. 定义UserService接口

    package com.example.demo;
    
    import java.util.List;
    
    public interface UserService {
       List<User> getAllUsers();
       User createUser(User user);
       User updateUser(Long id, User user);
       void deleteUser(Long id);
       User getUserById(Long id);
    }
  3. 实现UserService接口

    package com.example.demo;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import javax.transaction.Transactional;
    import java.util.List;
    import java.util.Optional;
    
    @Service
    public class UserServiceImpl implements UserService {
       @Autowired
       private UserRepository userRepository;
    
       @Override
       public List<User> getAllUsers() {
           return userRepository.findAll();
       }
    
       @Override
       public User createUser(User user) {
           return userRepository.save(user);
       }
    
       @Override
       @Transactional
       public User updateUser(Long id, User user) {
           Optional<User> optionalUser = userRepository.findById(id);
           if (optionalUser.isPresent()) {
               User existingUser = optionalUser.get();
               existingUser.setName(user.getName());
               existingUser.setEmail(user.getEmail());
               return userRepository.save(existingUser);
           }
           return null;
       }
    
       @Override
       public void deleteUser(Long id) {
           userRepository.deleteById(id);
       }
    
       @Override
       public User getUserById(Long id) {
           Optional<User> optionalUser = userRepository.findById(id);
           return optionalUser.orElse(null);
       }
    }
  4. 定义UserRepository接口

    package com.example.demo;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    
    import java.util.List;
    import java.util.Optional;
    
    public interface UserRepository extends JpaRepository<User, Long> {
    }
  5. 配置UserController

    package com.example.demo;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.List;
    
    @RestController
    @RequestMapping("/api/users")
    public class UserController {
       @Autowired
       private UserService userService;
    
       @GetMapping
       public List<User> getAllUsers() {
           return userService.getAllUsers();
       }
    
       @PostMapping
       public User createUser(@RequestBody User user) {
           return userService.createUser(user);
       }
    
       @PutMapping("/{id}")
       public User updateUser(@PathVariable Long id, @RequestBody User user) {
           return userService.updateUser(id, user);
       }
    
       @DeleteMapping("/{id}")
       public void deleteUser(@PathVariable Long id) {
           userService.deleteUser(id);
       }
    
       @GetMapping("/{id}")
       public User getUserById(@PathVariable Long id) {
           return userService.getUserById(id);
       }
    }
数据库集成与操作

Spring Boot中数据库连接配置

Spring Boot支持多种数据库,如MySQL、PostgreSQL、SQL Server等。以下是如何配置MySQL连接:

  1. 添加依赖

    pom.xml中添加MySQL的依赖和Spring Data 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>
  2. 配置数据库连接

    application.properties中配置数据库连接参数。

    spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
    spring.datasource.username=root
    spring.datasource.password=root
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    spring.jpa.hibernate.ddl-auto=update
    spring.jpa.show-sql=true

使用JPA进行数据库操作

Spring Data JPA提供了一个简化数据库操作的API。通过定义Repository接口,可以轻松地完成CRUD操作。

  1. 创建实体类

    使用@Entity注解定义实体类。

    package com.example.demo;
    
    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
       public Long getId() {
           return id;
       }
    
       public void setId(Long id) {
           this.id = id;
       }
    
       public String getName() {
           return name;
       }
    
       public void setName(String name) {
           this.name = name;
       }
    
       public String getEmail() {
           return email;
       }
    
       public void setEmail(String email) {
           this.email = email;
       }
    }
  2. 创建Repository接口

    使用Spring Data JPA的JpaRepository接口。

    package com.example.demo;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    
    public interface UserRepository extends JpaRepository<User, Long> {
    }
  3. 实现Service层

    在Service层中注入Repository接口,编写业务逻辑。

    package com.example.demo;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import javax.transaction.Transactional;
    import java.util.List;
    import java.util.Optional;
    
    @Service
    public class UserServiceImpl implements UserService {
       @Autowired
       private UserRepository userRepository;
    
       @Override
       public List<User> getAllUsers() {
           return userRepository.findAll();
       }
    
       @Override
       public User createUser(User user) {
           return userRepository.save(user);
       }
    
       @Override
       @Transactional
       public User updateUser(Long id, User user) {
           Optional<User> optionalUser = userRepository.findById(id);
           if (optionalUser.isPresent()) {
               User existingUser = optionalUser.get();
               existingUser.setName(user.getName());
               existingUser.setEmail(user.getEmail());
               return userRepository.save(existingUser);
           }
           return null;
       }
    
       @Override
       public void deleteUser(Long id) {
           userRepository.deleteById(id);
       }
    
       @Override
       public User getUserById(Long id) {
           Optional<User> optionalUser = userRepository.findById(id);
           return optionalUser.orElse(null);
       }
    }

实战:CRUD操作实现

以上已经定义了User实体类、UserRepository接口和UserServiceImpl类,接下来在UserController中实现CRUD操作。

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping
    public List<User> getAllUsers() {
        return userService.getAllUsers();
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user);
    }

    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}
测试与调试

单元测试与集成测试

单元测试是测试代码的最小单位,而集成测试则是测试代码之间的交互。Spring Boot提供了强大的测试支持,可以通过注解和依赖注入来简化测试过程。

  1. 单元测试

    使用@SpringBootTest@RunWith(SpringRunner.class)注解进行测试。

    package com.example.demo;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.util.List;
    
    import static org.junit.jupiter.api.Assertions.*;
    
    @SpringBootTest
    public class UserServiceTest {
       @Autowired
       private UserService userService;
    
       @Test
       public void testGetAllUsers() {
           List<User> users = userService.getAllUsers();
           assertNotNull(users);
       }
    
       @Test
       public void testCreateUser() {
           User user = new User();
           user.setName("Test User");
           user.setEmail("test@example.com");
           User createdUser = userService.createUser(user);
           assertNotNull(createdUser);
           assertEquals(user.getName(), createdUser.getName());
           assertEquals(user.getEmail(), createdUser.getEmail());
       }
    
       @Test
       public void testUpdateUser() {
           User user = new User();
           user.setName("Test User");
           user.setEmail("test@example.com");
           User createdUser = userService.createUser(user);
           assertNotNull(createdUser);
           createdUser.setName("Updated User");
           createdUser.setEmail("updated@example.com");
           User updatedUser = userService.updateUser(createdUser.getId(), createdUser);
           assertNotNull(updatedUser);
           assertEquals(createdUser.getName(), updatedUser.getName());
           assertEquals(createdUser.getEmail(), updatedUser.getEmail());
       }
    
       @Test
       public void testDeleteUser() {
           User user = new User();
           user.setName("Test User");
           user.setEmail("test@example.com");
           User createdUser = userService.createUser(user);
           assertNotNull(createdUser);
           userService.deleteUser(createdUser.getId());
           assertNull(userService.getUserById(createdUser.getId()));
       }
    }
  2. 集成测试

    使用@WebMvcTest注解进行集成测试。

    package com.example.demo;
    
    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.boot.test.mock.mockito.MockBean;
    import org.springframework.test.web.servlet.MockMvc;
    
    import java.util.Collections;
    
    import static org.mockito.Mockito.*;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    
    @WebMvcTest(UserController.class)
    public class UserControllerTest {
       @Autowired
       private MockMvc mockMvc;
    
       @MockBean
       private UserService userService;
    
       @Test
       public void testGetAllUsers() throws Exception {
           List<User> users = Collections.singletonList(new User());
           when(userService.getAllUsers()).thenReturn(users);
    
           mockMvc.perform(get("/api/users"))
                   .andExpect(status().isOk())
                   .andExpect(jsonPath("$[0].name").value("Test User"))
                   .andExpect(jsonPath("$[0].email").value("test@example.com"));
       }
    
       @Test
       public void testCreateUser() throws Exception {
           User user = new User();
           user.setName("Test User");
           user.setEmail("test@example.com");
           when(userService.createUser(user)).thenReturn(user);
    
           mockMvc.perform(post("/api/users")
                   .contentType("application/json")
                   .content("{\"name\":\"Test User\", \"email\":\"test@example.com\"}"))
                   .andExpect(status().isOk())
                   .andExpect(jsonPath("$.name").value("Test User"))
                   .andExpect(jsonPath("$.email").value("test@example.com"));
       }
    
       @Test
       public void testUpdateUser() throws Exception {
           User user = new User();
           user.setName("Test User");
           user.setEmail("test@example.com");
           when(userService.updateUser(anyLong(), any(User.class))).thenReturn(user);
    
           mockMvc.perform(put("/api/users/1")
                   .contentType("application/json")
                   .content("{\"name\":\"Updated User\", \"email\":\"updated@example.com\"}"))
                   .andExpect(status().isOk())
                   .andExpect(jsonPath("$.name").value("Updated User"))
                   .andExpect(jsonPath("$.email").value("updated@example.com"));
       }
    
       @Test
       public void testDeleteUser() throws Exception {
           User user = new User();
           user.setName("Test User");
           user.setEmail("test@example.com");
           doNothing().when(userService).deleteUser(anyLong());
    
           mockMvc.perform(delete("/api/users/1"))
                   .andExpect(status().isOk());
       }
    }

使用Spring Boot Actuator监控应用

Spring Boot Actuator是一个提供生产就绪功能的库,它提供了详细的运行时信息,对于监控、管理和诊断应用非常有用。

  1. 添加依赖

    pom.xml中添加Actuator依赖。

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
  2. 启用Actuator

    application.properties中启用Actuator的默认端点。

    management.endpoints.web.exposure.include=*
    management.endpoint.health.show-details=always
  3. 访问Actuator端点

    启动应用后,可以通过访问http://localhost:8080/actuator来查看Actuator提供的各种端点信息,包括健康检查、JVM信息、线程信息等。

调试技巧与常见问题解决

  1. 使用IDE调试工具

    在IDE中设置断点,运行调试模式,可以逐行查看变量值,跟踪程序执行流程。

  2. 日志输出

    调整logging.level配置来查看详细的日志信息。在application.properties中设置日志级别。

    logging.level.root=DEBUG
    logging.level.com.example.demo=DEBUG
  3. 查看错误堆栈

    发生异常时,查看完整的错误堆栈信息,定位问题所在。

部署与上线

构建与打包

Spring Boot应用可以通过Maven或Gradle构建工具打包成可执行的JAR文件。

  1. Maven打包

    使用命令mvn clean package构建和打包项目,生成的JAR文件位于target目录下。

  2. Gradle打包

    使用命令gradle build构建和打包项目,生成的JAR文件位于build/libs目录下。

部署到Tomcat服务器

Spring Boot应用可以通过嵌入式的Web服务器运行,也可以部署到外部的Web服务器如Tomcat中。

  1. 运行Spring Boot应用

    使用命令java -jar target/your-application.jar运行打包后的应用。

  2. 部署到Tomcat

    可以将Spring Boot应用的JAR文件部署到Tomcat服务器中。首先解压Tomcat,然后将JAR文件复制到webapps目录下,启动Tomcat服务器,应用会自动部署。

线上环境部署实战

  1. 使用Docker部署

    创建Dockerfile文件,定义应用的运行环境。

    FROM openjdk:8-jdk-alpine
    VOLUME /tmp
    COPY target/your-application.jar your-application.jar
    EXPOSE 8080
    CMD ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/your-application.jar"]

    构建Docker镜像。

    docker build -t your-application .

    运行Docker容器。

    docker run -p 8080:8080 your-application
  2. 使用Kubernetes部署

    创建Kubernetes部署文件deployment.yaml,定义Pod、Service和Deployment。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: your-application
     labels:
       app: your-application
    spec:
     replicas: 1
     selector:
       matchLabels:
         app: your-application
     template:
       metadata:
         labels:
           app: your-application
       spec:
         containers:
         - name: your-application
           image: your-application:latest
           ports:
           - containerPort: 8080
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: your-application
     labels:
       app: your-application
    spec:
     selector:
       app: your-application
     ports:
     - protocol: TCP
       port: 80
       targetPort: 8080
     type: LoadBalancer

    应用部署文件。

    kubectl apply -f deployment.yaml
  3. 使用云平台部署

    可以使用AWS、Google Cloud Platform、Azure等云平台提供的服务部署Spring Boot应用。云平台提供了容器和无服务器的部署方式,可以简化部署过程。

通过以上步骤,您已经掌握了Spring Boot项目的开发、测试、部署等全过程,可以顺利地开发和部署自己的Spring Boot应用。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消