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

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

Java分布式入門教程:搭建與應用

標簽:
Java 微服務
概述

本文详细介绍了Java分布式系统的核心概念和应用,涵盖了Java在分布式系统中的多种开发框架,如Java RMI、JNDI和JMS。文章进一步探讨了Java分布式系统的优势,包括跨平台性、丰富的API和强大的开发工具支持。此外,还介绍了Java分布式系统的基础组件和开发工具,帮助读者全面了解如何搭建和维护Java分布式系统。

Java分布式入门教程:搭建与应用
Java分布式系统简介

分布式系统概念

分布式系统是由多台计算机协同工作的系统,这些计算机通过网络相互连接,协同执行任务。分布式系统的核心特征之一是各计算机之间的通信和协作。分布式系统的主要目标是提高系统性能、可靠性和可用性,以便更好地服务于大规模的用户群体。

Java在分布式系统中的应用

Java是一种广泛使用的编程语言,尤其在构建分布式系统中扮演着重要角色。Java提供了多种分布式系统开发框架,例如Java Remote Method Invocation (RMI)、Java Naming and Directory Interface (JNDI)、Java Message Service (JMS)等。

  • Java RMI:允许Java程序通过网络调用远程对象的方法。它支持基于对象的网络通信,提供了透明的对象方法调用。
  • Java Naming and Directory Interface (JNDI):提供了一种统一的框架,用于访问和操作命名服务。它可以用于查找和绑定各种资源,如数据库连接、JMS队列和主题等。
  • Java Message Service (JMS):提供了一种标准的接口来访问消息传递服务。它允许在分布式系统中实现异步通信。

Java分布式系统的优势

Java在分布式系统中的优势包括跨平台性、丰富的API和强大的开发工具支持。Java程序可以在多种操作系统上运行,无需修改代码。此外,Java提供了大量的库和框架,使得开发者能够更高效地构建和维护分布式系统。

  • 跨平台性:Java编写的程序可以在不同的操作系统上运行,这使得开发人员可以编写一次代码,然后在多个环境中部署。
  • 丰富的API:Java提供了大量的API,支持网络通信、数据库操作、并发控制、安全认证等,这些都大大简化了分布式系统开发的工作量。
  • 强大的开发工具支持:Java开发工具如Eclipse、IntelliJ IDEA等提供了强大的开发环境,支持代码编辑、调试、测试和部署。这些工具还可以与各种构建工具(如Maven和Gradle)集成,使得项目管理和构建过程更加便捷。
Java分布式系统的基础组件

网络通信

在分布式系统中,网络通信是实现组件之间交互的关键。Java提供了多种网络通信机制,包括Socket编程、Java套接字API (Socket API)、Java套接字编程API (NIO)等。

Socket编程是网络通信的基础,它允许程序在不同计算机之间建立连接并发送数据。以下是一个简单的服务器端Socket编程示例:

import java.io.*;
import java.net.*;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("Server started on port 8080");

        while (true) {
            Socket clientSocket = serverSocket.accept();
            new Thread(() -> {
                try {
                    BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                    String request = in.readLine();
                    System.out.println("Received request: " + request);

                    PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
                    out.println("Received your request: " + request);

                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

客户端Socket编程示例:

import java.io.*;
import java.net.*;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 8080);
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        out.println("Hello Server");

        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String response = in.readLine();
        System.out.println("Server response: " + response);

        socket.close();
    }
}

Java套接字API (Socket API)示例:

import java.io.*;
import java.net.*;

public class SocketsAPIExample {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        Socket clientSocket = serverSocket.accept();
        InputStream in = clientSocket.getInputStream();
        OutputStream out = clientSocket.getOutputStream();

        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        PrintWriter writer = new PrintWriter(out, true);

        writer.println("Hello, Client!");
        String clientResponse = reader.readLine();
        System.out.println("Client responded: " + clientResponse);

        writer.close();
        reader.close();
        clientSocket.close();
        serverSocket.close();
    }
}

Java套接字编程API (NIO)示例:

import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class NioExample {
    public static void main(String[] args) throws Exception {
        Selector selector = Selector.open();
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            for (SelectionKey key : selector.selectedKeys()) {
                if (key.isAcceptable()) {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(100);
                    int bytesReceived = socketChannel.read(buffer);
                    if (bytesReceived > 0) {
                        buffer.flip();
                        System.out.println("Received: " + new String(buffer.array(), 0, bytesReceived));
                        buffer.clear();
                    }
                }
            }
            selector.selectedKeys().clear();
        }
    }
}

数据库连接

在分布式系统中,数据库连接是实现数据持久化的重要组成部分。Java提供了多种方法连接数据库,如Java Database Connectivity (JDBC)、MyBatis和Hibernate。

JDBC是一个Java标准接口,用于与各种数据库进行通信。以下是一个简单的JDBC示例:

import java.sql.*;

public class DatabaseConnection {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydatabase";
        String user = "root";
        String password = "password";

        try {
            Connection conn = DriverManager.getConnection(url, user, password);
            System.out.println("Connected to the database successfully!");

            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM users");

            while (rs.next()) {
                System.out.println("Username: " + rs.getString("username"));
                System.out.println("Email: " + rs.getString("email"));
            }

            rs.close();
            stmt.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

MyBatis是一个持久层框架,用于简化数据库操作。以下是一个简单的MyBatis示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
    <select id="selectUser" resultType="com.example.model.User">
        SELECT * FROM users WHERE id = #{id}
    </select>
</mapper>
import org.apache.ibatis.session.SqlSession;

public class MyBatisExample {
    public static void main(String[] args) {
        SqlSession session = null;
        try {
            session = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession();
            User user = session.selectOne("com.example.mapper.UserMapper.selectUser", 1);
            System.out.println("User: " + user.getUsername() + ", " + user.getEmail());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (session != null) {
                session.close();
            }
        }
    }
}

Hibernate是一个对象关系映射(ORM)框架,用于简化Java对象与数据库之间的映射。以下是一个简单的Hibernate示例:

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateExample {
    public static void main(String[] args) {
        SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
        Session session = sessionFactory.openSession();
        session.beginTransaction();
        User user = new User();
        user.setUsername("user1");
        user.setEmail("[email protected]");
        session.save(user);
        session.getTransaction().commit();
        session.close();
        sessionFactory.close();
    }
}

分布式缓存

分布式缓存是用于存储和访问数据的内存数据库,它提高了应用程序的响应速度和性能。Java中常用的分布式缓存技术包括Redis、Memcached和Apache Ignite等。

Redis是一个内存数据库,提供了丰富的数据结构和网络通信机制。以下是一个使用Jedis客户端访问Redis的示例:

import redis.clients.jedis.Jedis;

public class RedisExample {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("localhost");

        // 设定值
        jedis.set("key", "value");
        System.out.println("Set 'key' to 'value'");

        // 获取值
        String value = jedis.get("key");
        System.out.println("Value of 'key': " + value);

        // 删除值
        jedis.del("key");
        System.out.println("Deleted 'key'");

        jedis.close();
    }
}

Memcached是一个高性能的分布式内存对象缓存系统。以下是一个使用Memcached客户端访问Memcached的示例:

import net.spy.memcached.AddrUtil;
import net.spy.memcached.MemcachedClient;

public class MemcachedExample {
    public static void main(String[] args) throws Exception {
        MemcachedClient memcachedClient = new MemcachedClient(AddrUtil.getAddresses("localhost:11211"));
        memcachedClient.set("key", 0, "value");
        System.out.println("Set 'key' to 'value'");
        String value = memcachedClient.get("key").toString();
        System.out.println("Value of 'key': " + value);
        memcachedClient.delete("key");
        System.out.println("Deleted 'key'");
        memcachedClient.shutdown();
    }
}

Apache Ignite是一个高性能、可扩展的内存平台,用于构建分布式数据处理系统。以下是一个使用Apache Ignite的简单示例:

import org.apache.ignite.Ignition;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;

public class IgniteExample {
    public static void main(String[] args) {
        IgniteConfiguration cfg = new IgniteConfiguration();
        CacheConfiguration<String, String> cacheCfg = new CacheConfiguration<>("myCache");
        cacheCfg.setCacheMode(CacheMode.REPLICATED);
        cfg.setCacheConfiguration(cacheCfg);
        Ignition.start(cfg);

        Ignite ignite = Ignition.ignite();
        ignite.getCache("myCache").put("key", "value");
        System.out.println("Set 'key' to 'value'");
        String value = ignite.getCache("myCache").get("key");
        System.out.println("Value of 'key': " + value);
        ignite.getCache("myCache").remove("key");
        System.out.println("Deleted 'key'");
    }
}
Java分布式系统的开发工具

Eclipse和IntelliJ IDEA简介

EclipseIntelliJ IDEA是两个广泛使用的Java集成开发环境(IDE)。它们提供了代码编辑、调试、测试和部署功能,支持Java开发的各个方面。

  • Eclipse是一个开源IDE,提供了广泛的插件和扩展,支持多种编程语言。
  • IntelliJ IDEA是一个商业IDE,提供了代码智能感知、快速修复和重构功能,支持Java和其他多种编程语言。

Maven与Gradle的使用

MavenGradle是两个广泛使用的构建工具,用于管理Java项目的依赖关系和构建流程。

Maven使用项目对象模型(POM)文件来定义构建配置,支持自动下载依赖关系和执行构建任务。以下是一个简单的Maven POM文件示例:

<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>example-project</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.3.4.RELEASE</version>
        </dependency>
    </dependencies>
</project>

Gradle使用Groovy或Kotlin脚本文件来定义构建配置,支持更灵活的构建流程。以下是一个简单的Gradle脚本示例:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web:2.3.4.RELEASE'
}

Spring Boot与Spring Cloud集成

Spring Boot是一个用于简化Spring应用开发的框架,提供了自动配置和依赖管理功能。Spring Cloud是一个用于构建分布式系统的框架,提供了服务发现、断路器、负载均衡等特性。

Spring Boot示例:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

Spring Cloud示例:

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

@SpringBootApplication
@EnableEurekaClient
public class EurekaClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaClientApplication.class, args);
    }
}
实战:搭建一个简单的Java分布式系统

环境搭建

要搭建一个简单的Java分布式系统,需要准备以下工具和环境:

  1. IDE:Eclipse或IntelliJ IDEA。
  2. 构建工具:Maven或Gradle。
  3. 服务器:Tomcat或Jetty。
  4. 数据库:MySQL或PostgreSQL。

代码示例

以下是一个简单的Java分布式系统示例,包含一个服务端和客户端。

服务端代码示例

import java.io.*;
import java.net.*;

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        System.out.println("Server started on port 8080");

        while (true) {
            Socket clientSocket = serverSocket.accept();
            new Thread(() -> {
                try {
                    BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
                    String request = in.readLine();
                    System.out.println("Received request: " + request);

                    PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
                    out.println("Received your request: " + request);

                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

客户端代码示例

import java.io.*;
import java.net.*;

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 8080);
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        out.println("Hello Server");

        BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String response = in.readLine();
        System.out.println("Server response: " + response);

        socket.close();
    }
}

运行与测试

  1. 使用IDE启动服务端代码。
  2. 执行客户端代码,检查服务端是否正确接收和响应请求。
Java分布式系统中的常见问题与解决方案

数据一致性问题

分布式系统中的数据一致性问题是确保所有参与节点对同一数据有相同认识。常用的解决方案包括:

  • 最终一致性:允许数据在一段时间内不同步,但最终会达到一致状态。
  • 强一致性:要求所有节点对同一数据有一致的认识。
  • 共识算法:如Raft和Paxos,用于确保多个节点之间的数据一致。

数据库一致性示例

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DatabaseConsistencyExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydatabase";
        String user = "root";
        String password = "password";

        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            // 更新数据
            String updateQuery = "UPDATE users SET status = ? WHERE id = ?";
            try (PreparedStatement updateStmt = conn.prepareStatement(updateQuery)) {
                updateStmt.setString(1, "active");
                updateStmt.setInt(2, 1);
                updateStmt.executeUpdate();
            }

            // 查询数据
            String selectQuery = "SELECT status FROM users WHERE id = ?";
            try (PreparedStatement selectStmt = conn.prepareStatement(selectQuery)) {
                selectStmt.setInt(1, 1);
                ResultSet rs = selectStmt.executeQuery();
                while (rs.next()) {
                    System.out.println("Status: " + rs.getString("status"));
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

网络通信故障处理

网络通信故障是分布式系统中常见的问题,需要采取措施来处理这些故障。常用的解决方案包括:

  • 重试机制:在网络连接失败时自动重试。
  • 超时处理:设置超时时间,避免长时间等待。
  • 断路器模式:在网络故障时隔离故障节点,防止整个系统崩溃。

网络通信重试机制示例

import java.io.*;
import java.net.Socket;
import java.util.concurrent.TimeUnit;

public class RetryExample {
    public static void main(String[] args) {
        String host = "localhost";
        int port = 8080;
        int maxRetries = 3;
        int retryInterval = 2; // seconds
        String request = "Hello Server";

        for (int i = 0; i < maxRetries; i++) {
            try (Socket socket = new Socket(host, port)) {
                PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
                out.println(request);

                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                String response = in.readLine();
                System.out.println("Server response: " + response);
                break;
            } catch (IOException e) {
                System.err.println("Failed to connect to server. Retrying...");
                try {
                    TimeUnit.SECONDS.sleep(retryInterval);
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
}

性能优化方法

分布式系统需要处理大量并发请求,性能优化是确保系统高效运行的关键。常用的优化方法包括:

  • 负载均衡:将请求分发到多个服务器,避免单点过载。
  • 缓存:使用分布式缓存减少数据库访问,提高响应速度。
  • 异步处理:使用消息队列等技术处理异步任务,提高系统吞吐量。

负载均衡示例

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class LoadBalancer {
    private List<Service> services;
    private AtomicInteger currentIndex = new AtomicInteger(0);

    public LoadBalancer(List<Service> services) {
        this.services = services;
    }

    public void dispatchRequest(String request) {
        int index = currentIndex.getAndIncrement() % services.size();
        services.get(index).handleRequest(request);
    }
}

interface Service {
    void handleRequest(String request);
}

public class SimpleService implements Service {
    @Override
    public void handleRequest(String request) {
        System.out.println("Processing request: " + request);
    }
}

public class LoadBalancerExample {
    public static void main(String[] args) {
        List<Service> services = List.of(new SimpleService(), new SimpleService());
        LoadBalancer loadBalancer = new LoadBalancer(services);
        ExecutorService executor = Executors.newFixedThreadPool(10);

        for (int i = 0; i < 100; i++) {
            executor.submit(() -> loadBalancer.dispatchRequest("Request " + i));
        }

        executor.shutdown();
    }
}
Java分布式系统部署与运维

部署方式

分布式系统可以部署在不同的环境中,包括本地机器、虚拟机和云服务(如AWS、Azure和阿里云)。部署方式包括:

  • 单机部署:适用于测试和小型项目。
  • 容器化部署:使用Docker和Kubernetes等容器技术来部署和管理服务。
  • 云服务部署:利用云服务提供商的资源和服务部署应用。

监控与日志管理

监控和日志管理是分布式系统运维的重要环节,需要关注以下方面:

  • 监控工具:使用Prometheus、Grafana等工具监控系统状态。
  • 日志管理:使用ELK(Elasticsearch、Logstash、Kibana)等工具收集和分析日志。

Prometheus监控示例

import io.prometheus.client.Counter;
import io.prometheus.client.Summary;

public class PrometheusExample {
    public static final Counter requestCounter = Counter.build()
        .name("request_count")
        .help("Total number of requests")
        .create();

    public static final Summary requestLatency = Summary.build()
        .name("request_latency_ms")
        .help("Total latency of requests in milliseconds")
        .create();

    public static void main(String[] args) {
        requestCounter.inc();
        requestLatency.observe(100); // latency in milliseconds
    }
}

ELK日志管理示例

import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;

public class LoggingExample {
    private static final Logger logger = Logger.getLogger(LoggingExample.class);

    public static void main(String[] args) {
        DOMConfigurator.configure("log4j.xml");

        logger.info("Logging information");
        logger.warn("Logging warning");
        logger.error("Logging error");
    }
}

安全性考虑

安全性是分布式系统运维中必不可少的考虑因素,包括:

  • 身份验证:使用OAuth、JWT等技术验证用户身份。
  • 加密通信:使用HTTPS、SSL等协议加密网络通信。
  • 访问控制:限制对敏感资源的访问,使用RBAC(Role-Based Access Control)等技术管理权限。

身份验证示例

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;

public class AuthenticationExample {
    public static void main(String[] args) {
        Algorithm algorithm = Algorithm.HMAC256("secret");
        String token = JWT.create()
            .withSubject("johndoe")
            .withArrayClaim("roles", new String[]{"admin", "user"})
            .withExpiresAt(new Date(System.currentTimeMillis() + 3600000))
            .sign(algorithm);

        System.out.println("Generated JWT token: " + token);
    }
}

加密通信示例

import javax.net.ssl.HttpsURLConnection;
import java.net.URL;

public class SecureCommunicationExample {
    public static void main(String[] args) throws Exception {
        URL url = new URL("https://example.com");
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.connect();

        int responseCode = connection.getResponseCode();
        System.out.println("Response Code: " + responseCode);
        connection.disconnect();
    }
}

访问控制示例

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Arrays;
import java.util.Collections;

public class AccessControlExample {
    public static void main(String[] args) {
        Algorithm algorithm = Algorithm.HMAC256("secret");
        String token = JWT.create()
            .withSubject("johndoe")
            .withArrayClaim("roles", new String[]{"admin", "user"})
            .withExpiresAt(new Date(System.currentTimeMillis() + 3600000))
            .sign(algorithm);

        DecodedJWT decodedJWT = JWT.decode(token);
        String[] roles = decodedJWT.getClaim("roles").asArray(String.class);
        if (Collections.binarySearch(Arrays.asList(roles), "admin") >= 0) {
            System.out.println("Access granted as admin");
        } else {
            System.out.println("Access denied");
        }
    }
}

通过以上内容,你已经了解了Java分布式系统的概念、基础组件、开发工具、实战示例以及运维方面的知识。希望这些内容能够帮助你更好地理解和开发Java分布式系统。

點擊查看更多內容
TA 點贊

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

評論

作者其他優質文章

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

100積分直接送

付費專欄免費學

大額優惠券免費領

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

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

幫助反饋 APP下載

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

公眾號

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

舉報

0/150
提交
取消