中间件技术——实验二:EJB调用和练习

2019-04-10  本文已影响0人  东郭_先森

一、实验内容

  1. 实验目的
    理解EJB,利用wildfly服务器容器进行远程调用。(笔者实现的是服务器端和客户端都在同一台电脑上)
  2. 实验准备操作
    a.下载安装java jdk 1.6或以上(笔者用的版本是1.8.0_201);
    b.下载安装Maven(笔者用的版本是3.6.0)
    c.熟悉IDEA或eclipse等开发环境(笔者用的版本是IDEA 2018.3.5)。
    d.下载并安装Wildfly服务器(网上的教程大多是10.0.0版本,最新的版本是16.0.0,笔者用的版本是16.0.0)。
    e.下载并安装Mysql数据库
    f.windows10家庭版
  3. 实验内容
    a.建立有状态的Java Bean,实现以下功能:
    b.操作用户(录入人员)登陆后,显示本次登陆的次数和上一次登陆的时间;
    c.操作用户登录后,可进行校友的检索、修改、删除、统计等功能;
    d.5分钟如果没有操作,则自动登出系统;
    e.操作用户退出时,显示用户连接的时间长度,并把此次登陆记录到数据库。

二、实验过程

1.代码打包如下:链接: https://pan.baidu.com/s/1mxV0BWVY3QjMjz3L5anSZQ 提取码: es83
2.主体代码:

package org.jboss.as.quickstarts.ejb.remote.stateful;

import java.util.List;

public interface MyRemote {
    boolean login(String username, String password);
    boolean mysql_init();
    int update(String sql);
    List query(String sql);
}
package org.jboss.as.quickstarts.ejb.remote.stateful;

import javax.ejb.Remote;
import javax.ejb.Stateful;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Stateful
@Remote(MyRemote.class)
public class Bean implements MyRemote {
    //不知道为什么,我用resultset返回query的结果到client时,就会报错,缺少什么resultset的jdk,于是我把resultset转换成list返回
    private List convertList(ResultSet rs) throws SQLException{
        List list = new ArrayList();
        ResultSetMetaData md = rs.getMetaData();//获取键名
        int columnCount = md.getColumnCount();//获取行的数量
        while (rs.next()) {
            Map rowData = new HashMap();//声明Map
            for (int i = 1; i <= columnCount; i++) {
                rowData.put(md.getColumnName(i), rs.getObject(i));//获取键名及值
            }
            list.add(rowData);
        }
        return list;
    }
    //登录
    public boolean login(String username, String password){
        if(username.equals("cyd") && password.equals("cyd"))
            return true;
        else
            return false;
    }
    //数据库初始化
    public boolean mysql_init(){
        boolean flag = false;
        try {
            Context context = new InitialContext();
            DataSource dataSource = (DataSource) context.lookup("java:jboss/datasources/ExampleDS");
            Connection connection = dataSource.getConnection();
            Statement statement = connection.createStatement();
            statement.executeUpdate("create table admin(login_time TIMESTAMP (23) not null);");//一定不能大于23,不然会报错,建表失败
            //姓名、性别、生日、入学年份、毕业年份、工作城市/地区、工作单位、职务、手机、邮箱、微信
            statement.executeUpdate("create table alumni(name char (20) not null, gender char (10), birthday char (20), " +
                    "entrance int (4), graduation int (4), location char (20), company char (20), job char (20)," +
                    "phone char(11) not null, mail char (20), wechat char (20));");
            statement.executeUpdate("insert into alumni(name,gender,birthday,entrance,graduation,location,company,job,phone,mail,wechat)" +
                    "values('cyd','male','19971012','2016','2020','xiamen','xmu','student','15659833304','767937571@qq.com','cyd767937571')");
            statement.executeUpdate("insert into alumni(name,gender,birthday,entrance,graduation,location,company,job,phone,mail,wechat)" +
                    "values('cxx','female','19941209','2014','2018','xiamen','liantong','manager','15659833303','7685946828@qq.com','wechat')");
            flag = true;
            connection.close();
            statement.close();
        } catch (NamingException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return flag;
    }
    //insert, delete, update用这个,返回的是更新的行数
    public int update(String sql){
        int ins = 0;
        try {
            Context context = new InitialContext();
            DataSource dataSource = (DataSource) context.lookup("java:jboss/datasources/ExampleDS");
            Connection connection = dataSource.getConnection();
            Statement statement = connection.createStatement();
            ins = statement.executeUpdate(sql);
            connection.close();
            statement.close();
        } catch (NamingException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return ins;
    }
    //select用这个,返回的是本来是结果集,现在被我转换成List
    public List query(String sql){
        List list = new ArrayList();
        try {
            Context context = new InitialContext();
            DataSource dataSource = (DataSource) context.lookup("java:jboss/datasources/ExampleDS");
            Connection connection = dataSource.getConnection();
            Statement statement = connection.createStatement();
            ResultSet rs = statement.executeQuery(sql);
            list = convertList(rs);
            connection.close();
            statement.close();
        } catch (NamingException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }
}
package org.jboss.as.quickstarts.ejb.remote.client;
import org.jboss.as.quickstarts.ejb.remote.stateful.MyRemote;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.*;

public class RemoteEJBClient {

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

        // Invoke a stateful bean
        invokeStatefulBean();
    }


    /**
     * Looks up a stateful bean and invokes on it
     *
     * @throws NamingException
     */
    private static void invokeStatefulBean() throws NamingException{
        final MyRemote statefulRemoteCounter = lookupRemoteStatefulCounter();
        statefulRemoteCounter.mysql_init();
        boolean flag = true;
        while(flag){
            System.out.println("1:login");
            System.out.println("others:exit");
            Scanner input_login = new Scanner(System.in);
            switch (input_login.nextInt()) {
                case 1:
                    Scanner input_info = new Scanner(System.in);
                    System.out.println("username:");
                    String username = input_info.nextLine();
                    System.out.println("password:");
                    String password = input_info.nextLine();
                    if (statefulRemoteCounter.login(username, password)) {
                        Timestamp login_time = new Timestamp(System.currentTimeMillis());
                        List list_time = statefulRemoteCounter.query("select login_time from admin;");
                        if (list_time.isEmpty()) {
                            System.out.println("You have never logged in!");
                        } else {
                            int login_count = 1;
                            Timestamp timestamp = new Timestamp(System.currentTimeMillis());
                            for (Object list : list_time) {
                                login_count++;
                                HashMap hm = (HashMap) list;
                                for (Object key : hm.keySet()) {
                                    timestamp = (Timestamp) hm.get(key);
                                }
                            }
                            System.out.println("You have logged in to the system " + login_count + " times.");
                            System.out.println("The last time you logged into the system was " + timestamp + ".");
                        }
                        int result_int = statefulRemoteCounter.update(
                                "insert into admin(login_time)values('" + login_time + "');");
//                        if (result_int > 0) {
//                            System.out.println("insert data successfully!");
//                        }
                        System.out.println("login successfully");
                        boolean flag2 = true;
                        Timestamp init_time = new Timestamp(System.currentTimeMillis());
                        while(flag2) {
                            System.out.println("1:select");
                            System.out.println("2:update");
                            System.out.println("3:delete");
                            System.out.println("4:total");
                            System.out.println("5:insert");
                            System.out.println("others:logout");
                            Scanner input_operation = new Scanner(System.in);
                            int input_num = input_operation.nextInt();
                            Timestamp current_time = new Timestamp(System.currentTimeMillis());
                            float difftime = (current_time.getTime()-init_time.getTime())/1000;
                            if(difftime > 300){
                                System.out.println("You have logged out of the system because it has not been operated for a long time!");
                                current_time = new Timestamp(System.currentTimeMillis());
                                difftime = (current_time.getTime()-login_time.getTime())/1000;
                                System.out.println("Your login time is "+difftime+" seconds.");
                                break;
                            }
                            init_time = current_time;
                            switch (input_num){
                                case 1:
                                    System.out.println("input the content you want to select(name,gender,birthday,entrance,graduation,location,company,job,phone,mail,wechat,*):");
                                    Scanner input_content1 = new Scanner(System.in);
                                    String content1 = input_content1.nextLine();
                                    System.out.println("input the someone you want to show(where name = 'caiyuedong' or nothing):");
                                    Scanner input_value1 = new Scanner(System.in);
                                    String value1 = input_value1.nextLine();
                                    List select_result1=statefulRemoteCounter.query("select "+content1+" from alumni "+value1+";");
                                    if(select_result1.isEmpty()){
                                        System.out.println("Check no such person!");
                                    }else {
                                        for (Object sr : select_result1) {
                                            System.out.println(sr);
                                        }
                                    }
                                    break;
                                case 2:
                                    System.out.println("input the name you select:");
                                    Scanner input_name2 = new Scanner(System.in);
                                    String name2 = input_name2.nextLine();
                                    List select_result2=statefulRemoteCounter.query("select * from alumni where name ='"+name2+"';");
                                    if(select_result2.isEmpty()){
                                        System.out.println("Check no such person!");
                                    }else {
                                        for (Object sr : select_result2) {
                                            System.out.println(sr);
                                        }
                                        System.out.println("input the content you want to update(name,gender,birthday,entrance,graduation,location,company,job,phone,mail,wechat):");
                                        Scanner input_content2 = new Scanner(System.in);
                                        String content2 = input_content2.nextLine();
                                        System.out.println("input the value you want to update:");
                                        Scanner input_value2 = new Scanner(System.in);
                                        String value2 = input_value2.nextLine();
                                        int update_result = statefulRemoteCounter.update("update alumni set "+content2+"='"+value2+"' WHERE name='"+name2+"';");
                                        if(update_result>0){
                                            System.out.println("Update successfully");
                                        }else {
                                            System.out.println("Update unsuccessfully");
                                        }
                                    }
                                    break;
                                case 3:
                                    System.out.println("input the content you want to delete(name,gender,birthday,entrance,graduation,location,company,job,phone,mail,wechat):");
                                    Scanner input_content3 = new Scanner(System.in);
                                    String content3 = input_content3.nextLine();
                                    System.out.println("input the value you want to delete:");
                                    Scanner input_value3 = new Scanner(System.in);
                                    String value3 = input_value3.nextLine();
                                    System.out.println("Are you sure?Y/N");
                                    Scanner input_sure3 = new Scanner(System.in);
                                    String sure3 = input_sure3.nextLine();
                                    if(sure3.equals("Y")){
                                        statefulRemoteCounter.update("delete from alumni where "+content3+" = '"+value3+"';");
                                        System.out.println("delete successfully");
                                    }
                                    break;
                                case 4:
                                    int count = 0;
                                    System.out.println("input the content you want to count(name,gender,birthday,entrance,graduation,location,company,job,phone,mail,wechat):");
                                    Scanner input_content4 = new Scanner(System.in);
                                    String content4 = input_content4.nextLine();
                                    System.out.println("input the value you want to count:");
                                    Scanner input_value4 = new Scanner(System.in);
                                    String value4 = input_value4.nextLine();
                                    List select_result4=statefulRemoteCounter.query("select * from alumni where "+content4+"='"+value4+"';");
                                    if(select_result4.isEmpty()){
                                        System.out.println("no person!");
                                    }else {
                                        for (Object sr : select_result4) {
                                            System.out.println(sr);
                                            count++;
                                        }
                                        System.out.println("There are "+count+" people totally");
                                    }
                                    break;
                                case 5:
                                    System.out.println("input the value you want to insert(name,gender,birthday,entrance,graduation,location,company,job,phone,mail,wechat):");
                                    System.out.println("such as 'cyd','male','19971012','2016','2020','xiamen','xmu','student','15659833304','767937571@qq.com','cyd767937571'");
                                    Scanner input_name5 = new Scanner(System.in);
                                    String value5 = input_name5.nextLine();
                                    System.out.println(value5);
                                    int insert_result = statefulRemoteCounter.update("insert into alumni(name,gender,birthday,entrance,graduation,location,company,job,phone,mail,wechat)" +
                                            "values("+value5+")");
                                    if(insert_result>0)
                                        System.out.println("insert successfully");
                                    break;
                                    default:
                                        current_time = new Timestamp(System.currentTimeMillis());
                                        difftime = (current_time.getTime()-login_time.getTime())/1000;
                                        System.out.println("Your login time is "+difftime+" seconds.");
                                        flag2 = false;
                                        break;
                            }
                        }
                    } else {
                        System.out.println("login unsuccessfully");
                    }
                    break;
                    default:
                        flag = false;
                        break;
            }
        }
    }


    /**
     * Looks up and returns the proxy to remote stateful counter bean
     *
     * @return
     * @throws NamingException
     */
    private static MyRemote lookupRemoteStatefulCounter() throws NamingException {
        final Hashtable<String, String> jndiProperties = new Hashtable<>();
        jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
        final Context context = new InitialContext(jndiProperties);

        // The JNDI lookup name for a stateful session bean has the syntax of:
        // ejb:<appName>/<moduleName>/<distinctName>/<beanName>!<viewClassName>?stateful
        //
        // <appName> The application name is the name of the EAR that the EJB is deployed in
        // (without the .ear). If the EJB JAR is not deployed in an EAR then this is
        // blank. The app name can also be specified in the EAR's application.xml
        //
        // <moduleName> By the default the module name is the name of the EJB JAR file (without the
        // .jar suffix). The module name might be overridden in the ejb-jar.xml
        //
        // <distinctName> : WildFly allows each deployment to have an (optional) distinct name.
        // This example does not use this so leave it blank.
        //
        // <beanName> : The name of the session been to be invoked.
        //
        // <viewClassName>: The fully qualified classname of the remote interface. Must include
        // the whole package name.

        // let's do the lookup
        return (MyRemote) context.lookup("ejb:/wildfly-ejb-remote-server-side/Bean!"
            + MyRemote.class.getName() + "?stateful");
    }
}

3.我的实验过程
我的代码是在一个demo(链接: https://pan.baidu.com/s/1OAkiqpxF2e9W7uOynX1Y4A 提取码: qezh)的基础上修改的。实验思路很清晰,用server连接数据库,然后在client端传送操作指令到server与数据库交互。刚开始的时候,打算使用JDBC连接数据库,但是每次都会报以下错误
java.lang.ClassNotFoundException: jdbc:mysql://127.0.0.1:3306/ejb_remote
在网上查找了很多相关的教程,例如在server的文件右键中的“Open Module Setting”添加jar包依赖,修改pom.xml文件等,都没办法解决这个问题,(有关于以上两个方法见后面的分享),于是我改用JNDI连接Mysql,(有关于JDBC和JDNI的优劣等见后面的分享),核心代码如下:

Context context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("java:jboss/datasources/ExampleDS");//连接默认的数据库
Connection connection = dataSource.getConnection();//创建连接
Statement statement = connection.createStatement();//用来执行sql语句
statement.executeUpdate("create table admin(login_time TIMESTAMP (23) not null);");//.executeUpdate返回的是受影响的行数,executeQuery返回的ResultSet,即操作的结果集合
connect.close;
statement.close;

接下来是最坑的阶段了,我以为wildfly要自己手动配置,于是我从官网上https://wildfly.org/downloads/下载了wildfly16.0.0,但是DataSource的配置一直配置不好,于是我更改版本,换成wildfly10.0.0版本(链接: https://pan.baidu.com/s/12DtYy022icKQaHlnSFllcQ 提取码: ijxb ),重新配置数据源,(配置数数据源的方法见后面的分享),这次成功了(科学的终点是玄学?有时候我也搞不懂,按照教程来,有时候可以,有时候不行),到这个时候我才发现,原来我第一次运行demo的时候,这个demo会自动下载并部署好一个wildfly16.0.0,以后的每次运行都是重新加载wildfly16.0.0,可以理解成重置,同时默认连接好Mysql,即数据源java:jboss/datasources/ExampleDS,每次重启server的时候,Mysql都会清空,所以要重新建表,初始化表。运行server后,会生成一个target文件夹,里面有一些配置,包括wildfly的文件夹。


所以其实如果知道这个东西之后,实验的内容就很简单了,直接在MyRemote.java里面设置接口,在Bean.java里面实现函数,从Client里面调用函数,处理好逻辑和熟悉SQL语句的话根本不难。以下是一些运行结果的截图


三、分享及我遇见的各种bug(满满的都是干货)

1.wildfly安装与环境配置,以及一些操作细节(上述的代码无需安装和配置wildfly)

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

或者直接在下图添加


2.jdbc和jdni

JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序.
JNDI全名为Java Naming and Directory Interface.JNDI主要提供应用程序所需要资源上命名目录服务。在Java EE环境中,JNDI扮演了一个很重要的角色,它提供了一个接口让用户在不知道资源所在位置的情形下,取得该资源服务。就好比网络磁盘驱动器的功能一样。如果有人事先将另一台机器上的磁盘驱动器接到用户的机器上,用户在使用的时候根本就分辨不出现在的驱动器是存在本端,还是在另一端的机器上,用户只需取得资源来用,根本就不知道资源在什么地方。
以上概念来自百度百科。

String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/mysqldb";
String username = "root";
String password = "";
Connection conn = null;
try {
     Class.forName(driver); //classLoader,加载对应驱动
     conn = (Connection) DriverManager.getConnection(url, username, password);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (SQLException e) {
        e.printStackTrace();
}
Context context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("java:jboss/datasources/ExampleDS");//连接默认的数据库
Connection connection = dataSource.getConnection();//创建连接
Statement statement = connection.createStatement();//用来执行sql语句
statement.executeUpdate("create table admin(login_time TIMESTAMP (23) not null);");//.executeUpdate返回的是受影响的行数,executeQuery返回的ResultSet,即操作的结果集合
connect.close;
statement.close;

3.运行的代码解读
server端的运行结果,挑选几条特别关心
[org.jboss.as] (MSC service thread 1-2) WFLYSRV0049: WildFly Full 16.0.0.Final (WildFly Core 8.0.0.Final) starting ——启动的是默认配置的wildfly16
[org.jboss.as.connector.subsystems.datasources] (MSC service thread 1-7) WFLYJCA0001: Bound data source [java:jboss/datasources/ExampleDS] ——绑定的数据源是默认配置的ExampleDS
[org.jboss.as.server] (management-handler-thread - 1) WFLYSRV0010: Deployed "wildfly-ejb-remote-server-side.jar" (runtime-name : "wildfly-ejb-remote-server-side.jar") ——到这步说明部署成功,可以开始运行client端,在这之前运行client会报错,大概意思是连接被拒绝。

4.总结
兜兜转转,配环境那么久到最后发现demo已经帮你搞定一切了,只需要直接编写逻辑代码就行,有点难受,不过实际配环境这么久,查了很多官方文档和看了很多博客,也学习到了很多东西,至少我对wildfly、maven、jdni的运用的了解加深了很多。

以上有小部分内容引用了其他博客的内容,都有附上链接,以及一些代码等也有放在百度网盘里了,如果有侵权的地方,我会立即删除。以上,终于完成这个作业了,舒服。

上一篇 下一篇

猜你喜欢

热点阅读