亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

Java微服務項目實戰:從入門到實踐

概述

Java微服务项目实战涵盖了从微服务基础概念到Java微服务的具体实现,包括开发环境搭建、框架选择与配置、以及项目实战案例等全面内容。文章详细介绍了如何使用Spring Boot和Spring Cloud等工具创建和部署Java微服务,并通过实战案例构建了一个简单的电商系统,展示了微服务之间的通信和集成。

Java微服务基础介绍

微服务的概念与优势

微服务是一种将应用程序分解为一组小型、独立服务的方法,每个服务都围绕一个特定的业务功能构建。这些服务通过HTTP、消息队列、数据库等协议和接口相互通信。相比传统单体应用程序,微服务架构具有以下优势:

  1. 独立部署:每个微服务可以独立部署和扩展,提高了系统的灵活性和可维护性。
  2. 快速迭代:由于每个服务规模较小,易于理解和测试,可以实现快速迭代和频繁部署。
  3. 高可用性:某个服务出现问题不会导致整个系统瘫痪,其他服务仍然可以正常运行。
  4. 可伸缩性:可以根据业务需求,灵活地扩展或缩减特定服务。
  5. 技术栈多样性:可以根据服务的具体需求选择合适的技术栈和语言。

Java微服务的特点

Java语言因其强大的开发工具和成熟的生态系统,成为微服务架构中的重要选择之一。Java微服务的特点包括:

  1. 跨平台性:Java虚拟机(JVM)允许Java程序在任何支持JVM的平台上运行。
  2. 丰富的库支持:Java社区提供了大量成熟的库和框架,如Spring Boot和Spring Cloud。
  3. 开发效率高:强大的IDE支持(如IntelliJ IDEA和Eclipse)极大地提高了开发效率。
  4. 安全性:Java的内置安全机制和成熟的认证、授权框架(如Spring Security)保证了应用的安全性。
  5. 社区支持:活跃且庞大的Java社区为开发者提供丰富的资源和帮助。

常见的Java微服务框架简介

  1. Spring Boot:Spring Boot是Spring框架的一个简化版本,旨在简化新Spring应用的初始搭建和配置工作。它通过约定优于配置的方式,让开发者能够快速搭建独立的、生产级别的应用。

  2. Spring Cloud:Spring Cloud是一组子项目,为构建分布式、微服务架构提供了完整的解决方案。它包含了服务发现(Eureka)、服务网关(Zuul)、断路器(Hystrix)、负载均衡(Ribbon)等组件。

开发环境搭建

Java开发环境配置

开发Java微服务项目,首先需要安装Java环境。以下步骤展示了如何配置Java环境:

  1. 下载并安装Java:访问Oracle官网或其他Java发行版网站,下载并安装Java SDK。
  2. 设置环境变量:在系统环境变量中添加Java的安装路径,确保JAVA_HOMEPATH变量正确设置。
  3. 验证安装:打开命令行窗口,输入java -version,确认Java安装成功。

下面是一个配置JAVA_HOMEPATH变量的示例:

# 设置JAVA_HOME环境变量
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
export PATH=$JAVA_HOME/bin:$PATH

# 验证安装
java -version

Maven/Gradle构建工具简介

Java项目的构建和管理工具主要有Maven和Gradle,这里简要介绍两种工具的特点:

  1. Maven:一个强大的项目管理和构建工具,使用约定优于配置的方式,自动管理依赖关系,并提供了一套标准的项目结构。Maven通过pom.xml文件来描述项目及其依赖项。

  2. Gradle:一个更现代、灵活的构建工具,使用Groovy或Kotlin脚本进行项目配置。Gradle支持增量构建,提高了构建速度。Gradle通过build.gradle文件来配置项目。

示例:在Maven项目中的pom.xml文件内容:

<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>my-service</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.0</version>
        </dependency>
        <!-- 添加其他依赖 -->
    </dependencies>
</project>

IDE配置与使用

推荐的Java开发IDE有IntelliJ IDEA和Eclipse,这里简要介绍它们的配置步骤:

  1. IntelliJ IDEA

    • 安装:从官网下载并安装IntelliJ IDEA。
    • 配置:安装完成后,打开IDE,选择合适的主题和代码风格。
    • 配置Maven或Gradle:在设置中添加Maven和Gradle的路径,方便项目构建。
    • 导入项目:通过打开项目文件夹,导入项目至IDE中。
  2. Eclipse
    • 安装:从官网下载并安装Eclipse。
    • 配置:安装完成后,打开Eclipse,设置合适的主题。
    • 安装Maven/Gradle插件:通过Eclipse内置的插件管理器安装Maven和Gradle插件。
    • 导入项目:使用Eclipse的导入项目功能,选择Maven或Gradle项目导入。

第一个Java微服务项目

创建Spring Boot微服务项目

Spring Boot简化了应用创建过程,以下步骤描述了如何使用Spring Initializr创建一个简单的Spring Boot项目:

  1. 访问Spring Initializr:在浏览器中打开https://start.spring.io/
  2. 选择项目信息:选择项目的基本信息,如项目类型、语言和构建工具。
  3. 添加依赖:选择需要的依赖项,如Spring Web、Spring Data JPA等。
  4. 生成项目:点击"Generate"按钮,下载生成的项目文件。
  5. 导入项目:将下载的项目导入IDE中,配置Maven或Gradle构建工具。

示例:在Spring Initializr中创建一个简单的项目:

  • 项目类型:选择Maven Project
  • 语言:Java
  • 依赖:选择Spring Web、Spring Data JPA
  • 生成并下载项目

Hello World示例详解

以下是一个简单的Hello World示例,展示如何使用Spring Boot创建一个Web服务:

  1. 创建Spring Boot项目:使用Spring Initializr创建一个包含Spring Web依赖的项目。
  2. 编写控制器:在src/main/java/com/example目录下创建一个新的Java类HelloController.java,并在其中定义一个简单的REST控制器。

示例代码:

package com.example.demo;

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

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, World!";
    }
}
  1. 配置应用:在src/main/resources目录下找到application.properties文件,进行应用配置。例如,配置端口号:
server.port=8080
  1. 运行项目:在IDE中右键点击项目,选择运行Spring Boot应用。然后,访问http://localhost:8080/hello,可以看到输出"Hello, World!"。

项目打包与部署

  1. 打包项目:使用Maven或Gradle打包项目,生成可执行的JAR文件。

示例:使用Maven打包项目

mvn package
  1. 运行JAR文件:使用java -jar命令运行生成的JAR文件。
java -jar target/my-service-1.0.0.jar
  1. 部署到服务器:将打包好的JAR文件上传到服务器上,并通过命令行或后台服务(如Tomcat、Spring Boot Actuator)启动应用。

微服务通信与集成

RESTful API设计与实现

微服务之间通常通过RESTful API进行通信。设计一个RESTful API时,应遵循以下原则:

  1. 资源:每个URI表示一个资源。
  2. HTTP方法:使用标准的HTTP方法(GET、POST、PUT、DELETE)操作资源。
  3. 状态码:使用标准的HTTP状态码表示操作结果。
  4. 超媒体:使用超媒体链接(如Link头或嵌入链接)提供资源之间的导航。

示例:定义一个简单的REST API来处理用户信息

package com.example.demo;

import org.springframework.web.bind.annotation.*;

@RestController
public class UserController {

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        // 从数据库中获取用户信息
        return new User(id, "John Doe", "[email protected]");
    }

    @PostMapping("/users")
    public User createUser(@RequestBody User user) {
        // 将用户信息存入数据库
        return user;
    }
}

使用Feign进行服务调用

Feign是一个声明式的Web服务客户端,它通过注解的方式简化了HTTP请求的编写。以下步骤展示了如何使用Feign进行服务调用:

  1. 添加依赖:在pom.xmlbuild.gradle中添加Feign依赖。
  2. 定义接口:创建一个Java接口定义Feign客户端。

示例代码:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
package com.example.demo;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("user-service")
public interface UserClient {

    @GetMapping("/users/{id}")
    User getUser(@PathVariable Long id);
}
  1. 使用Feign客户端:在服务中注入Feign客户端,进行服务调用。

示例代码:

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserClient userClient;

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        User user = userClient.getUser(id);
        return user;
    }
}

配置服务注册与发现(Eureka)

Eureka是Netflix公司开源的基于REST的服务注册和发现组件,广泛用于微服务架构中。以下步骤描述了如何配置Eureka服务注册和发现:

  1. 添加依赖:在pom.xmlbuild.gradle中添加Eureka和Spring Cloud Eureka依赖。

示例代码:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  1. 配置Eureka客户端:在application.properties中配置Eureka客户端。

示例代码:

spring.application.name=my-service
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
  1. 启动Eureka服务:创建一个Eureka服务实例,启动并注册到Eureka服务器。

示例代码:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class Application {

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

微服务容错与监控

服务熔断与降级(Hystrix)

Hystrix是Netflix开发的一款开源服务容错和限流工具,用于处理分布式系统中的延迟和容错问题。以下步骤展示了如何使用Hystrix进行服务熔断和降级:

  1. 添加依赖:在pom.xmlbuild.gradle中添加Hystrix依赖。

示例代码:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
  1. 启用Hystrix:在应用主类中启用Hystrix支持。

示例代码:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;

@SpringBootApplication
@EnableHystrix
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
  1. 编写熔断逻辑:在服务调用中使用Hystrix进行熔断和降级处理。

示例代码:

package com.example.demo;

import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableCircuitBreaker
public class UserController {

    @Autowired
    private UserClient userClient;

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        return userClient.getUser(id);
    }

    public static class UserCommand extends HystrixCommand<User> {

        private final UserClient userClient;
        private final Long id;

        public UserCommand(UserClient userClient, Long id) {
            super(HystrixCommandGroupKey.Factory.asKey("UserGroup"));
            this.userClient = userClient;
            this.id = id;
        }

        @Override
        protected User run() throws Exception {
            return userClient.getUser(id);
        }

        @Override
        protected User getFallback() {
            return new User(id, "Fallback User", "[email protected]");
        }
    }
}

服务网关配置(Zuul)

Zuul是Netflix开发的微服务网关组件,用于路由、过滤和监控请求。以下步骤展示了如何配置Zuul网关:

  1. 添加依赖:在pom.xmlbuild.gradle中添加Zuul依赖。

示例代码:

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  1. 配置网关:在application.properties中配置Zuul网关。

示例代码:

spring.application.name=api-gateway
zuul.routes.user-service.path=/users/**
zuul.routes.user-service.url=http://localhost:8081/
  1. 创建网关应用:创建一个Spring Boot应用作为网关,启动并注册到Eureka。

示例代码:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class GatewayApplication {

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

使用Prometheus进行服务监控

Prometheus是一款开源的监控工具,用于收集和查询时间序列数据。以下步骤描述了如何使用Prometheus进行服务监控:

  1. 安装Prometheus:下载Prometheus并启动Prometheus服务器。
  2. 配置监控目标:在Prometheus配置文件prometheus.yml中配置监控目标。

示例代码:

scrape_configs:
  - job_name: 'spring-app'
    static_configs:
      - targets: ['localhost:8080']
  1. 添加Prometheus依赖:在pom.xmlbuild.gradle中添加Prometheus依赖。

示例代码:

<!-- pom.xml -->
<dependency>
    <groupId>io.prometheus</groupId>
    <artifactId>simpleclient_spring_boot</artifactId>
    <version>0.10.0</version>
</dependency>
  1. 启用Prometheus监控:在应用主类中启用Prometheus监控。

示例代码:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.actuate.autoconfigure.ExportSpringBootActuatorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsDropwizardAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsMicrometerAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsPrometheusAutoConfiguration;

@SpringBootApplication
@EnableMetricsPrometheusAutoConfiguration
public class Application {

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

实战案例:构建一个简单的电商系统

商品服务设计与实现

一个简单的电商系统通常包括商品、订单和用户服务。以下步骤描述了如何设计并实现商品服务:

  1. 定义商品实体:创建一个商品实体类,用于表示商品信息。

示例代码:

package com.example.demo;

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;

    // Getter and Setter methods
}
  1. 定义商品服务接口:创建一个商品服务接口,定义商品的CRUD操作。

示例代码:

package com.example.demo;

import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/products")
public class ProductService {

    // 假设这里使用了Spring Data JPA来操作数据库
    private ProductRepository productRepository;

    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    @GetMapping
    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }

    @GetMapping("/{id}")
    public Product getProduct(@PathVariable Long id) {
        return productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));
    }

    @PostMapping
    public Product createProduct(@RequestBody Product product) {
        return productRepository.save(product);
    }

    @PutMapping("/{id}")
    public Product updateProduct(@PathVariable Long id, @RequestBody Product product) {
        Product existingProduct = productRepository.findById(id).orElseThrow(() -> new RuntimeException("Product not found"));
        existingProduct.setName(product.getName());
        existingProduct.setPrice(product.getPrice());
        return productRepository.save(existingProduct);
    }

    @DeleteMapping("/{id}")
    public void deleteProduct(@PathVariable Long id) {
        productRepository.deleteById(id);
    }
}
  1. 配置持久化层:使用Spring Data JPA配置持久化层,定义一个ProductRepository接口。

示例代码:

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
}

订单服务设计与实现

订单服务负责处理订单的创建、查询等操作。以下步骤描述了如何设计并实现订单服务:

  1. 定义订单实体:创建一个订单实体类,用于表示订单信息。

示例代码:

package com.example.demo;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.List;

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String userId;
    private List<Product> products;

    // Getter and Setter methods
}
  1. 定义订单服务接口:创建一个订单服务接口,定义订单的CRUD操作。

示例代码:

package com.example.demo;

import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/orders")
public class OrderService {

    // 假设这里使用了Spring Data JPA来操作数据库
    private OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    @GetMapping
    public List<Order> getAllOrders() {
        return orderRepository.findAll();
    }

    @GetMapping("/{id}")
    public Order getOrder(@PathVariable Long id) {
        return orderRepository.findById(id).orElseThrow(() -> new RuntimeException("Order not found"));
    }

    @PostMapping
    public Order createOrder(@RequestBody Order order) {
        return orderRepository.save(order);
    }

    @PutMapping("/{id}")
    public Order updateOrder(@PathVariable Long id, @RequestBody Order order) {
        Order existingOrder = orderRepository.findById(id).orElseThrow(() -> new RuntimeException("Order not found"));
        existingOrder.setUserId(order.getUserId());
        existingOrder.setProducts(order.getProducts());
        return orderRepository.save(existingOrder);
    }

    @DeleteMapping("/{id}")
    public void deleteOrder(@PathVariable Long id) {
        orderRepository.deleteById(id);
    }
}
  1. 配置持久化层:使用Spring Data JPA配置持久化层,定义一个OrderRepository接口。

示例代码:

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
}

用户服务设计与实现

用户服务负责处理用户信息的创建、查询等操作。以下步骤描述了如何设计并实现用户服务:

  1. 定义用户实体:创建一个用户实体类,用于表示用户信息。

示例代码:

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;

    // Getter and Setter methods
}
  1. 定义用户服务接口:创建一个用户服务接口,定义用户的CRUD操作。

示例代码:

package com.example.demo;

import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/users")
public class UserService {

    // 假设这里使用了Spring Data JPA来操作数据库
    private UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

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

    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
    }

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

    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        User existingUser = userRepository.findById(id).orElseThrow(() -> new RuntimeException("User not found"));
        existingUser.setName(user.getName());
        existingUser.setEmail(user.getEmail());
        return userRepository.save(existingUser);
    }

    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userRepository.deleteById(id);
    }
}
  1. 配置持久化层:使用Spring Data JPA配置持久化层,定义一个UserRepository接口。

示例代码:

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

整合与测试

在完成各个服务的实现后,需要将它们整合在一起并进行测试。以下步骤描述了如何整合各个服务:

  1. 配置服务间通信:使用Feign或RestTemplate进行服务间通信。

示例代码:

package com.example.demo;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient("product-service")
public interface ProductServiceClient {

    @GetMapping("/products/{id}")
    Product getProduct(@PathVariable Long id);
}
  1. 创建集成测试用例:编写集成测试用例,验证各个服务的功能。

示例代码:

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient;

@SpringBootTest
public class OrderServiceIntegrationTest {

    @Autowired
    private WebTestClient webTestClient;

    @Autowired
    private ProductServiceClient productServiceClient;

    @Test
    public void shouldCreateOrderWithProduct() {
        Product product = productServiceClient.getProduct(1L);
        Order order = new Order();
        order.setUserId("user1");
        order.setProducts(List.of(product));

        webTestClient.post().uri("/orders")
                .bodyValue(order)
                .exchange()
                .expectStatus().isOk();
    }
}
點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消