Chat Room

package cy;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

public class ChatRoomServer extends Frame implements Runnable {
    Panel panel;

    ScrollPane sPanel;

    TextArea textArea;

    Button button1;

    // net
    ServerSocket serverSock;

    public final static int DEFAULT_PORT = 6666;// 默认端口号

    Thread chatAcceptThread;// 启动接受连接的线程

    BroadcastThread broadcastThread;// 广播thread; run when server is listening

    java.util.Vector clients;// 记录连接的线程

    java.util.Vector clientsInfor;// 记录连接线程的信息

    public static int index = 0;

    public ChatRoomServer() {
        try {
            jbInit();
        } catch (Exception e) {
            e.printStackTrace();
        }
        serverListen();// 服务器开始监听
    }

    private void jbInit() {// 初始化界面
        panel = new Panel();
        sPanel = new ScrollPane();
        textArea = new TextArea("server information:/n");
        button1 = new Button("退出");

        sPanel.add(textArea);

        button1.addActionListener(new java.awt.event.ActionListener() {// 退出按钮注册
                    public void actionPerformed(ActionEvent e) {
                        button1_actionPerformed(e);
                    }
                });
        panel.add(button1);

        this.addWindowListener(new ChatFrame_WindowAdapter(this));// 注册到继承了窗口适配器的类
        this.setSize(600, 600);
        this.setLayout(new BorderLayout());
        this.add(sPanel, BorderLayout.CENTER);
        this.add(panel, BorderLayout.SOUTH);
        this.show();

    }

    private void button1_actionPerformed(ActionEvent e) {
        exit();
    }

    public void processMsg(String str) {//
        textArea.append(str);
    }

    private void serverListen() {
        try {
            serverSock = new ServerSocket(DEFAULT_PORT);
        } catch (IOException e) {
            processMsg(e.toString());
            processMsg("server failed!/n");
        }
        processMsg("server listening on port:" + DEFAULT_PORT);
        clients = new java.util.Vector();
        clientsInfor = new java.util.Vector();

        chatAcceptThread = new Thread(this);// 启动接受连接的线程
        chatAcceptThread.start();

        broadcastThread = new BroadcastThread(this);// 广播线程
        broadcastThread.start();

        // 还有一个回收无用连接thread 的线程
    }

    public void run() {// 接受连接并记录线程信息
        int i = 0;
        try {
            while (true) {
                Socket clientSock = serverSock.accept();
                CommunicateThread ct = new CommunicateThread(clientSock, this,
                        index);// 创建线程保持连接
                clients.add(ct);// record Communicate Thread;
                i++;
                index++;// version2
                clientsInfor.add("Thread-" + i);
                processMsg("Thread-" + i + "join in/n");

            }
        } catch (IOException e) {
            processMsg(e.toString());
        }
    }

    public void exit() {
        broadcastThread.broadcast("Server exit!");
        try {
            serverSock.close();
        } catch (IOException ioe) {
        } finally {
            System.exit(0);
        }
    }

    public static void main(String[] args) {
        ChatRoomServer chat = new ChatRoomServer();
    }
}

class CommunicateThread extends Thread {// 保持连接线程
    protected Socket clientSock;

    protected BufferedReader in = null;

    protected PrintWriter out;

    ChatRoomServer chatFrame;

    boolean isTrue = true;// run()

    java.util.Vector inforStack;

    int index2;//

    public CommunicateThread(Socket Sock, ChatRoomServer cFrame, int index) {
        clientSock = Sock;
        chatFrame = cFrame;
        index2 = index;
        inforStack = new java.util.Vector();
        try {
            in = new BufferedReader(new InputStreamReader(clientSock
                    .getInputStream()));
            out = new PrintWriter(clientSock.getOutputStream());
        } catch (IOException ei) {
            try {
                clientSock.close();
            } catch (IOException ei2) {
            }
            chatFrame.processMsg(ei.toString());
            return;
        }
        this.start();
    }

    public void run() {
        String infor;
        try {
            while (isTrue) {
                infor = in.readLine();
                if (infor.equals("Client exit!")) {
                    writeInformation(infor);// 把信息写到信息栈,以倍广播出去
                    stopRun();
                } else if (infor != null) {
                    writeInformation(infor);
                }// else break;
                try {
                    Thread.sleep(100);// version2
                } catch (InterruptedException ex) {
                }
            }
        } catch (IOException e) {
            ;
        } finally {
            try {
                in.close();
                out.close();
                clientSock.close();
                chatFrame.clients.remove(index2);// 在clients中清除本线程序
                ChatRoomServer.index--;//
            } catch (IOException ei) {
                ;
            }
        }

    }

    public void writeInformation(String infor) {// 写信息栈
        inforStack.add(infor);
    }

    private void stopRun() {// 终止线程
        isTrue = false;
    }

    public void sendInformation(String str) {// 发送信息
        try {
            out.println(str);
            out.flush();
        } catch (Exception e) {
            ;
        }
    }
}

class BroadcastThread extends Thread {// 广播线程
    ChatRoomServer chatFrame2;

    java.util.Vector chatClients;// 连接线程信息

    java.util.Vector msgStack;// 信息栈

    java.util.Vector clientMsg;// 记录客户发送的信息

    CommunicateThread comThread1;

    CommunicateThread comThread2;

    String string;// information in inforStack

    String clientName;// client thread name

    String broadcastInfor;// broadcast information=clientName+string;

    public BroadcastThread(ChatRoomServer cFrame) {
        chatFrame2 = cFrame;
        chatClients = chatFrame2.clients;
        clientMsg = chatFrame2.clientsInfor;
        // this.start();
    }

    public void broadcast(String str) {// 广播
        for (int k = 0; k < chatClients.size(); k++) {// send to
                                                        // everyone分别调用每个连接线程,发送信息
            comThread2 = (CommunicateThread) chatClients.get(k);
            comThread2.sendInformation(str);
        }
    }

    public void run() {
        try {
            while (true) {
                for (int i = 0; i < chatClients.size(); i++) {
                    comThread1 = (CommunicateThread) chatClients.get(i);
                    msgStack = comThread1.inforStack;// 得到每个连接的信息栈
                    clientName = (String) clientMsg.get(i);// 客户名
                    // 读取每个连接线程的信息栈并把信息发送出去
                    for (int j = 0; j < msgStack.size(); j++) {
                        string = (String) msgStack.get(j);
                        broadcastInfor = clientName + "->" + string;
                        broadcast(broadcastInfor);
                    }
                    // clear the inforStack
                    msgStack.removeAllElements();// 清除以发送的信息

                }
                try {
                    Thread.sleep(100);// version2
                } catch (InterruptedException ex) {
                }
            }
        } catch (Exception e) {
        }
    }

}

// 处理窗口关闭事件的适配器
class ChatFrame_WindowAdapter extends java.awt.event.WindowAdapter {
    ChatRoomServer chatFrame;

    public ChatFrame_WindowAdapter(ChatRoomServer chatFrame) {
        this.chatFrame = chatFrame;
    }

    public void windowClosing(WindowEvent e) {// exit program
        chatFrame.exit();// reference to the method exit() in ChatRoomServer.
    }
}



======================
package cy;

//ChatRoomClient
//designed by Chen Heping(陈和平)

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;

public class ChatRoomClient extends Frame implements Runnable {
    Panel panel1, panel2;

    Button button1, button2;

    TextField textField1, textField2;

    Label label1;

    TextArea textArea;

    ScrollPane sPanel;

    // net
    PrintWriter out;

    BufferedReader in = null;

    Socket sock;

    public final static int DEFAULT_PORT = 6666;

    // create Thread to Read information from Server
    Thread readThread;

    boolean isTrue = true;// thread can go on runing ??

    public ChatRoomClient() {
        try {
            jbInit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {// main method
        ChatRoomClient c = new ChatRoomClient();
        c.show();
    }

    private void jbInit() {// should set size,position and Font of every
        // component

        button1 = new Button("连接");// set Font
        button2 = new Button("发送");
        textField1 = new TextField("input Server address here!");
        textField2 = new TextField("input Message here and send to server");
        label1 = new Label("消息:");
        panel1 = new Panel();
        panel2 = new Panel();
        sPanel = new ScrollPane();
        textArea = new TextArea();

        // panel1
        // press button1: 连接 to connect the client to server
        button1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(ActionEvent e) {
                button1_actionPerformed(e);
            }
        });
        // textField1:for input the address of server;be registered to
        // KeyListener.
        // press key:Enter to connect the client to server
        textField1.addKeyListener(new textField1_KeyAdapter(this));// java.awt.event.KeyAdapter()
        panel1.add(button1);
        panel1.add(textField1);

        // sPanel ScrollPane
        sPanel.add(textArea);

        // panel2
        // press button2: 发送 to send message
        button2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(ActionEvent e) {
                button2_actionPerformed(e);
            }
        });
        // textField2:for input message;be registered to KeyListener.
        // press key:Enter to send message
        textField2.addKeyListener(new textField2_KeyAdapter(this));
        panel2.add(label1);
        panel2.add(textField2);
        panel2.add(button2);

        // frame
        this.addWindowListener(new ChatFrame_WindowAdapterClient(this));// frame
                                                                        // is
        // registered to
        // WindowListener
        this.setLayout(new BorderLayout());
        this.setSize(500, 400);
        this.add(panel1, BorderLayout.NORTH);
        this.add(sPanel, BorderLayout.CENTER);
        this.add(panel2, BorderLayout.SOUTH);
        // this.show()

    }

    public void startConnect() {// 开始连接
        try {
            sock = new Socket(textField1.getText(), DEFAULT_PORT);
            if (sock != null) {// connection successed
                processMsg("Connect successfully!");
            }
            in = new BufferedReader(
                    new InputStreamReader(sock.getInputStream()));
            out = new PrintWriter(sock.getOutputStream());
        } catch (IOException ex) {
            processMsg(ex.toString());
            processMsg("Connect failed!");
        }

        readThread = new Thread(this);
        readThread.start();
    }

    // public void endConnect(){//close IOstream

    public void sendInformation() {
        out.println(textField2.getText());
        out.flush();

    }

    private void button1_actionPerformed(ActionEvent e) {// 连接按钮
        startConnect();
    }

    private void button2_actionPerformed(ActionEvent e) {// 发送按钮
        sendInformation();
    }

    public void stopRun() {// to stop the running thread
        isTrue = false;
    }

    public void processMsg(String msg) {// 客户端处理消息
        textArea.append(msg);
        textArea.append("/n");
    }

    public void run() {
        String msg;
        isTrue = true;
        while (isTrue) {
            try {
                msg = in.readLine();
                if (msg.equals("Server exit!")) {// server exit
                    processMsg(msg);
                    stopRun();// 终止线程
                } else if (msg != null) {
                    processMsg(msg);
                }
                Thread.sleep(1000);
            } catch (IOException e) {
                processMsg(e.toString());
            } catch (InterruptedException ei) {
                processMsg(ei.toString());
            }
        }
        // endConnect();
        try {// 服务器退出关闭连接和相关的"流"
            sock.close();
            in.close();
            out.close();
        } catch (IOException ioe) {
        }
    }

    public void exit() {// 窗口关闭;如果有连接则关闭连接和相关的"流"
        try {// send "Client exit!" to Server!
            out.println("Client exit!");
            out.flush();
        } catch (Exception exc) {
        }
        // endConnect();
        try {// close IOstream
            sock.close();
            in.close();
            out.close();
        } catch (IOException ioe) {
        } finally {
            System.exit(0);
        }
    }
}

// 文本筐textField1的键击事件适配器
class textField1_KeyAdapter extends java.awt.event.KeyAdapter {
    ChatRoomClient chatFrame;

    public textField1_KeyAdapter(ChatRoomClient chatFrame) {
        this.chatFrame = chatFrame;
    }

    public void keyPressed(KeyEvent e) {// 输入的是enter,开始连接!
        int j = e.getKeyCode();
        if (j == e.VK_ENTER) {
            chatFrame.startConnect();
        }
    }
}

// 文本筐textField2的键击事件适配器
class textField2_KeyAdapter extends java.awt.event.KeyAdapter {
    ChatRoomClient chatFrame;

    public textField2_KeyAdapter(ChatRoomClient chatFrame) {
        this.chatFrame = chatFrame;
    }

    public void keyPressed(KeyEvent e) {// 键击Enter键,发送信息!
        int j = e.getKeyCode();
        if (j == e.VK_ENTER) {
            chatFrame.sendInformation();
        }
    }
}

// 窗口关闭事件适配器
class ChatFrame_WindowAdapterClient extends java.awt.event.WindowAdapter {
    ChatRoomClient chatFrame;

    public ChatFrame_WindowAdapterClient(ChatRoomClient chatFrame) {
        this.chatFrame = chatFrame;
    }

    public void windowClosing(WindowEvent e) {// exit program
        chatFrame.exit();// reference to the method exit() in ChatRoomClient.
    }
}
1. 实现登录功能        先把从前台接收的数据封装起来,然后查询数据库,看数据库中是否有这个用户,如果没有则提示登录失败,如果有这个用户则先销毁之前的session,然后再检查此用户是否在其它地方登录,有的话则销毁它的session,强制下线。到这里才算登录成功,将页面跳转到主聊天界面。 2. 检查用户登录信息是否过期的实现        获取session域中的User对象,判断该对象是否为空,如果为空则用户登录信息过期,提示用户重新登录,跳转到登录界面。 3. 注册功能的实现        先把从前台接收的数据封装起来,然后检查用户输入的两次密码是否一致,如果不一致,则提示“登录失败,两次密码不一致”的错误,然后查询数据库是否有用户名一样的用户,如果有,则提示“注册失败,此用户已存在”,否则向数据库中插入用户信息,然后提示注册成功。 4. 聊天功能的实现        发送消息:先获取从前台发送的聊天内容,然后拼接上已发送的聊天记录,再将消息存入到application的范围,最后调用接收消息的方法。         接收消息:从ServletContext中获取消息,如果不为空则输出消息。 5. 在线人员列表显示功能的实现        将登录进系统的用户与其对应的session存储到一个userMap中,然后显示出来 6. 踢人功能的实现        接收前台传来的需要踢下线的用户id,然后在userMap中获取用户并销毁该用户的session    7. 退出聊天室        获得session然后将其销毁,跳转到登录界面
chatRoom.zip 聊天室聊天室服务端 package chatroom; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashSet; import javax.swing.JFrame; import javax.swing.JOptionPane; /** * 聊天室服务器端 ChatRoomServer类 * * @version 1.01, 09/04/10 */ public class ChatRoomServer { private ServerSocket ss; /* 存放Socket的集合hs */ private HashSet<Socket> hs; public ChatRoomServer() { JFrame jf = new JFrame(); do { /* * 弹出输入对话框,提示输入服务器需要绑定的端口号 */ int port = Integer.parseInt(JOptionPane.showInputDialog(jf, "bind port:")); try { ss = new ServerSocket(port); System.out.println("server start success,now listening port:" + port); } catch (Exception e) { /* 弹出确认框进行确认 */ int op = JOptionPane.showConfirmDialog(jf, // 指定是在jf中弹出确认框 "bind fail,retry?", // 框体内容 "bind fail", // 对话框的标题 JOptionPane.YES_NO_OPTION); // 确认框按钮项 /* 如果选择'否',则退出程序 */ if (op == JOptionPane.NO_OPTION) { System.exit(1); } /* 打印异常栈信息 */ e.printStackTrace(); } } while (ss == null); /* 创建HashSet,用来存放Socket对象 */ hs = new HashSet<Socket>(); while (true) { try { /* 获得Socket,网络阻塞,等待客户端的连接 */ Socket s = ss.accept(); /* 一旦客户端连接上,则加入HashSet,便于维护 */ hs.add(s); /* 启动一个服务线程,为客户端服务 */ new ServerThread(s).start(); } catch (IOException e) { e.printStackTrace(); } } } /** * 成员内部类,服务线程类 */ class ServerThread extends Thread { private Socket s; public ServerThread(Socket s) { this.s = s; } @Override public void run() { BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(s .getInputStream())); while (true) { /* 从网络中读取客户端发出的消息 */ String str = br.readLine(); /* * 客户退出时的处理逻辑 规则:以"%EXIT_CHATROOM%"开头的消息为客户退出标记 */ if (str.charAt(0) == '%') { String com = str.split("%")[1]; if (com.equals("EXIT_CHATROOM")) { hs.remove(s); printMessage(str.split("%")[2] + ",leave!"); s.close(); break; } } else { /* 正常情况,直接向客户端群发消息 */ printMessage(str); } } } catch (IOException e) { e.printStackTrace(); } } /* * 负责为客户端群发消息 */ private void printMessage(String mes) { System.out.println(mes); try { /* 遍历所有Socket */ for (Socket s : hs) { PrintStream ps = new PrintStream(s.getOutputStream()); /* 产生发消息的时刻 */ Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); /* 向客户端发消息,消息结构为mes [yyyy-MM-dd HH:mm:ss] */ ps.println(mes + " [" + sdf.format(date) + "]"); /* 注意需要及时flush,清空缓冲区 */ ps.flush(); } } catch (IOException e) { e.printStackTrace(); } } } /* * 主方法,启动聊天室服务器端 */ public static void main(String[] args) { new ChatRoomServer(); } } 客户端窗体 package chatroom; import java.awt.BorderLayout; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; /** * 客户端窗口ChatRoomClientFrame类 负责客户端的视图表示、事件处理等逻辑 作为一个窗口,所以本类继承自JFrame * 为了实现事件处理,本类实现了ActionListener接口 * * @version 1.01, 09/04/10 */ public class ChatRoomClientFrame extends JFrame implements ActionListener { private static final long serialVersionUID = 3484437496861281646L; private JTextArea jta; // 多行文本域 private JLabel label; // 文本标签 private JTextField jtf; // 单行文本框 private JButton jb; // 按钮 private Socket socket; // socket 套接字 private String name; // 用户名 /* * ChatRoomClientFrame构造方法,负责初始化以及添加事件处理 */ public ChatRoomClientFrame(String name, Socket socket) { super("chatroom"); Font f = new Font("楷体", Font.BOLD, 20); /* 设置字体 */ jta = new JTextArea(10, 10); /* 创建10行10列的空多行文本域 */ jta.setEditable(false); /* 设置多行文本域为不可编辑 */ jta.setFont(f); /* 设置多行文本域字体 */ label = new JLabel(name + ":"); /* 创建带有用户名的文本标签 */ label.setFont(f); /* 设置文本标签字体 */ jtf = new JTextField(25); /* 创建单行文本框 */ jtf.setFont(f); /* 设置单行文本框字体 */ jb = new JButton("send"); /* 创建按钮 */ this.name = name; this.socket = socket; init(); /* 初始化,设置组件关系 */ addEventHandler(); /* 为组件添加事件监听 */ } /* * 初始化组件关系方法,供构造方法调用 */ private void init() { JScrollPane jsp = new JScrollPane(jta); this.add(jsp, BorderLayout.CENTER); JPanel jp = new JPanel(); jp.add(label); jp.add(jtf); jp.add(jb); this.add(jp, BorderLayout.SOUTH); } /* * 负责为各组件添加事件处理机制 */ private void addEventHandler() { jb.addActionListener(this); // 为jb添加事件监听,JButton点击触发事件 jtf.addActionListener(this); // 为jtf添加事件监听,JTextField敲回车触发事件 /* 设置JFrame默认关闭状态:DO_NOTHING_ON_CLOSE */ this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); /* 为JFrame添加窗口事件监听 */ this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent arg0) { /* 弹出确认框进行交互 */ int op = JOptionPane.showConfirmDialog( ChatRoomClientFrame.this, "exit?", "exit", JOptionPane.YES_NO_OPTION); if (op == JOptionPane.YES_OPTION) { try { PrintStream ps = new PrintStream(socket .getOutputStream()); /* 向服务器发送以%EXIT_CHATROOM%name为格式的串,代表退出信号 */ ps.println("%EXIT_CHATROOM%" + name); /* 注意需要及时flush */ ps.flush(); try { Thread.sleep(168); // 进行延时控制,防止提前关闭socket } catch (InterruptedException e) { e.printStackTrace(); } socket.close(); // 关闭客户端socket ps.close(); // 关闭流 } catch (IOException e) { e.printStackTrace(); } System.exit(1); // 退出程序 } } }); } /* * 实现事件处理方法 */ public void actionPerformed(ActionEvent ae) { try { PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println(name + ": " + jtf.getText()); ps.flush(); /* 清空jtf中内容 */ jtf.setText(""); } catch (IOException e) { e.printStackTrace(); } } /* * 显示并执行窗口逻辑 */ public void showMe() { this.pack(); // 自动调整此窗口的大小 this.setVisible(true); // 设置窗口可见 /* * 启动线程,负责接收服务器端发来的消息 */ new Thread() { @Override public void run() { BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(socket .getInputStream())); while (true) { /* 从网络中读取服务器发出的数据 */ String str = br.readLine(); /* 对JTextArea进行追加消息 */ jta.append(str + "\n"); } } catch (IOException e) { e.printStackTrace(); } } }.start(); } } 客户端 package chatroom; import java.io.PrintStream; import java.net.Socket; import javax.swing.JFrame; import javax.swing.JOptionPane; /** * 聊天室客户端 ChatRoomClient * * @version 1.01, 09/04/10 */ public class ChatRoomClient { private String name; // 用户名 private Socket socket; // Socket 套接字 private ChatRoomClientFrame frame; // 组合复用 ChatRoomClientFrame /* * ChatRoomClient构造方法,负责构造客户端表示逻辑 */ public ChatRoomClient() { JFrame jf = new JFrame(); /* * 弹出用户输入对话框,提示用户输入服务器的IP地址 返回相应字符串形式,存于变量serverIP,缺省值127.0.0.1 */ String serverIP = JOptionPane.showInputDialog(jf, "server IP:", "127.0.0.1"); /* * 弹出用户输入对话框,提示用户输入服务器端口号 转化为int形式返回,存于变量serverPort */ int serverPort = Integer.parseInt(JOptionPane.showInputDialog(jf, "port:")); /* * 弹出用户输入对话框,提示用户输入用户名,存于成员属性name */ name = JOptionPane.showInputDialog(jf, "your name:"); try { /* 通过IP和Port,与服务器端建立连接 */ socket = new Socket(serverIP, serverPort); /* 给服务器发消息 */ PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println(name + ",login !"); } catch (Exception e) { JOptionPane.showMessageDialog(jf, "fail,check the connection!"); e.printStackTrace(); System.exit(1); } /* * 创建ChatRoomClientFrame,进行客户端主窗口的显示 */ frame = new ChatRoomClientFrame(name, socket); frame.showMe(); } /* * 主方法,启动聊天室客户端 */ public static void main(String[] args) { new ChatRoomClient(); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值