>>分享流行的Java框架以及开源软件,对孙卫琴的《精通Spring》、《Spring Cloud Alibaba微服务开发零基础入门到实操》提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 31601 个阅读者 刷新本主题
 * 贴子主题:  EJB3教程 回复文章 点赞(0)  收藏  
作者:fly123    发表时间:2018-09-12 11:34:38     消息  查看  搜索  好友  邮件  复制  引用

一个实体Bean的实现

JPA和实体Bean的应用


EJB:

Enterprice JavaBeans

EJB是一个用于分布式业务应用的标准服务端组件模型。采用EJB架构编写的应用是可伸缩的、事务性的、多用户安全的。采用ejb编写的这些应用,可以部署在任何支持EJB规范的服务器平台,如jboss、weblogic等。

EJB用来干什么?

EJB实际上是用于编写业务层代码。如果大家对于MVC (model-view-controller)结构的应用有所了解的话,我们知道一个基于MVC结构的应用应包含显示层、控制层和业务层, 假设我们采用ejb开发基于MVC结构的应用,那么ejb就是用于开发应用的业务层.



EJB的好处

EJB为我们提供了很多在企业开发中需要使用到的服务,如事务管理/安全/持久化/分布式等,因为这些服务由容器提供,无需我们自行开发,这样大大减少了我们的开发工作量.另外EJB提供了强制式分层解耦设计方法

EJB3 VS Spring2.5

估计有同学会问,除了EJB,像spring+hibernate同样提供了事务管理/持久化服务,好像没有必要使用ejb.

   如果你的应用不需要分布式能力,确实没有必要使用ejb, 因为spring+hibernate提供了大部分原来只有ejb才有的服务,而且spring提供的有些服务比ejb做的更细致,更周到。

   那么是不是有了spring,EJB3就没有必要存在了?这种说法是不正确的,因为ejb设计的初衷是用于分布式场合,而spring一开始就没有打算提供分布式功能。所以两者看似有竞争的关系,但实际上两者的偏重点不一样,像ejb比较适合用于大型企业,因为大型企业一般都会存在多个信息系统,而这些信息系统又相互关联。为了避免业务功能重复开发,实现最大程度的重用,有必要把业务层独立出来,让多个信息系统共享一个业务中心,这样应用就需要具备分布式能力。

EJB3的运行环境

EJB3.0应用需要运行在EJB容器里,下面是一些JavaEE应用服务器,JavaEE应用服务器包含Web容器和EJB容器。

Jboss(4.2.x以上版本)

  是一个成熟的开源的准JavaEE应用服务器,在开源JavaEE应用服务器中所占市场份额第一。如果你打算选用开源的JavaEE应用服务器,那么jboss是最值得选择的。

Glassfish

  是一个开源的JavaEE应用服务器,对JavaEE规范的支持非常好,其运行性能比较高。因为发展时间相对较短,市场占有率比较低。另外,它能否提供稳定的运行性能,还有待时间的考验。但本人对其后期的发展非常看好。绝对跟jboss有的一拼。

Weblogic(10以上版本)

  是商业市场占有率第一的商业JavaEE应用服务器,它具有出色的稳定性,并提供了人性化的管理界面,还有企业需要使用到的众多功能。但在ejb3.0领域,本人认为它做的比jboss差些,bug比较多。

Sun Application Server(9.0以上版本)

  商业JavaEE应用服务器,如果你打算选用商业应用服务器运行ejb3,这个是不错的选择。

Oracle Application Server(10g以上版本)

  商业JavaEE应用服务器,如果你的数据库是oracle,要想兼容性更好,这个是不错的选择。

  

apusic应用服务器  这是国内的商业JavaEE应用服务器,主要在政府中占有一定的市场份额。要批评的是,其向开发人员提供的文档实在太少了

注意:Tomcat目前只是Web容器,它不能运行EJB应用。

EJB中的三种bean

1.会话bean(session bean)

   负责与客户端交互,是编写业务逻辑的地方,在会话bean中可以通过jdbc直接操作数据库,但大多数情况下都是通过实体bean来完成对数据库的操作.



2.实体bean(entity bean)

   它实际上属于java持久化规范(简称JPA)里的技术, JPA的出现主要是为了简化现有的持久化开发工作和整合ORM技术,结束现在Hibernate、TopLink等ORM框架各自为营的局面。



3.消息驱动bean(message-driven bean)

   它是专门用于异步处理java消息的组件.具有处理大量并发消息的能力.

  

什么是持久化

   在程序退出后信息可以长期保存的一种数据存储技术。

  

存储Java对象的流行方式之一是使用传统的RDBMS。

主流的关系数据库存取技术有如下四类:  

JDBC直接访问数据库

EJB entity bean

JDO技术(Java Data Objects)

第三方O/R工具,如Hibernate, 其它如IBATIS,Castor,Toplink.


实体bean

它属于java持久化规范(简称JPA)里的技术,实体bean通过元数据在javabean和数据库表之间建立起映射关系,然后Java程序员就可以随心所欲的使用面向对象的编程思想来操纵数据库。 JPA的出现主要是为了简化现有的持久化开发工作和整合ORM技术,目前实现的JPA规范的主流产品有Hibernate、TopLink和OpenJPA,在jboss中采用了Hibernate 作为其持久化实现产品。



添加JPA的配置文件persistence.xml



根据JPA规范的要求:

在实体bean应用中,我们需要在应用的类路径下的META-INF目录加入持久化配置文件persistence.xml

Xml代码  收藏代码
<?xml version="1.0"?>  
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">  
    
</persistence>  
  
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>  
<property name="hibernate.show_sql" value="true"/>  
<property name="hibernate.format_sql" value="true"/>  


实体bean只有持久化之后,才可以使用EntityManager对象访问数据库


项目使用:

Java代码  收藏代码
@PersistenceContext  
    private EntityManager em;  
      
    @Override  
    public void init() {  
          
        StringBuilder sql = new StringBuilder();  
        sql.append("SELECT DISTINCT S.SERVICE_NAME_EN, I.BOUND_IP");  
        sql.append("  FROM ESB_SERVICE      S,");  
        sql.append("       ESB_SERVICE_AUTH SA,");  
        sql.append("       ESB_APPLICATION  A,");  
        sql.append("       ESB_APP_BOUND_IP I");  
        sql.append(" WHERE S.ID = SA.SERVICE_ID");  
        sql.append("   AND SA.APPLICATION_ID = A.ID");  
        sql.append("   AND A.ID = I.APPLICATION_ID");  
        sql.append("   AND S.ENABLED_FLAG = 'Y'");  
        sql.append("   AND SA.ENABLED_FLAG = 'Y'");  
        sql.append("   AND A.ENABLED_FLAG = 'Y'");  
        sql.append("   AND I.ENABLED_FLAG = 'Y'");  
          
        Query query = em.createNativeQuery(sql.toString());  
        List<Object[]> result = query.getResultList();  
        for(Object[] oa : result){  
            logger.debug(oa[0].toString() + ":" + oa[1].toString());      
            ...  
        }  
    }  
    ...  
}  


META-INF下:

persistence.xml:

Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8"?>  
<persistence xmlns="http://java.sun.com/xml/ns/persistence"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"  
    version="1.0">  
    <persistence-unit name="init-ds">  
        <!-- 数据源:server\default\deploy\datasources\visesbdb-ds.xml 中jndi-name为datasources/visesbdb -->  
        <jta-data-source>java:/datasources/visesbdb</jta-data-source>  
    </persistence-unit>  
</persistence>  
或:

Java代码  收藏代码
<?xml version="1.0" encoding="UTF-8"?>  
<persistence xmlns="http://java.sun.com/xml/ns/persistence"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"  
    version="1.0">  
    <persistence-unit name="msgreceiver-ds">  
        <jta-data-source>java:/datasources/visesbdb</jta-data-source>  
        <jar-file>com.project.soa.lightesb.bean-2.2.0.jar</jar-file>  
        <properties>  
            <property name="hibernate.hbm2ddl.auto" value="none" />  
            <property name="hibernate.show_sql" value="false" />  
            <property name="hibernate.format_sql" value="false" />  
        </properties>  
    </persistence-unit>  
</persistence>  
  或:

Java代码  收藏代码
<persistence xmlns="http://java.sun.com/xml/ns/persistence"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"  
version="1.0">  
  
<persistence-unit name="jboss-eb" transaction-type="JTA">  
  <jta-data-source>java:/MSSQLDS</jta-data-source>  
  <class>org.tibetjungle.javaeee.beginner.ejb.eb.Book</class>  
</persistence-unit>  
  
</persistence>  




会话bean



无状态会话bean

  平常,我们使用最多的是无状态bean,因为它的bean实例可供多个用户使用,所以它的性能比有状态bean高.正因为一个bean实例被多个用户使用.那么,前一个用户设置的值有可能被后一个用户所修改,所以它无法正确保存某个用户设置的值,因此是无状态的.



有状态会话bean



有状态bean平常使用的并不多,因为它的一个bean实例只供一个用户使用,所以性能开销比较大,正因为它的实例只被一个用户使用, 用户为它设置的值是不会被其他用户修改,所以可以正确保存用户设置的值,因此是有状态的.





Session bean的客户端开发

Java代码  收藏代码
public static void main(String[] args) {  
    Properties props = new Properties();  
    props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");  
    props.setProperty("java.naming.provider.url", "localhost:1099");  
    try {  
        InitialContext ctx = new InitialContext(props);  
        HelloWorld helloworld = (HelloWorld) ctx.lookup("HelloWorldBean/remote");  
        System.out.println(helloworld.sayHello("佛山"));  
    } catch (NamingException e) {  
        System.out.println(e.getMessage());  
    }  
}  




设置JNDI访问环境信息

在进行JNDI查找前,我们必须设置应用服务器的上下文信息,主要是设置JNDI驱动的类名(java.naming.factory.initial)和命名服务提供者的URL (java.naming.provider.url) 。



java.naming.factory.initial或Context.INITIAL_CONTEXT_FACTORY:

环境属性名,用于指定InitialContext工厂(或JNDI驱动),它类似于JDBC指定数据库驱动类。

因为本例子连接的是JbossNS(命名服务的实现者),所以使用Jboss提供的驱动类:org.jnp.interfaces.NamingContextFactory



java.naming.provider.url或Context.PROVIDER_URL:

         环境属性名,包含提供命名服务的主机地址和端口号。它类似于JDBC指定数据库的连接URL。连接到JbossNS的URL格式为:jnp://host:port,该URL的“jnp:”部分是指使用的协议,JBoss使用的是基于Socket/RMI的协议。host为主机的地址,port为JNDI服务的端口。除了host之外,其他部分都是可以不写的。



下面是数据库访问例子:

Java代码  收藏代码
Class.forName("org.gjt.mm.mysql.Driver").newInstance();  
Properties props = new Properties();  
props.put("user","root");  
props.put("password","123456");  
Connection conn =  DriverManager.getConnection("jdbc:mysql://localhost:3306/itcast",  props);  


如同数据库一样,根据访问命名服务器的不同,为上下文设置的驱动类和URL也是不同的,如下面是访问Sun应用服务器的上下文信息:

Java代码  收藏代码
Properties props = new Properties();  
props.setProperty("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");  
props.setProperty("java.naming.provider.url", "localhost:3700");  
InitialContext = new InitialContext(props);  
HelloWorld helloworld = (HelloWorld) ctx.lookup("com.foshanshop.ejb3.HelloWorld");  


如果客户端运行在应用服务器内,我们不需要为InitialContext设置应用服务器的上下文信息,也不建议设置。

因为应用服务器启动时会把JNDI驱动类等上下文信息添加进系统属性,创建InitialContext对象时如果没有指定Properties参数,InitialContext内部会调用System.getProperty()方法从系统属性里获取必要的上下文信息。对本例子而言,你可以省略传入props参数,之所以给InitialContext设置参数,目的是引出相关知识点,便于教学。在实际应用中,如果给InitialContext设置了参数,反而会带来不可移植的问题。



注:创建InitialContext对象时如果没有指定Properties参数,InitialContext还会在classpath下寻找jndi.properties文件,并从该文件中加载应用服务器的上下文信息。这样避免了硬编码为InitialContext设置Properties参数。



jndi.properties的配置如下:

java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory

java.naming.provider.url=localhost:1099

java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces







Jboss默认生成的JNDI 名称

当EJB发布到Jboss 时,如果我们没有为它指定全局JNDI名称或修改过其默认EJB名称,Jboss就会按照默认的命名规则为EJB生成全局JNDI名称,默认的命名规则如下:



如果把EJB作为模块打包进后缀为*.ear的JAVA EE企业应用文件,默认的全局JNDI名称是

本地接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/local

远程接口:EAR-FILE-BASE-NAME/EJB-CLASS-NAME/remote

       EAR-FILE-BASE-NAME为ear文件的名称,EJB-CLASS-NAME为EJB的非限定类名。

例:把HelloWorld应用作为EJB模块打包进名为HelloWorld.ear的企业应用文件,它的远程接口的JNDI 名称是:HelloWorld/HelloWorldBean/remote



如果把EJB应用打包成后缀为*.jar的模块文件,默认的全局JNDI名称是

本地接口:EJB-CLASS-NAME/local

远程接口:EJB-CLASS-NAME/remote

例:把HelloWorld应用打包成HelloWorld.jar文件,它的远程接口的JNDI名称是:HelloWorldBean/remote


使用注释改变Session Bean的JNDI 名称



如果我们没有指定EJB的JNDI名称,当EJB发布到应用服务器时,应用服务器会按默认规则为EJB生成全局JNDI名称。当我们需要自定义JNDI名称时,可以这样做

如果EJB在Jboss中使用,可以使用Jboss提供的 @LocalBinding 和 @RemoteBinding 注释,@LocalBinding注释指定Session Bean的Local接口的JNDI名称,@RemoteBinding注释指定Session Bean的Remote接口的JNDI名称,如下:

Java代码  收藏代码
@Stateless  
@Remote ({Operation.class})  
@RemoteBinding (jndiBinding="foshanshop/RemoteOperation")  
@Local ({LocalOperation.class})  
@LocalBinding (jndiBinding="foshanshop/LocalOperation")  
public class OperationBean implements Operation, LocalOperation {  
  
}  




使用xml文件改变Session Bean的JNDI 名称

由于JNDI名称与厂商有关,如果使用注释定义JNDI名称会带来移植问题,因此建议使用ejb-jar.xml部署描述文件进行定义,该文件必须放置在jar的META-INF目录下

Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8"?>  
<ejb-jar  xmlns=http://java.sun.com/xml/ns/javaee  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee  
                          http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"  version="3.0">  
    <enterprise-beans>  
        <session>  
            <ejb-name>HelloWorldBean</ejb-name>  
            <mapped-name>HelloWorldBean</mapped-name>  
        </session>  
    </enterprise-beans>  
</ejb-jar>  


ejb-name为EJB名称,mapped-name为bean的JNDI名称。





目前jboss不支持在ejb-jar.xml通过mapped-name指定JNDI名称,但我们可以使用他专属的部署描述文件jboss.xml进行定义,如下:

Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 4.2//EN“ "http://www.jboss.org/j2ee/dtd/jboss_4_2.dtd">  
<jboss>  
    <enterprise-beans>  
        <session>  
            <ejb-name>HelloWorldBean</ejb-name>  
            <jndi-name>hello/remote</jndi-name>  
        </session>  
    </enterprise-beans>  
</jboss>  


项目中使用:

Java代码  收藏代码
public interface ControlService {  
  
    void init();      
}  
  
@Stateless (name = "ControlService")  
@Local ({ControlService.class})  
public class ControlServiceImpl implements ControlService{  
      
    private static final Logger logger = LoggerFactory.getLogger(ControlServiceImpl.class);  
      
    @PersistenceContext  
    private EntityManager em;  
      
    @Override  
    public void init() {  
        ...  
    }  
    ...  
}  


META-INF下:

jboss.xml:

Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8"?>  
<jboss>  
    <enterprise-beans>  
        <session>  
            <ejb-name>ControlService</ejb-name>  
            <jndi-name>ESBDaemon/ControlService</jndi-name>  
            <local-jndi-name>ESBDaemon/ControlService/local</local-jndi-name>  
        </session>  
          
        ..  
    </enterprise-beans>  
</jboss>  


persistence.xml:

Xml代码  收藏代码
<?xml version="1.0" encoding="UTF-8"?>  
<persistence xmlns="http://java.sun.com/xml/ns/persistence"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"  
    version="1.0">  
    <persistence-unit name="init-ds">  
        <!-- 数据源:server\default\deploy\datasources\visesbdb-ds.xml 中jndi-name为datasources/visesbdb -->  
        <jta-data-source>java:/datasources/visesbdb</jta-data-source>  
    </persistence-unit>  
</persistence>  




通过远程接口调用ejb的过程:

首先客户端需要与ejb建立起socket通信,在通信管道上他们之间需要来回发送IIOP协议消息,因为数据要在网络进行传输,存放数据的java对象必须要进行序列化。

在这个过程中我们看到,有网络通信的开销、协议解析的开销、对象序列化的开销。因为ejb是分布式技术,它允许客户端与ejb应用在不同一机器上面,所以这些性能开销也是必然的。但是在实际生产中,不可避免存在这种情况:客户端与EJB应用运行在同一个jboss中。这时候客户端访问ejb是否有必要走上面的网络通信呢?据我们所知,这时候客户端与ejb是在同一个jvm内,他们之间完全可以通过内存进行交互,这样就可以避免网络通信的性能开销。既然我们都想到了这一点,EJB专家组也想到了这一点,所以引入了本地接口。



通过本地接口调用ejb,直接在内存中交互,这样就能避免因网络通信所造成的各种性能开销。但是有一点,大家必须注意,只有客户端与EJB应用在同一个JVM内运行的时候,我们才能调用本地接口,否则只能调用远程接口。

什么情况下客户端与EJB应用是在同一个JVM?简单地说只要客户端与ejb发布在同一个jboss内,我们就认为他们是在同一个JVM





开发具有local接口session bean:

Java代码  收藏代码
@Stateless  
@Local ({HelloWorldLocal.class})  
public class HelloWorldBean implements HelloWorldLocal {  
      
    public String say (String name) {          
        return name +"说:你好!世界,这是我的第一个EJB3哦.";  
    }  
}  
  
  
try {  
    InitialContext ctx = new InitialContext();  
    HelloWorldLocal helloworld = (HelloWorldLocal) ctx.lookup("HelloWorldBean/local");  
    out.println(helloworld.sayHello("佛山人"));  
} catch (NamingException e) {  
    out.println(e.getMessage());  
}  




EJB调用机制

由于EJB的调用过程对开发者来说是透明的,以至于我们错误地认为:lookup()方法返回的对象就是bean实例。实际上,客户端与Session bean交互,它并不直接与Bean实例打交道,而是经由bean的远程或本地接口。当你调用远程或本地接口的方法时,接口使用的是存根(stub)对象。该存根实现了sessionbean的远程或本地接口。它负责将方法调用经过网络发送到远程EJB容器,或将请求路由到位于本地JVM内的EJB容器。存根是在部署期间使用JDK所带的java.lang.reflect.Proxy动态生成。



第一步:客户端调用远程接口的SayHello()方法(实际上调用的是存根对象的SayHello()方法,该存根实现了HelloWorld的远程接口)。

第二步:方法调用经过IIOP Runtime被转换成CORBA IIOP消息发往应用服务器。

第三步:应用服务器接收到请求消息后,交由骨架(skeleton)处理。骨架通过IIOP Runtime解析协议消息,并根据协议要求调用bean实例的SayHello()方法。

第四步:骨架(skeleton)将SayHello()方法的返回值经过IIOP Runtime转换成CORBA IIOP应答消息发回客户端。

第五步:存根对象通过IIOP Runtime将CORBA IIOP应答消息解析成返回值。







依赖注入(dependency injection)



注入ejb:

Java代码  收藏代码
@Stateless  
@Remote (Injection.class)  
public class InjectionBean implements Injection {  
  
       @EJB (beanName="HelloBean")  
       LocalHello helloworld;  
        
       public String SayHello() {  
           return helloworld.SayHello("注入者");  
       }  
}  


或:

Java代码  收藏代码
@EJB (mappedName = "ESBDaemon/ControlService/local")  
    private ControlService cs;  
      
    public void contextInitialized(ServletContextEvent sce) {  
        cs.init();  
    }  


注入数据源:

Java代码  收藏代码
@Resource(mappedName = "java:/DefaultMySqlDS")  
DataSource myDb;  
  
Connection conn = null;  
try {  
    conn = myDb.getConnection();  
    Statement stmt = conn.createStatement();  
    ResultSet rs = stmt.executeQuery("SELECT studentName FROM student");  
    if (rs.next())  str = rs.getString(1);  rs.close();  
    stmt.close();  
} catch (SQLException e) {  
    e.printStackTrace();  
}finally{  
    try {  
        if(null!=conn && !conn.isClosed()) conn.close();  
    } catch (SQLException e) {  
        e.printStackTrace();  
    }  
}  




在jboss中配置数据源


<datasources>  
  <local-tx-datasource>  
    <jndi-name>DefaultMySqlDS</jndi-name>  
    ...  
  </local-tx-datasource>  
</datasources>  


程序猿的技术大观园:www.javathinker.net
  Java面向对象编程-->图形用户界面(上)
  JavaWeb开发-->Web运作原理(Ⅰ)
  JSP与Hibernate开发-->立即检索和延迟检索策略
  Java网络编程-->基于MVC和RMI的分布式应用
  精通Spring-->Vue指令
  Vue3开发-->通过Vuex进行状态管理
  推荐一本微服务开发经典书籍《Spring Cloud Alibaba微服务开...
  10分钟认识RocketMQ!想进阿里连这个都不会?
  一篇文章让你彻底了解什么叫Netty!
  从零开始手写 spring ioc 框架,深入学习 spring 源码
  SSM三大框架整合详细教程
  Spring MVC关于分页的简单实现
  SpringMVC Model、ModelMap和ModelAndView的区别和用法
  RESTful架构和RESTful API设计总结
  Spring Security中使用的责任链模式
  另一种缓存,Spring Boot 整合 Ehcache
  分布式消息队列RocketMQ部署与监控
  浓缩精华的架构演进过程,经验总结,值得收藏!
  一睹Web服务真面目,有商业价值的Web服务是这样的
  Spring配置日志
  MyBatis解析和运行原理
  更多...
 IPIP: 已设置保密
楼主      
该用户目前不在线 nihaota 
  
威望: 0
级别: 新手上路
魅力: 1315
经验: 1315
现金: 2944
发文章数: 243
注册时间: 0001-01-01
 消息  查看  搜索  好友  邮件  复制  引用


讨债公司
发文章时间 2022-10-28 21:38:29
 IPIP: 已设置保密 1 楼     
1页 1条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。