RMI原理展示-UI含源代码

博采众生我在上一篇文章中,简单地介绍了RMI的原理,这一篇文章我想在通过一个稍微复杂一点的例子,更好的向大家说明。读这篇文章需要你先参考我的上一篇文章: RMI(Remote Method Invocation)原理浅析

例子中,用到了javaUI的swing和事件处理,以及线程知识,如果你对这方面的知识不是太清楚的话,希望你能参考一下资料,非常简单 !

例子的思想就是通过在远程启动服务,客户端提交任务,处理完以后,把结果反馈给客户端完成任务。程序的功能就是计算加减乘除, 有六个文件,分别为:

  • AllCalculate.java,接口,定义了客户端和服务端共用的接口;
  • AllCalculateImpl.java,服务端接口实现;
  • AllCalculateServer.java,服务端服务提供者,它需要实例接口实现,导入到注册表中;
  • MyRMIExam.java,客户端启动
  • MyRMIGui.java,客户端UI,实现了加减乘除,分别在不同的线程里处理,是程序不会猛然间显得没有反应;
  • ServiceListFrame.java,使用在客户端,用以检索服务端机器的远程服务名字。
  • tools包是我自己写的一个工具包,辅助我来验证客户的输入,有关这个包中的文本验证和窗体居中显示,请你参考我的三片文章: 文本控件内容录入限制(含源代码说明)(一) Java 文本控件内容录入限制(含源代码说明)(二) Java窗体居中显示。由于源代码比较长,在这里就是简单的罗列了: AllCalculate.java,AllCalculateServer.java和MyRMIExam.java代码清单,如果你需要参考完整的源代码,请你到CSDN资源下载中心下载,文件名称为:MyRMI.rar(搜索下载, 我得源代码中使用的UTF-8的编码格式,工程是Eclipse),如果你有任何问题的话,请给我留言。

    下面是程序运行的几幅演示图片,你可以在你的电脑上演示:

    博采众生

    所在环境的文件结构,方便你的实验

    博采众生

    Eclipse中的结构

    博采众生

    在Eclipse中启动设置,注意此时需要先启动rmiregistry服务环境

    博采众生

    客户端启动配置

    博采众生

    如果你没有安装Eclipse,需要手动命令行启动

    博采众生

    命令行启动客户端,注意此时client.policy放在exam目录下

    图片中,小三角加感叹号是由于我使用恶java的SecurityManager,你可以在源代码中注释掉这个功能。

    以下是几个程序源码清单:

    1. package net.csdn.blog.qb2049_xg;
    2. import java.rmi.Remote;
    3. import java.rmi.RemoteException;
    4. /**
    5.  *AllCalculate.java
    6.  * @author Ulysses Ma
    7.  * @date 2008-9-9
    8.  *Remote 在这里标识远程对象
    9.  */
    10. public interface AllCalculate extends Remote 
    11. {
    12.     //加
    13.     public float add(float a,float b) throws RemoteException;
    14.     //减
    15.     public float minus(float a,float b) throws RemoteException;
    16.     //除
    17.     public float div(float a,float b) throws RemoteException;
    18.     //乘
    19.     public float mul(float a,float b) throws RemoteException;  
    20. }
    *****************************************************************************

    1. package net.csdn.blog.qb2049_xg;
    2. import java.rmi.AccessException;
    3. import java.rmi.AlreadyBoundException;
    4. import java.rmi.RemoteException;
    5. import java.rmi.registry.LocateRegistry;
    6. import java.rmi.registry.Registry;
    7. /**
    8.  * AllCalculateServer.java
    9.  * @author Ulysses Ma
    10.  * @date 2008-9-9
    11.  */
    12. public class AllCalculateServer {
    13.     public static void main(String[] args) {
    14.        try{
    15.             //实现要导出的远程对象,它来完成运算(创建远程对象实例)
    16.             AllCalculateImpl allCalculate=new AllCalculateImpl();
    17.             //获得本地的(RMI,要求是在rmiregistry启动情况下)注册表
    18.             Registry rg=LocateRegistry.getRegistry();
    19.             //实现对象的绑定,完成远程对象的注册工作
    20.             rg.bind("allCalculate1", allCalculate);
    21.             //状态提示
    22.             System.out.println("实现所有方法的服务现在已成功启动!");
    23.        }catch(NullPointerException ne){
    24.            System.out.println("服务端出现了异常,可能是bind方法中name或是对象为空。/n"+ne.getMessage());
    25.        }catch(AlreadyBoundException abe){
    26.            System.out.println("服务端出现了异常,可能是bind名字已被占用。/n"+abe.getMessage());
    27.        }catch(AccessException ae){
    28.            System.out.println("服务端出现了异常,可能是访问被拒绝。/n"+ae.getMessage());
    29.        }catch(RemoteException re){
    30.         System.out.println("服务端出现了异常,可能是连接通信出现了问题。/n"+re.getMessage());
    31.        }        
    32.     }
    33. }
    ************************************************************************************

    1. package net.csdn.blog.qb2049_xg;
    2. import java.awt.BorderLayout;
    3. import java.awt.Color;
    4. import java.awt.Container;
    5. import java.awt.GridBagConstraints;
    6. import java.awt.GridBagLayout;
    7. import java.awt.event.ActionEvent;
    8. import java.awt.event.ActionListener;
    9. import java.rmi.NotBoundException;
    10. import java.rmi.RemoteException;
    11. import java.rmi.registry.LocateRegistry;
    12. import java.rmi.registry.Registry;
    13. import javax.swing.JButton;
    14. import javax.swing.JFrame;
    15. import javax.swing.JLabel;
    16. import javax.swing.JMenu;
    17. import javax.swing.JMenuBar;
    18. import javax.swing.JMenuItem;
    19. import javax.swing.JOptionPane;
    20. import javax.swing.JPanel;
    21. import javax.swing.JScrollPane;
    22. import javax.swing.JTextArea;
    23. import javax.swing.JTextField;
    24. import javax.swing.border.LineBorder;
    25. import net.csdn.blog.qb2049_xg.tools.JTextHelp;
    26. import net.csdn.blog.qb2049_xg.tools.MidScr;
    27. /**
    28.  * MyRMIGui.java
    29.  * @author Ulysses Ma
    30.  *
    31.  */
    32. public class MyRMIGui extends JFrame implements ActionListener
    33. {
    34.     //序列化标识使用
    35.     private static final long serialVersionUID = 2049L;
    36.     //窗体布局面板的定义
    37.     private JPanel title_p=new JPanel();
    38.     private JPanel body_p=new JPanel();
    39.     private JPanel bottom_p=new JPanel();
    40.     private JTextField addA_t,addB_t,minusA_t,minusB_t,divA_t,divB_t,mulA_t,mulB_t;
    41.     private JTextField addResult_t,addServer_t,minusResult_t,minusServer_t,divResult_t,
    42.               divServer_t,mulResult_t,mulServer_t,serviceAdd_t,serviceMinus_t,serviceMul_t,serviceDiv_t;
    43.     //分
    44.     private ServiceListFrame listFrame;
    45.     //一些关键性部件声明
    46.     private JLabel title_l=new JLabel("<html><font color=red size=6>RMI 加、减、乘、除实验</font></html>");
    47.     private JLabel exception_l=new JLabel("异常处理:");
    48.     private JTextArea exception_ta=new JTextArea(10,70);
    49.     //构造函数
    50.     public MyRMIGui() 
    51.     {
    52.       //标题部分显示的设置
    53.       title_p.setAlignmentX(JPanel.CENTER_ALIGNMENT);
    54.       title_p.add(title_l);
    55.       
    56.       //主体部分的设置      
    57.       GridBagLayout gbl1=new GridBagLayout();
    58.       body_p.setLayout(gbl1);
    59.       GridBagConstraints c1 = new GridBagConstraints();
    60.       
    61.       //表题说明
    62.       JLabel numberA,numberB,result,equal,operate,server,start,service;
    63.       numberA=new JLabel("数A");
    64.       numberA.setHorizontalAlignment(JLabel.CENTER);
    65.       numberB=new JLabel("数B");
    66.       numberB.setHorizontalAlignment(JLabel.CENTER);
    67.       result=new JLabel("结果");
    68.       result.setHorizontalAlignment(JLabel.CENTER);
    69.       equal=new JLabel("等号");
    70.       equal.setHorizontalAlignment(JLabel.CENTER);
    71.       operate=new JLabel("操作符");
    72.       operate.setHorizontalAlignment(JLabel.CENTER);
    73.       server=new JLabel("服务器");
    74.       server.setHorizontalAlignment(JLabel.CENTER);
    75.       service=new JLabel("服务名称");
    76.       service.setHorizontalAlignment(JLabel.CENTER);
    77.       start=new JLabel("开始");
    78.       start.setHorizontalAlignment(JLabel.CENTER);
    79.       c1.fill=GridBagConstraints.VERTICAL;
    80.       c1.gridx=0;
    81.       c1.gridy=0;
    82.       body_p.add(numberA,c1);
    83.       c1.gridx=1;
    84.       body_p.add(operate,c1);
    85.       c1.gridx=2;
    86.       body_p.add(numberB,c1);
    87.       c1.gridx=3;
    88.       body_p.add(equal,c1);
    89.       c1.gridx=4;
    90.       body_p.add(result,c1);
    91.       c1.gridx=5;
    92.       body_p.add(server,c1);
    93.       c1.gridx=6;
    94.       body_p.add(service,c1);
    95.       c1.gridx=7;
    96.       body_p.add(start,c1);
    97.       
    98.      //加运算UI
    99.       addA_t=new JTextField(10);
    100.       addB_t=new JTextField(10);
    101.       new JTextHelp(addA_t,JTextHelp.NUMBER).insertCheck();
    102.       new JTextHelp(addB_t,JTextHelp.NUMBER).insertCheck();
    103.       addResult_t=new JTextField(10);
    104.       serviceAdd_t=new JTextField(10);
    105.       addServer_t=new JTextField(15);
    106.       JButton addStart_b=new JButton("开始计算");
    107.       addStart_b.addActionListener(this);
    108.       addStart_b.setActionCommand("add");
    109.       JLabel add_l=new JLabel("+");
    110.       add_l.setHorizontalAlignment(JLabel.CENTER);
    111.       JLabel addEqual_l=new JLabel("=");
    112.       addEqual_l.setHorizontalAlignment(JLabel.CENTER);
    113.       c1.gridx=0;
    114.       c1.gridy=1;
    115.       body_p.add(addA_t,c1);
    116.       c1.gridx=1;
    117.       body_p.add(add_l,c1);
    118.       c1.gridx=2;
    119.       body_p.add(addB_t,c1);
    120.       c1.gridx=3;
    121.       body_p.add(addEqual_l,c1);
    122.       c1.gridx=4;
    123.       body_p.add(addResult_t,c1);
    124.       c1.gridx=5;
    125.       body_p.add(addServer_t,c1);
    126.       c1.gridx=6;
    127.       body_p.add(serviceAdd_t,c1);
    128.       c1.gridx=7;
    129.       body_p.add(addStart_b,c1);
    130.       
    131.       //减运算UI
    132.       minusA_t=new JTextField(10);
    133.       minusB_t=new JTextField(10);
    134.       new JTextHelp(minusA_t,JTextHelp.NUMBER).insertCheck();
    135.       new JTextHelp(minusB_t,JTextHelp.NUMBER).insertCheck();
    136.       minusResult_t=new JTextField(10);
    137.       minusServer_t=new JTextField(15);
    138.       serviceMinus_t=new JTextField(10);
    139.       JButton minusStart_b=new JButton("开始计算");
    140.       minusStart_b.addActionListener(this);
    141.       minusStart_b.setActionCommand("minus");
    142.       JLabel minus_l=new JLabel("-");
    143.       minus_l.setHorizontalAlignment(JLabel.CENTER);
    144.       JLabel minusEqual_l=new JLabel("=");
    145.       minusEqual_l.setHorizontalAlignment(JLabel.CENTER);
    146.       c1.gridx=0;
    147.       c1.gridy=2;
    148.       body_p.add(minusA_t,c1);
    149.       c1.gridx=1;
    150.       body_p.add(minus_l,c1);
    151.       c1.gridx=2;
    152.       body_p.add(minusB_t,c1);
    153.       c1.gridx=3;
    154.       body_p.add(minusEqual_l,c1);
    155.       c1.gridx=4;
    156.       body_p.add(minusResult_t,c1);
    157.       c1.gridx=5;
    158.       body_p.add(minusServer_t,c1);
    159.       c1.gridx=6;
    160.       body_p.add(serviceMinus_t,c1);
    161.       c1.gridx=7;
    162.       body_p.add(minusStart_b,c1);
    163.       
    164.       //除运算UI
    165.       divA_t=new JTextField(10);
    166.       divB_t=new JTextField(10);
    167.       new JTextHelp(divA_t,JTextHelp.NUMBER).insertCheck();
    168.       new JTextHelp(divB_t,JTextHelp.NUMBER).insertCheck();
    169.       divResult_t=new JTextField(10);
    170.       divServer_t=new JTextField(15);
    171.       serviceDiv_t=new JTextField(10);
    172.       JButton divStart_b=new JButton("开始计算");
    173.       divStart_b.setActionCommand("div");
    174.       divStart_b.addActionListener(this);
    175.       JLabel div_l=new JLabel("÷");
    176.       div_l.setHorizontalAlignment(JLabel.CENTER);
    177.       JLabel divEqual_l=new JLabel("=");
    178.       divEqual_l.setHorizontalAlignment(JLabel.CENTER);
    179.       c1.gridx=0;
    180.       c1.gridy=3;
    181.       body_p.add(divA_t,c1);
    182.       c1.gridx=1;
    183.       body_p.add(div_l,c1);
    184.       c1.gridx=2;
    185.       body_p.add(divB_t,c1);
    186.       c1.gridx=3;
    187.       body_p.add(divEqual_l,c1);
    188.       c1.gridx=4;
    189.       body_p.add(divResult_t,c1);
    190.       c1.gridx=5;
    191.       body_p.add(divServer_t,c1);
    192.       c1.gridx=6;
    193.       body_p.add(serviceDiv_t,c1);
    194.       c1.gridx=7;
    195.       body_p.add(divStart_b,c1);
    196.       
    197.      //乘运算UI
    198.       mulA_t=new JTextField(10);
    199.       mulB_t=new JTextField(10);
    200.       new JTextHelp(mulA_t,JTextHelp.NUMBER).insertCheck();
    201.       new JTextHelp(mulB_t,JTextHelp.NUMBER).insertCheck();
    202.       mulResult_t=new JTextField(10);
    203.       mulServer_t=new JTextField(15);
    204.       serviceMul_t=new JTextField(10);
    205.       JButton mulStart_b=new JButton("开始计算");
    206.       mulStart_b.addActionListener(this);
    207.       mulStart_b.setActionCommand("mul");
    208.       JLabel mul_l=new JLabel("×");
    209.       mul_l.setHorizontalAlignment(JLabel.CENTER);
    210.       JLabel mulEqual_l=new JLabel("=");
    211.       mulEqual_l.setHorizontalAlignment(JLabel.CENTER);
    212.       c1.gridx=0;
    213.       c1.gridy=4;
    214.       body_p.add(mulA_t,c1);
    215.       c1.gridx=1;
    216.       body_p.add(mul_l,c1);
    217.       c1.gridx=2;
    218.       body_p.add(mulB_t,c1);
    219.       c1.gridx=3;
    220.       body_p.add(mulEqual_l,c1);
    221.       c1.gridx=4;
    222.       body_p.add(mulResult_t,c1);
    223.       c1.gridx=5;
    224.       body_p.add(mulServer_t,c1);
    225.       c1.gridx=6;
    226.       body_p.add(serviceMul_t,c1);
    227.       c1.gridx=7;
    228.       body_p.add(mulStart_b,c1);
    229.       
    230.       //状态初始化
    231.       addResult_t.setEditable(false);
    232.       minusResult_t.setEditable(false);
    233.       mulResult_t.setEditable(false);
    234.       divResult_t.setEditable(false);
    235.       
    236.       //异常问题的处理
    237.       GridBagLayout gbl=new GridBagLayout();
    238.       bottom_p.setLayout(gbl);
    239.       GridBagConstraints c = new GridBagConstraints();
    240.       c.fill=GridBagConstraints.NONE;
    241.       c.gridx=0;
    242.       c.gridy=0;
    243.       bottom_p.add(exception_l,c);
    244.       c.gridx=5;
    245.       JButton clear_b=new JButton("清空");
    246.       clear_b.addActionListener(this);  
    247.       clear_b.setActionCommand("clear");
    248.       bottom_p.add(clear_b,c);
    249.       
    250.       exception_ta.setBorder(new LineBorder(new Color(0,0,0)));
    251.       exception_ta.setLineWrap(true);
    252.       JScrollPane scrollPane=new JScrollPane(exception_ta);
    253.       c.fill=GridBagConstraints.HORIZONTAL;
    254.       c.gridx=0;
    255.       c.gridy=1;
    256.       c.gridwidth=6;
    257.       bottom_p.add(scrollPane,c);   
    258.       
    259.       //设置菜单栏
    260.       JMenuBar jmb=new JMenuBar();
    261.       JMenu help_m=new JMenu("帮助");
    262.       JMenuItem listService=new JMenuItem("浏览已注册的服务");
    263.       listService.addActionListener(this);
    264.       listService.setActionCommand("list");
    265.       JMenuItem exit=new JMenuItem("退出");
    266.       exit.addActionListener(this);
    267.       exit.setActionCommand("exit");
    268.       help_m.add(listService);
    269.       help_m.add(exit);
    270.       jmb.add(help_m);
    271.       
    272.       //加载面板
    273.       this.setJMenuBar(jmb);
    274.       Container rp=this.getContentPane();      
    275.       rp.add(title_p,BorderLayout.NORTH);
    276.       rp.add(body_p,BorderLayout.CENTER);
    277.       rp.add(bottom_p,BorderLayout.SOUTH);
    278.       
    279.       
    280.       
    281.       //设置窗体展示宽度
    282.       this.setSize(800,450);
    283.       //设置显示位置
    284.       MidScr ms=new MidScr(this);
    285.       this.setLocation(ms.getX(),ms.getY());
    286.       //设置标题
    287.       this.setTitle("测试Java RMI的使用问题");
    288.       //关闭点击后的处理
    289.       this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    290.       this.setVisible(true);      
    291.       this.validate();
    292.     }
    293.    //事件的处理
    294.     public void actionPerformed(ActionEvent e)
    295.     {
    296.         //add,minus,div,mul   commands
    297.         
    298.         exception_ta.setForeground(new Color(255,0,0));
    299.         //加事件的处理
    300.         if(e.getActionCommand().equals("add"))
    301.         {
    302.             String arg1=addA_t.getText().trim();
    303.             String arg2=addB_t.getText().trim();
    304.             String host=addServer_t.getText().trim();
    305.             String service=serviceAdd_t.getText().trim();
    306.             if(arg1.equals("")&&arg2.equals(""))
    307.             {
    308.                 JOptionPane.showMessageDialog(this,"参与计算的两个数字不能为空,请检查你的输入,谢谢!",
    309.                                    "远程调用",JOptionPane.INFORMATION_MESSAGE);
    310.                 return ;
    311.             }   
    312.             new Thread(new LoadRMI(host,arg1,arg2,service,e.getActionCommand())).start();
    313.         }
    314.         //减事件的处理
    315.         if(e.getActionCommand().equals("minus"))
    316.         {
    317.             String arg1=minusA_t.getText().trim();
    318.             String arg2=minusB_t.getText().trim();
    319.             String host=minusServer_t.getText().trim();
    320.             String service=serviceMinus_t.getText().trim();
    321.             if(arg1.equals("")&&arg2.equals(""))
    322.             {
    323.                 JOptionPane.showMessageDialog(this,"参与计算的两个数字不能为空,请检查你的输入,谢谢!",
    324.                                    "远程调用",JOptionPane.INFORMATION_MESSAGE);
    325.                 return ;
    326.             }   
    327.             new Thread(new LoadRMI(host,arg1,arg2,service,e.getActionCommand())).start();
    328.         }
    329.         //乘事件的处理
    330.         if(e.getActionCommand().equals("mul"))
    331.         {
    332.             String arg1=mulA_t.getText().trim();
    333.             String arg2=mulB_t.getText().trim();
    334.             String host=mulServer_t.getText().trim();
    335.             String service=serviceMul_t.getText().trim();
    336.             if(arg1.equals("")&&arg2.equals(""))
    337.             {
    338.                 JOptionPane.showMessageDialog(this,"参与计算的两个数字不能为空,请检查你的输入,谢谢!",
    339.                                    "远程调用",JOptionPane.INFORMATION_MESSAGE);
    340.                 return ;
    341.             }   
    342.             new Thread(new LoadRMI(host,arg1,arg2,service,e.getActionCommand())).start();   
    343.         }
    344.         //除事件的处理
    345.         if(e.getActionCommand().equals("div"))
    346.         {
    347.             String arg1=divA_t.getText().trim();
    348.             String arg2=divB_t.getText().trim();
    349.             String host=divServer_t.getText().trim();
    350.             String service=serviceDiv_t.getText().trim();
    351.             if(arg1.equals("")&&arg2.equals(""))
    352.             {
    353.                 JOptionPane.showMessageDialog(this,"参与计算的两个数字不能为空,请检查你的输入,谢谢!",
    354.                                    "远程调用",JOptionPane.INFORMATION_MESSAGE);
    355.                 return ;
    356.             }   
    357.             new Thread(new LoadRMI(host,arg1,arg2,service,e.getActionCommand())).start();
    358.         }
    359.         //清理文本框按钮事件
    360.         if(e.getActionCommand().equals("clear")){
    361.             exception_ta.setText("");
    362.         }
    363.         //退出菜单事件处理
    364.         if(e.getActionCommand().equals("exit")){
    365.             System.exit(HIDE_ON_CLOSE);
    366.         }
    367.         //查看注册服务菜单事件
    368.         if(e.getActionCommand().equals("list")){
    369.             if(listFrame==null)
    370.                listFrame=new ServiceListFrame();
    371.             else
    372.                 listFrame.setVisible(true);
    373.         }
    374.         
    375.     }   
    376.     //完成各种方法调用,在这里使用了多线程的方法,可以多个任务同时的进行,不会有等待的感觉
    377.     class LoadRMI implements Runnable
    378.     {
    379.         String host,arg1,arg2,service;
    380.         String actionCommand;
    381.         public LoadRMI(String host,String arg1,String arg2,String service,String actionCommand){
    382.             this.arg1=arg1;
    383.             this.arg2=arg2;
    384.             this.host=host;
    385.             this.service=service;
    386.             this.actionCommand=actionCommand;           
    387.         }
    388.         public void run(){
    389.             try{
    390.                 //如果host的值是null的话,那么系统就默认调用本地远程方法 
    391.                 Registry rg=LocateRegistry.getRegistry(host);
    392.                 AllCalculate ac=(AllCalculate)rg.lookup(service);
    393.                 float a=Float.valueOf(arg1).floatValue();
    394.                 float b=Float.valueOf(arg2).floatValue();
    395.                 //根据事件名称调用方法
    396.                 if(this.actionCommand.equals("add")){
    397.                     addResult_t.setText(String.valueOf(ac.add(a, b)));
    398.                 }
    399.                 if(this.actionCommand.equals("minus")){
    400.                     minusResult_t.setText(String.valueOf(ac.minus(a, b)));
    401.                 }
    402.                 if(this.actionCommand.equals("mul")){
    403.                     mulResult_t.setText(String.valueOf(ac.mul(a, b)));
    404.                 }
    405.                 if(this.actionCommand.equals("div")){
    406.                     divResult_t.setText(String.valueOf(ac.div(a, b)));
    407.                 }
    408.             }catch(NullPointerException npe){
    409.                 exception_ta.append("调用的服务名称为空"+npe.getMessage()+"/n");
    410.             }catch(NotBoundException nbe){
    411.                 exception_ta.append("调用的服务不存在,请检查你的输入"+nbe.getMessage()+"/n");
    412.             }   
    413.             catch(RemoteException re){
    414.                 exception_ta.append("调用远程方法时出现了问题,情况可能是:"+re.getMessage()+"/n");
    415.             }
    416.         }
    417.     }
    418. }

    如果你对这个小例子感兴趣的话,请你到CSDN资源中心下载!

    <script type="text/JavaScript"> alimama_pid="mm_11642003_1480608_3725409"; alimama_titlecolor="0000FF"; alimama_descolor ="000000"; alimama_bgcolor="FFFFFF"; alimama_bordercolor="E6E6E6"; alimama_linkcolor="008000"; alimama_bottomcolor="FFFFFF"; alimama_anglesize="0"; alimama_bgpic="0"; alimama_icon="0"; alimama_sizecode="11"; alimama_width=760; alimama_height=90; alimama_type=2; </script> <script src="http://a.alimama.cn/inf.js" type="text/javascript"> </script>
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值