实验2 EJB

实验目的

使用idea+wildfly+ejb搭建web项目:
假设某天你毕业了,需要构建一个校友的信息收集系统。 你定义了管理员格Admin表,需要收集的校友的信息Alumni表。Alumni字段定义如下:
{姓名、性别、生日、入学年份、毕业年份、工作城市/地区、工作单位、职务、手机、邮箱、微信} 。

Stateless

实验内容

建立无状态的Java Bean,实现以下功能:

验证操作用户(录入人员)的登陆的信息是否正确;
把校友的数据插入到数据库的中;应包含校友的所有信息;
对校友目录进行的检索、修改、删除、统计等功能;
随机生成20个录入员,生成1000个校友用户。进行各种增删改的操作。

实验过程

  • 搭建EJb环境
  • 实现modelBean
  • 定义sessionBean接口
  • 实现sessionBean
  • 部署项目
  • 客户端测试

搭建EJb环境

参考博文https://blog.csdn.net/c_j33/article/details/78990742

不使用jndi连接数据库,直接导入jdbc驱动:
1.导入jdbc驱动的jar包并add as library
2.File->Project Structure->Artifacts->server:war exploded->在WEB-INF目录下新建lib目录,把jdbc的library加进去(这样部署的时候才会把jdbc的驱动依赖也部署上去)


image.png

最后项目结构如下


image.png

实现modelBean

SchoolFellowModel

public class SchoolFellowModel implements Serializable {
    Connection connection;
    public static String URL = "jdbc:mysql://localhost:3306/schoowfellow?useUnicode=true&characterEncoding=UTF8&useSSL=false";
    public static String USER = xxx;
    public static String PASSWORD = xxx;

    public SchoolFellowModel() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.jdbc.Driver");
        connection = DriverManager.getConnection(URL, USER, PASSWORD);
    }

    public boolean update(T schoolFellow) throws InvocationTargetException, IllegalAccessException, SQLException {
        String values = "";
        int start = 0;
        Field[] fields = SchoolFellow.class.getDeclaredFields();
        //遍历这个类所有的属性
        for (Field field : SchoolFellow.class.getDeclaredFields()) {
            //遍历这个类所有的方法,找到对应属性的get方法,并在传入的实例调用,如果不为空的话则将它作为插入信息加到sql语句里
            for (Method method : SchoolFellow.class.getMethods()) {
                String methodName = method.getName();
                if (methodName.substring(0, 3).equals("get")) {
                    String methodAttribute = methodName.substring(3, methodName.length());
                    String transfer = methodAttribute.substring(0, 1).toLowerCase()
                            + methodAttribute.substring(1, methodAttribute.length());
                    if (!transfer.equals(field.getName())) {
                        continue;
                    }
                    if (method.invoke(schoolFellow) == null || method.getName().equals("getId")) {
                        break;
                    }
                    if (start > 0) {
                        values += ",";
                    }
                    values += field.getName() + "='" + method.invoke(schoolFellow) + "'";
                    start++;
                    break;
                }
            }
        }
        String sql = "update schoolfellow set " + values;
        Statement statement = connection.createStatement();
        statement.execute(sql);
        statement.close();
        return true;
    }
}

这里使用java的反射机制实现了简单的增删改的框架,这里只贴出了insert的代码,其他的实现大同小异(我猜其他orm框架实现原理也差不多)
这里测试的时候发现通过java反射获取到的method列表的排列顺序并不源文件里定义的顺序,跟属性定义的顺序对不上,所以只能像上面的方法那样做两次遍历。

定义sessionBean接口

@Remote
public interface SchoolFellowService {
    public Object login(String username, String password) throws Exception;

    public boolean insert(SchoolFellow schoolFellow) throws InvocationTargetException, IllegalAccessException, SQLException;

    public boolean delete(int id) throws SQLException;

    public boolean update(SchoolFellow schoolFellow) throws InvocationTargetException, IllegalAccessException, SQLException;

    public SchoolFellow get(int id) throws InvocationTargetException, IllegalAccessException, SQLException;

    public int getCount() throws SQLException;
}

实现sessionBean

@Stateless
@Interceptors(CheckIsLogin.class)
public class SchoolFellowServiceBean implements SchoolFellowService {
    private SchoolFellowModel schoolFellowBean;
    private AdminModel adminModel;

    public SchoolFellowServiceBean() throws SQLException, ClassNotFoundException {
        schoolFellowBean = new SchoolFellowModel();
        adminModel = new AdminModel();
    }

    @Override
    public Object login(String username, String password) throws Exception {
        Admin admin = new Admin();
        admin.setUsername(username);
        admin.setPassword(password);
        if (adminModel.check(admin)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean insert(SchoolFellow schoolFellow) throws InvocationTargetException, IllegalAccessException, SQLException {
        return schoolFellowBean.insert(schoolFellow);
    }

    @Override
    public boolean delete(int id) throws SQLException {
        return schoolFellowBean.delete(id);
    }

    @Override
    public boolean update(SchoolFellow schoolFellow) throws InvocationTargetException, IllegalAccessException, SQLException {
        return schoolFellowBean.update(schoolFellow);
    }

    @Override
    public SchoolFellow get(int id) throws InvocationTargetException, IllegalAccessException, SQLException {
        return schoolFellowBean.get(id);
    }

    @Override
    public int getCount() throws SQLException {
        return schoolFellowBean.getCount();
    }
}

使用AOP实现登录验证,这里为每个bean实现一个动态代理类,在调用login方法时验证登录信息,并把它标记为已登录。调用其他方法时验证是否登录,如果没有登录则报错。(stateful的bean这样做没有问题,但是stateless的bean这样做会出现问题,测试的时候再解释)

public class CheckIsLogin {
    private boolean isLogin;

    public CheckIsLogin() throws Exception {
        isLogin = false;
    }

    @AroundInvoke
    public Object check(InvocationContext ic) throws Exception {
        if (ic.getMethod().getName().equals("login")) {
            isLogin = (boolean) ic.proceed();
            return isLogin;
        }
        if (isLogin) {
            return ic.proceed();
        }
        throw new RuntimeException("not login!");
    }
}

部署项目

选择edit configrations配置运行,部署到wildfly。在deployment选项卡中,添加生成的war包。


image.png

image.png

客户端测试

测试crud操作

if((boolean)schoolFellowService.login("bao","123456")){
                System.out.println("login success!");
            }
            else{
                System.out.println("username or password error");
            }
            schoolFellowService.insert(schoolFellow);
            System.out.println("insert success!");

            SchoolFellow schoolFellow1=schoolFellowService.get(38);
            System.out.println("get success!");
            System.out.println(schoolFellow1);

            schoolFellow1.setWorkLocation("beijin");
            schoolFellow1.setJob("boss");
            schoolFellowService.update(schoolFellow1);
            System.out.println("update success!");
            System.out.println(schoolFellowService.get(38));

            schoolFellowService.delete(38);
            System.out.println("delete success!");
image.png

测试登录验证
client1

try {
            if((boolean)schoolFellowService.login("bao","123456")){
                System.out.println("login success!");
            }
            else{
                System.out.println("username or password error");
            }
            schoolFellowService.insert(schoolFellow);
            System.out.println("insert success!");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

client2

try {
            schoolFellowService.insert(schoolFellow);
            System.out.println("insert success!");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

这里client1和client2区别仅在于client1在执行sessionBean操作前先进行了登录验证,而client没有.
先运行client1再运行client2.
client1:


image.png

client2:


image.png

根据前面aop处理登录的定义,client2应该会输出错误信息"not login!",然而并没有。说明两个客户端的sessionBean的aop代理类是同一个,所以调用的sessionBean也是同一个。client1产生的sessionBean并没有销毁,而是保存在了对象池中,而client2调用了同一个sessionBean。

测试生成用户记录


image.png

Stateful

实验内容

建立有状态的Java Bean,实现以下功能:

操作用户(录入人员)登陆后,显示本次登陆的次数和上一次登陆的时间;
操作用户登录后,可进行校友的检索、修改、删除、统计等功能;
5分钟如果没有操作,则自动登出系统;
操作用户退出时,显示用户连接的时间长度,并把此次登陆记录到数据库。
在2台机器上模拟2个录入员,生成1000个校友用户,并进行各种增删改的操作。

实验过程

搭建EJb环境

实现modelBean

adminModel

public class AdminModel implements Serializable {
    Connection connection;
    public static String URL = "jdbc:mysql://localhost:3306/schoowfellow?useUnicode=true&characterEncoding=UTF8&useSSL=false";
    public static String USER = "xxx";
    public static String PASSWORD = "xxx";

    public AdminModel() throws SQLException {
        connection = DriverManager.getConnection(URL, USER, PASSWORD);
    }

    public boolean check(Admin admin) throws SQLException {
        String sql = "select * from admin where username='" + admin.getUsername() + "' and password=" + "'" + admin.getPassword() + "'";
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql);
        if (resultSet.next()) {
            statement.close();
            return true;
        } else {
            statement.close();
            return false;
        }
    }

    public void insert(Admin admin) throws SQLException {
        String sql = "insert into admin(username,password) values('" + admin.getUsername() + "','" + admin.getPassword() + "')";
        Statement statement = connection.createStatement();
        statement.execute(sql);
        statement.close();
    }

    public void insertConnectInfo(String username, String startTime, String connectTime) throws SQLException {
        String sql = "insert into connect_info values('" + username + "','" + startTime + "','" + connectTime + "')";
        Statement statement = connection.createStatement();
        statement.execute(sql);
        statement.close();
    }
}

定义sessionBean接口

@Remote
public interface SchoolFellowStatefulService extends SchoolFellowService {
    public String logout();
}

实现sessionBean

@Stateful
//@Interceptors(CheckIsLogin.class)
public class SchoolFellowStatefulServiceBean extends SchoolFellowServiceBean implements SchoolFellowStatefulService {

    public SchoolFellowStatefulServiceBean() throws SQLException, ClassNotFoundException {
        super();
    }

    @Override
    public String logout() {
        return null;
    }
}

AOP代理类保存登录信息,同时处理登录登出请求:
当执行login方法时返回此次登录的次数loginCount,和上次登录的时间 lastLoginTime,并更新loginCount和lastLoginTime以及lastOperateTime(上一次操作的时间)。
当执行其他方法时,先判断当前的时间和lastOperateTime的差值是否大于5分钟,如果是则跑错提醒用户需重新登录。
然后判断方法是否为logout,是的话则返回此次连接的时间。
最后调用原方法。

因为是StatefulBean是存在于整个会话的,一个StatefulBean对应一个用户,且一个StatefulBean有一个AOP代理类,所以这样做是可行的。

public class CheckIsLogin {
    private String username;
    private boolean isLogin;
    private boolean isStateful;
    private int loginCount;
    private String lastLoginTime;
    private long lastOperateTime;

    private AdminModel adminModel;

    public CheckIsLogin() throws Exception {
        username = null;
        loginCount = 0;
        lastOperateTime = 0;
        lastLoginTime = "first login";
        isLogin = false;
        isStateful = false;
        adminModel = new AdminModel();
    }

    @AroundInvoke
    public Object check(InvocationContext ic) throws Exception {
        if (ic.getMethod().getName().equals("login")) {
            isLogin = (boolean) ic.proceed();
            if (ic.getTarget().getClass().getAnnotation(javax.ejb.Stateful.class) != null && isLogin) {
                username = (String) ic.getParameters()[0];
                isStateful = true;
                loginCount++;
                lastOperateTime = System.currentTimeMillis();
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                lastLoginTime = df.format(new Date());
                return "login count:" + loginCount + " lastLoginTime:" + lastLoginTime;
            }
            return isLogin;
        }
        if (isLogin) {
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            if (ic.getMethod().getName().equals("logout")) {
                long connectTime = System.currentTimeMillis() - df.parse(lastLoginTime).getTime();
                String connectTimeString = df.format(new Date(new Long(connectTime)));
                adminModel.insertConnectInfo(username,lastLoginTime,connectTimeString);
                return "connect time:" + connectTime + "ms";
            }
            if (ic.getTarget().getClass().getAnnotation(javax.ejb.Stateful.class) != null) {
                isLogin = false;
                if (System.currentTimeMillis() - lastOperateTime >= 300000) {
                    String connectTime = df.format(new Date(new Long(300000)));
                    adminModel.insertConnectInfo(username,lastLoginTime,connectTime);
                    throw new RuntimeException("too long to operate you should login again!");
                }
                lastOperateTime = System.currentTimeMillis();
            }
            return ic.proceed();
        }
        throw new RuntimeException("not login!");
    }
}

部署项目

客户端测试

登录和自动登出


image.png

执行crud操作然后登出

public class testStateful {
    public static void main(String[] args) throws Exception {
        SchoolFellowStatefulService schoolFellowStatefulService = (SchoolFellowStatefulService) EJBFactory.getEJB(
                "ejb:/server_war_exploded/SchoolFellowStatefulServiceBean!stateful.SchoolFellowStatefulService?stateful");
        SchoolFellow schoolFellow = new SchoolFellow();
        schoolFellow.setName("happy");
        schoolFellow.setSex("boy");
        schoolFellow.setPhone("123456");
        schoolFellow.setJob("student");
        schoolFellow.setEmail("[email protected]");
        schoolFellow.setAttendTime("2012-8-25 00:00:00");
        schoolFellow.setBirth("1998-10-17 00:00:00");
        schoolFellow.setGraduateTime("2016-7-12 00:00:00");
        schoolFellow.setWechat("bao");
        schoolFellow.setWorkCity("changsha");
        schoolFellow.setWorkLocation("hangzhou");
        try {
            System.out.println(schoolFellowStatefulService.login("bao","123456"));

            schoolFellowStatefulService.insert(schoolFellow);
            System.out.println("insert success!");

            SchoolFellow schoolFellow1=schoolFellowStatefulService.get(504);
            System.out.println(schoolFellow1);
            System.out.println("get success!");

            schoolFellow1.setSex("girl");
            System.out.println("update success!");

            schoolFellowStatefulService.delete(504);
            System.out.println("delete success!");

            System.out.println(schoolFellowStatefulService.logout());
            System.out.println("logout success!");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }
}
image.png

image.png

你可能感兴趣的:(实验2 EJB)