Spring + Hessian 实现轻量级分布式远程调用【包含rmi方式重构】

最近一期的《programmer》里几乎从头至尾在讲关于“J2EE without EJB”的事情,可怜的ejb啊,居然被描述成了遗产系统的重要组成部分。。。

其实有上面的结论,无外乎现在java里面的新技术已经几乎能完全取代ejb的优点,而克服ejb的缺点,entity bean和有状态的session bean已经机乎被视为垃圾,hibernate和spring大行其到,看看最进n期《programmer》中篇幅的比重就知道了。本来我个人的感觉是hibernate取代了entity bean,spring取代了session bean,但是ejb的远程调用用hibernate和spring的架构还取代不了,可是在最近的一期《programmer》中我发现了Hessian!更爽的是,发现了spring原来可以和Hessian结合使用!看来真的可以say byebye to ejb了。

看到这么振奋人心的消息,怎么能不亲自试验一下呢,于是上http://www.caucho.com/以迅雷不及掩耳盗铃之势下载了Hessian的src jar和bin jar。create一个工程,把这些相关的jar统统扔进去,配置和coding就可以开始了。首先,开了如下几个包:



whao.test.hessian.server
放远程服务的接口

whao.test.hessian.server.impl
放远程服务的实现类

whao.test.hessian.client
放客户端应用



1. whao.test.hessian.server中写一个MyService接口:
Java代码 复制代码  收藏代码
  1. /*  
  2.  
  3.  * Created on 2005-7-25  
  4.  
  5.  *  
  6.  
  7.  */  
  8.   
  9. package whao.test.hessian.server;   
  10.   
  11.     
  12.   
  13. /**  
  14.  
  15.  * @author Hao Wei  
  16.  
  17.  *  
  18.  
  19.  */  
  20.   
  21. public interface MyService {   
  22.   
  23.     public String doSomething(String s);;   
  24.   
  25. }  
/*

 * Created on 2005-7-25

 *

 */

package whao.test.hessian.server;

 

/**

 * @author Hao Wei

 *

 */

public interface MyService {

    public String doSomething(String s);;

}



2. whao.test.hessian.server.impl中写一个实现类

Java代码 复制代码  收藏代码
  1. /*  
  2.  
  3.  * Created on 2005-7-25  
  4.  
  5.  *  
  6.  
  7.  */  
  8.   
  9. package whao.test.hessian.server.impl;   
  10.   
  11.     
  12.   
  13. import whao.test.hessian.server.MyService;   
  14.   
  15.     
  16.   
  17. /**  
  18.  
  19.  * @author Hao Wei  
  20.  
  21.  *  
  22.  
  23.  */  
  24.   
  25. public class MyServiceImpl implements MyService {   
  26.   
  27.     
  28.   
  29.     /* (non-Javadoc);  
  30.  
  31.      * @see whao.test.hessian.server.MyService#doSomething(java.lang.String);  
  32.  
  33.      */  
  34.   
  35.     public String doSomething(String s); {   
  36.   
  37.         return "HAHAHA: " + s;   
  38.   
  39.     }   
  40.   
  41. }   
  42.   
  43.    
/*

 * Created on 2005-7-25

 *

 */

package whao.test.hessian.server.impl;

 

import whao.test.hessian.server.MyService;

 

/**

 * @author Hao Wei

 *

 */

public class MyServiceImpl implements MyService {

 

    /* (non-Javadoc);

     * @see whao.test.hessian.server.MyService#doSomething(java.lang.String);

     */

    public String doSomething(String s); {

        return "HAHAHA: " + s;

    }

}

 


3. 配置远程服务

         Hessian的远程服务要配置成servlet,配置如下:
Java代码 复制代码  收藏代码
  1. <servlet>   
  2.   
  3.    <servlet-name>myservice</servlet-name>   
  4.   
  5.    <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>   
  6.   
  7.    <load-on-startup>1</load-on-startup>   
  8.   
  9.    <init-param>   
  10.   
  11.        <param-name>service-class</param-name>   
  12.   
  13.        <param-value>whao.test.hessian.server.impl.MyServiceImpl</param-value>   
  14.   
  15.    </init-param>   
  16.   
  17. </servlet>   
  18.   
  19. <servlet-mapping>   
  20.   
  21.    <servlet-name>myservice</servlet-name>   
  22.   
  23.    <url-pattern>/myservice</url-pattern>   
  24.   
  25. </servlet-mapping>   
    <servlet>

       <servlet-name>myservice</servlet-name>

       <servlet-class>com.caucho.hessian.server.HessianServlet</servlet-class>

       <load-on-startup>1</load-on-startup>

       <init-param>

           <param-name>service-class</param-name>

           <param-value>whao.test.hessian.server.impl.MyServiceImpl</param-value>

       </init-param>

    </servlet>

    <servlet-mapping>

       <servlet-name>myservice</servlet-name>

       <url-pattern>/myservice</url-pattern>

    </servlet-mapping>

 


这样,当启动了这个web应用,这个远程服务就以url http://localhost:8080/test_web/myservice 的形式发布了。然后就是开发客户端来调用这个远程服务。

Java代码 复制代码  收藏代码
  1. /*  
  2.  
  3.  * Created on 2005-7-25  
  4.  
  5.  *  
  6.  
  7.  */  
  8.   
  9. package whao.test.hessian.client;   
  10.   
  11.     
  12.   
  13. import whao.test.hessian.server.MyService;   
  14.   
  15.     
  16.   
  17. import com.caucho.hessian.client.HessianProxyFactory;   
  18.   
  19.     
  20.   
  21. /**  
  22.  
  23.  * @author Hao Wei  
  24.  
  25.  *    
  26.  
  27.  */  
  28.   
  29. public class TestMain {   
  30.   
  31.     public static void main(String[] args); throws Exception {   
  32.   
  33.         HessianProxyFactory proxyFactory = new HessianProxyFactory();;   
  34.   
  35.         MyService service = (MyService); proxyFactory.create(MyService.class,   
  36.   
  37.                 "http://localhost:8080/test_web/myservice");;   
  38.   
  39.         System.out.println(service.doSomething("xixixixi"););;   
  40.   
  41.         System.out.println("ok!");;   
  42.   
  43.     }   
  44.   
  45. }   
  46.   
  47.    
/*

 * Created on 2005-7-25

 *

 */

package whao.test.hessian.client;

 

import whao.test.hessian.server.MyService;

 

import com.caucho.hessian.client.HessianProxyFactory;

 

/**

 * @author Hao Wei

 *  

 */

public class TestMain {

    public static void main(String[] args); throws Exception {

        HessianProxyFactory proxyFactory = new HessianProxyFactory();;

        MyService service = (MyService); proxyFactory.create(MyService.class,

                "http://localhost:8080/test_web/myservice");;

        System.out.println(service.doSomething("xixixixi"););;

        System.out.println("ok!");;

    }

}

 


运行一把,显示

HAHAHA:xixixi

ok!

不错不错,纯Hessian的远程调用就这样搞定了。继续研究《programmer》看到上面介绍用spring的远程访问解决方案来访问ejb的远程服务。什么?spring还有远程解决方案?没听说过嘛,看了《programmer》上的介绍,发现是真的。那么既然spring能访问ejb的远程服务,那么能访问Hessian的远程服务么?打开spring.jar看看,居然发现了名曰org.springframework.remoting.caucho.HessianProxyFactoryBean的类!夏昕真不厚道啊,再他的spring中文教程中居然匿掉了spring里这么好的东西!于是打开sping英文版reference,终于找到了用spring配置Hessian客户端的方法:
Java代码 复制代码  收藏代码
  1. <bean id="myService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">   
  2.   
  3.    <property name="serviceUrl">   
  4.   
  5.        <value>   
  6.   
  7.        http://localhost:8080/test_web/myservice   
  8.   
  9.        </value>   
  10.   
  11.    </property>   
  12.   
  13.    <property name="serviceInterface">   
  14.   
  15.        <value>whao.test.hessian.server.MyService</value>   
  16.   
  17.    </property>   
  18.   
  19. </bean>   
    <bean id="myService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">

       <property name="serviceUrl">

           <value>

           http://localhost:8080/test_web/myservice

           </value>

       </property>

       <property name="serviceInterface">

           <value>whao.test.hessian.server.MyService</value>

       </property>

    </bean>

 

然后客户端就可以这么玩啦:

Java代码 复制代码  收藏代码
  1. /*  
  2.  
  3.  * Created on 2005-7-25  
  4.  
  5.  *  
  6.  
  7.  */  
  8.   
  9. package whao.test.hessian.client;   
  10.   
  11.     
  12.   
  13. import whao.test.hessian.server.MyService;   
  14.   
  15. import whao.util.spirng.SpringBeanFactory;   
  16.   
  17.     
  18.   
  19. import com.caucho.hessian.client.HessianProxyFactory;   
  20.   
  21.     
  22.   
  23. /**  
  24.  
  25.  * @author Hao Wei  
  26.  
  27.  *    
  28.  
  29.  */  
  30.   
  31. public class TestMain {   
  32.   
  33.     
  34.   
  35.     public static void main(String[] args); throws Exception {   
  36.   
  37.         testWithSpring();;   
  38.   
  39.     }   
  40.   
  41.     public static void testWithSpring();{   
  42.   
  43.         MyService service = (MyService);SpringBeanFactory.getBean("myService");;   
  44.   
  45.         System.out.println(service.doSomething("lllllllll"););;   
  46.   
  47.         System.out.println("ok!");;   
  48.   
  49.     }   
  50.   
  51.     public static void testWithoutSpring(); throws Exception {   
  52.   
  53.         HessianProxyFactory proxyFactory = new HessianProxyFactory();;   
  54.   
  55.         MyService service = (MyService); proxyFactory.create(MyService.class,   
  56.   
  57.                 "http://localhost:8080/test_web/myservice");;   
  58.   
  59.         System.out.println(service.doSomething("xixixixi"););;   
  60.   
  61.         System.out.println("ok!");;   
  62.   
  63.     }   
  64.   
  65. }   
  66.   
  67.    
/*

 * Created on 2005-7-25

 *

 */

package whao.test.hessian.client;

 

import whao.test.hessian.server.MyService;

import whao.util.spirng.SpringBeanFactory;

 

import com.caucho.hessian.client.HessianProxyFactory;

 

/**

 * @author Hao Wei

 *  

 */

public class TestMain {

 

    public static void main(String[] args); throws Exception {

        testWithSpring();;

    }

    public static void testWithSpring();{

        MyService service = (MyService);SpringBeanFactory.getBean("myService");;

        System.out.println(service.doSomething("lllllllll"););;

        System.out.println("ok!");;

    }

    public static void testWithoutSpring(); throws Exception {

        HessianProxyFactory proxyFactory = new HessianProxyFactory();;

        MyService service = (MyService); proxyFactory.create(MyService.class,

                "http://localhost:8080/test_web/myservice");;

        System.out.println(service.doSomething("xixixixi"););;

        System.out.println("ok!");;

    }

}

 


执行一下,输出是:

HAHAHA:lllllllll

ok!

spring真是个好东东,呵呵,其中的SpringBeanFactory是这样实现的:
Java代码 复制代码  收藏代码
  1.   
  2. /*  
  3.  
  4.  * Created on 2005-7-25  
  5.  
  6.  *  
  7.  
  8.  */  
  9.   
  10. package whao.util.spirng;   
  11.   
  12.     
  13.   
  14. import javax.servlet.ServletContext;   
  15.   
  16.     
  17.   
  18. import org.apache.commons.logging.Log;   
  19.   
  20. import org.apache.commons.logging.LogFactory;   
  21.   
  22. import org.springframework.context.ApplicationContext;   
  23.   
  24. import org.springframework.context.support.FileSystemXmlApplicationContext;   
  25.   
  26. import org.springframework.web.context.support.WebApplicationContextUtils;   
  27.   
  28.     
  29.   
  30. /**  
  31.  
  32.  * @author Hao Wei  
  33.  
  34.  *  
  35.  
  36.  */  
  37.   
  38. public class SpringBeanFactory {   
  39.   
  40.     private static final Log log = LogFactory.getLog(SpringBeanFactory.class);;   
  41.   
  42.          private static ApplicationContext ctx = null;   
  43.   
  44.     
  45.   
  46.     public static Object getBean(ServletContext context, String beanID); {   
  47.   
  48.         log.info("beanID=" + beanID);;   
  49.   
  50.         ApplicationContext ac = WebApplicationContextUtils   
  51.   
  52.                 .getWebApplicationContext(context);;   
  53.   
  54.         return ac.getBean(beanID);;   
  55.   
  56.     }   
  57.   
  58.        
  59.   
  60.     public static Object getBean(String beanID);{   
  61.   
  62.                    if(ctx == null);{   
  63.   
  64.                             ctx = new FileSystemXmlApplicationContext(   
  65.   
  66.                             "D:\\whao-work\\src\\test_web\\test_web\\WEB-INF\\applicationContext.xml");;   
  67.   
  68.                    }   
  69.   
  70.                    return ctx.getBean(beanID);;   
  71.   
  72.     }   
  73.   
  74. }   
  75.   
  76.    
/*

 * Created on 2005-7-25

 *

 */

package whao.util.spirng;

 

import javax.servlet.ServletContext;

 

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

import org.springframework.web.context.support.WebApplicationContextUtils;

 

/**

 * @author Hao Wei

 *

 */

public class SpringBeanFactory {

    private static final Log log = LogFactory.getLog(SpringBeanFactory.class);;

         private static ApplicationContext ctx = null;

 

    public static Object getBean(ServletContext context, String beanID); {

        log.info("beanID=" + beanID);;

        ApplicationContext ac = WebApplicationContextUtils

                .getWebApplicationContext(context);;

        return ac.getBean(beanID);;

    }

    

    public static Object getBean(String beanID);{

                   if(ctx == null);{

                            ctx = new FileSystemXmlApplicationContext(

                            "D:\\whao-work\\src\\test_web\\test_web\\WEB-INF\\applicationContext.xml");;

                   }

                   return ctx.getBean(beanID);;

    }

}

 


看到sping.jar的包org.springframework.remoting.caucho中还有另外两个类叫HessianClientInterceptor和HessianServiceExporter,看来貌似hessian服务端也可以和spring结合,还有客户端的Interceptor估计可以实现对远程服务的AOP,要继续研究一下了,待续吧
 
   发表时间:2005-07-31  
在成功的将hessian server端也和spring结合后,从整个分布式应用的架构可以看出,无论是服务端与客户端共有的业务接口,还是服务端业务实现类,以及客户端访问远程服务的应用代码里,已经没有一行关于远程操作的代码了。也就是spring让我们的分布式业务开发完全无关于远程访问协议了,这样我们就可以埋头开发服务端和客户端的业务接口、实现、应用等等,二不必关心远程调用究竟要怎么实现。很明显,这也是AOP(面向方面的编程)的一个比较完美的应用,它使远程访问接口和业务逻辑完全无耦合的分开了。设想一下,如果某天我们有需要,远程访问的接口要从rmi、jax-rpc、hessian、httpinvoker之间做切换,也只要改下配置文件就ok了,一行代码都不用改,真的非常exciting。

接着前面那篇日志,先把spring和hessian在服务端的结合帖上来:

接口,还是那个接口~;实现,还是那个实现~~;配置却不是了那个配置呀~~~

首先,servlet变成了:
Java代码 复制代码  收藏代码
  1. <servlet>   
  2.   
  3.    <servlet-name>remote</servlet-name>   
  4.   
  5.    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>   
  6.   
  7.    <load-on-startup>1</load-on-startup>   
  8.   
  9. </servlet>   
  10.   
  11. <servlet-mapping>   
  12.   
  13.    <servlet-name>remote</servlet-name>   
  14.   
  15.    <url-pattern>/remote/*</url-pattern>   
  16.   
  17. </servlet-mapping>  
    <servlet>

       <servlet-name>remote</servlet-name>

       <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

       <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

       <servlet-name>remote</servlet-name>

       <url-pattern>/remote/*</url-pattern>

    </servlet-mapping>


其次,applicationContext.xml没有必要了,但是要有个remote-servlet.xml,内容如下:

Java代码 复制代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2.   
  3. <!-- edited with XMLSPY v5 rel. 4 U (http://www.xmlspy.com); by whao (mdc); -->   
  4.   
  5. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">   
  6.   
  7. <beans>   
  8.   
  9.     <description>server properties</description>   
  10.   
  11.     <bean id="_myService_server" class="whao.test.hessian.server.impl.MyServiceImpl">   
  12.   
  13.     </bean>   
  14.   
  15.     <bean name="/myService_server" class="org.springframework.remoting.caucho.HessianServiceExporter">   
  16.   
  17.        <property name="service">   
  18.   
  19.            <ref bean="_myService_server"/>   
  20.   
  21.        </property>   
  22.   
  23.        <property name="serviceInterface">   
  24.   
  25.            <value>whao.test.hessian.server.MyService</value>   
  26.   
  27.        </property>   
  28.   
  29.     </bean>       
  30.   
  31. </beans>   
  32.   
  33.    
<?xml version="1.0" encoding="UTF-8"?>

<!-- edited with XMLSPY v5 rel. 4 U (http://www.xmlspy.com); by whao (mdc); -->

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

    <description>server properties</description>

    <bean id="_myService_server" class="whao.test.hessian.server.impl.MyServiceImpl">

    </bean>

    <bean name="/myService_server" class="org.springframework.remoting.caucho.HessianServiceExporter">

       <property name="service">

           <ref bean="_myService_server"/>

       </property>

       <property name="serviceInterface">

           <value>whao.test.hessian.server.MyService</value>

       </property>

    </bean>    

</beans>

 


这样一来这个hessian服务的发布地址就变成了 http://localhost:8080/test_web/remote/myService_server

客户端的配置改成:
Java代码 复制代码  收藏代码
  1. <bean id="myServiceClient" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">   
  2.   
  3.    <property name="serviceUrl">   
  4.   
  5.        <value>http://localhost:8080/test_web/remote/myService_server</value>   
  6.   
  7.    </property>   
  8.   
  9.    <property name="serviceInterface">   
  10.   
  11.        <value>whao.test.hessian.server.MyService</value>   
  12.   
  13.    </property>   
  14.   
  15. </bean>  
    <bean id="myServiceClient" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">

       <property name="serviceUrl">

           <value>http://localhost:8080/test_web/remote/myService_server</value>

       </property>

       <property name="serviceInterface">

           <value>whao.test.hessian.server.MyService</value>

       </property>

    </bean>



客户端的代码依然是:
Java代码 复制代码  收藏代码
  1. MyService service = (MyService);SpringBeanFactory.getBean("myServiceClient");;   
  2.   
  3. System.out.println(service.doSomething("mmmmmmmmm"););;   
        MyService service = (MyService);SpringBeanFactory.getBean("myServiceClient");;

        System.out.println(service.doSomething("mmmmmmmmm"););;

 


运行一下,输出:

HAHAHA: mmmmmmmmm

ok!



嗯,真是不错,下面尝试着不改一行代码,我们把远程协议由hessian改成rmi。

由于rmi server不用servlet,也就不用web server,所以可以由自己的进程之接启动,我们就把remote-servlet.xml改成beans.xml内容如下:

Java代码 复制代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>   
  2.   
  3. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">   
  4.   
  5. <beans>   
  6.   
  7.     <bean id="_myService_server" class="whao.test.hessian.server.impl.MyServiceImpl">   
  8.   
  9.     </bean>   
  10.   
  11.     <bean id="myService_server" class="org.springframework.remoting.rmi.RmiServiceExporter">   
  12.   
  13.        <property name="serviceName"><value>myService_server</value></property>   
  14.   
  15.        <property name="service"><ref bean="_myService_server"/></property>   
  16.   
  17.        <property name="serviceInterface"><value>whao.test.hessian.server.MyService</value></property>   
  18.   
  19.     </bean>   
  20.   
  21. </beans>   
  22.   
  23.    
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

    <bean id="_myService_server" class="whao.test.hessian.server.impl.MyServiceImpl">

    </bean>

    <bean id="myService_server" class="org.springframework.remoting.rmi.RmiServiceExporter">

       <property name="serviceName"><value>myService_server</value></property>

       <property name="service"><ref bean="_myService_server"/></property>

       <property name="serviceInterface"><value>whao.test.hessian.server.MyService</value></property>

    </bean>

</beans>

 


然后随便写个main程序启动服务,就不用启动web server了:

Java代码 复制代码  收藏代码
  1. /*  
  2.  
  3.  * Created on 2005-7-31  
  4.  
  5.  *  
  6.  
  7.  */  
  8.   
  9. package whao.test.rmi;   
  10.   
  11.     
  12.   
  13. import org.springframework.context.ApplicationContext;   
  14.   
  15. import org.springframework.context.support.FileSystemXmlApplicationContext;   
  16.   
  17.     
  18.   
  19. /**  
  20.  
  21.  * @author Hao Wei  
  22.  
  23.  *  
  24.  
  25.  */  
  26.   
  27. public class Server {   
  28.   
  29.          public static void main(String[] args); throws Exception{   
  30.   
  31.              ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\whao-work\\src\\test_web\\src_server\\beans.xml");;   
  32.   
  33.              ctx.getBean("myService_server");;   
  34.   
  35.                    System.out.println("Server started");;   
  36.   
  37.          }   
  38.   
  39. }  
/*

 * Created on 2005-7-31

 *

 */

package whao.test.rmi;

 

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.FileSystemXmlApplicationContext;

 

/**

 * @author Hao Wei

 *

 */

public class Server {

         public static void main(String[] args); throws Exception{

             ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\whao-work\\src\\test_web\\src_server\\beans.xml");;

             ctx.getBean("myService_server");;

                   System.out.println("Server started");;

         }

}



这样,我们的服务接口和实现类的代码一行不用动,而变成rmi协议的服务已经以rmi://localhost/myService_server 的url启动了。

然后在把客户端的配置略微调整一下:
Java代码 复制代码  收藏代码
  1. <bean id="myServiceClient" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">   
  2.   
  3.    <property name="serviceUrl">   
  4.   
  5.        <value>rmi://localhost/myService_server</value>   
  6.   
  7.    </property>   
  8.   
  9.    <property name="serviceInterface">   
  10.   
  11.        <value>whao.test.hessian.server.MyService</value>   
  12.   
  13.    </property>   
  14.   
  15. </bean>   
    <bean id="myServiceClient" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">

       <property name="serviceUrl">

           <value>rmi://localhost/myService_server</value>

       </property>

       <property name="serviceInterface">

           <value>whao.test.hessian.server.MyService</value>

       </property>

    </bean>

 

客户端的代码也一行不动,在执行下,输出依然是:

HAHAHA: mmmmmmmmm

ok!

然而,我们的remoting其实已经由基于http的hessian改成了rmi。果然不错啊,除了hessian,rmi之外,现在spring支持的remoting协议还包括jax-rpc,burlap,httpinvoker,也就是说我们的remoting操作协议在这些中间切换时,利用spring remoting框架,都可以不用改一行代码,已经非常强大了,只是现在还没有corba的支持。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值