1 实验要求
设计实现一个三层架构的数据通讯程序,后台数据库类型不限;界面层是Windows 窗体;中间层、数据服务层使用Java进行设计。分布式数据库程序实践。采用RMI技术,实现对数据库表的封装,远程可以实现增删改查操作。
1.1 具体要求
准备3台计算机(1台计算机也可以实现),分别为Client/Applicantion/Database。Client采用Form技 术;Database为任意数据库。建立一个User表包含用户基本信息(工号、姓名、性别、 电话)。完成下列要求程序:
(1)Client页面实现增删改查功能,内部调用Application计算机的UserList对象, 采用RMI方法。
(2)UserList对象调用Database上的UserTable对象,采用RMI方法。 UserTable真正完成本地User表的数据库操作。
提示:
UserTable类封装增删改查4个方法,对应数据库操作。UserList类内部为一个User对象的列表,对于列表实现增删改查操作,同步作用到UserTable对象。
1.2实验环境
系统:Windows10
语言:Java
开发工具:MyEclipse 2017 CI
数据库:MySQL
2 实验步骤
2.1RMI应用开发步骤
① 定义一个远程接口
② 实现远程接口和服务器
③ 使用远程接口开发客户程序
④ 启动RMI注册程序
⑤ 运行服务器程序
⑥ 运行客户程序
2.2 实验步骤
- 数据层设计
创建User表,关键代码:
// 该字段必须存在
private static final long serialVersionUID = 42L;
private String workid; // 工号
private String name; // 姓名
private String sex; // 性别
private String phone; // 电话号码
IUserTable接口的创建,关键代码:
// 添加
void addUser(User user) throws RemoteException;
// 删除
void deleteUser(String workid) throws RemoteException;
// 修改
void updateUser(User user) throws RemoteException;
// 查询
List<User> findAllUser() throws RemoteException;
UserTable接口实现类的设计(以增加为例进行说明)关键代码:
// 实现增加功能
@Override
public void addUser(User user) throws RemoteException {
String workid = user.getWorkid();
String name = user.getName();
String sex = user.getSex();
String phone = user.getPhone();
// 数据库连接
DBConn db = new DBConn();
Connection conn = db.getConnection();
// 预处理语句
PreparedStatement pre1;
try {
pre1 = conn.prepareStatement("insert into user(workid,name,sex,phone) VALUES(?,?,?,?)");
pre1.setString(1, workid);
pre1.setString(2, name);
pre1.setString(3, sex);
pre1.setString(4, phone);
int result = pre1.executeUpdate();
// 判断是否添加成功
if (result > 0) {
System.out.println("增加成功。");
} else {
System.out.println("插入失败。");
}
pre1.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
- 中间层设计
IUserList接口设计,关键代码:
// 添加
void addUser(User user) throws RemoteException;
// 删除
void deleteUser(String workid) throws RemoteException;
// 修改
void updateUser(User user) throws RemoteException;
// 查询
List<User> findAllUser() throws RemoteException;
使用远程接口开发程序:
// 创建实际提供服务的对象
UserListImpl obj = new UserListImpl();
// 使用匿名端口导出远程对象, 以便能够接收传入的调用。
IUserList stub = (IUserList) UnicastRemoteObject.exportObject(obj, 0);
// 获得本地注册存根,默认端口1099,可以自定义端口
// 主机和端口都是可选的,如果省略主机,则默认运行在本地;如果端口也省略,则默认端口是1099;
Registry registry = LocateRegistry.getRegistry();
// 注册远程对象stub的名字为addUser
registry.bind("userList", stub);
实现添加功能,关键代码:
Registry registry = LocateRegistry.getRegistry(null);
IUserTable stub = (IUserTable) registry.lookup("userTable");
stub.addUser(user);
- 界面层设计
使用Windows窗体进行设计
3 实验代码运行步骤
3.1 启动RMI注册程序
在项目bin目录下启动注册程序:
3.2 启动UserTableImpl
运行UserTableImpl.java。会出现:
3.3 启动UserListImpl
运行UserListImpl.java。会出现:
3.4 启动ClientJFrame
运行ClientJFrame.java。会出现:
4 整体项目文件结构图
5 关键代码
在此只附上关键代码,完整的代码可以在:https://gitee.com/haaaaaaaaaaaa/SourceCode.git这里下载,仓库中还有一些其他实验代码,感兴趣的话可以去看看。
5.1 UserTableImpl.java
package cn.edu.ujn.database;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
public class UserTableImpl implements IUserTable {
// 构造方法
public UserTableImpl() {
}
// 实现增加功能
@Override
public void addUser(User user) throws RemoteException {
String workid = user.getWorkid();
String name = user.getName();
String sex = user.getSex();
String phone = user.getPhone();
// 数据库连接
DBConn db = new DBConn();
Connection conn = db.getConnection();
// 预处理语句
PreparedStatement pre1;
try {
pre1 = conn.prepareStatement("insert into user(workid,name,sex,phone) VALUES(?,?,?,?)");
pre1.setString(1, workid);
pre1.setString(2, name);
pre1.setString(3, sex);
pre1.setString(4, phone);
int result = pre1.executeUpdate();
// 判断是否添加成功
if (result > 0) {
System.out.println("增加成功。");
} else {
System.out.println("插入失败。");
}
pre1.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 实现删除功能
public void deleteUser(String workid) throws RemoteException {
// 数据库连接
DBConn db = new DBConn();
Connection conn = db.getConnection();
// 预处理语句
PreparedStatement pre1;
try {
pre1 = conn.prepareStatement("delete from user where workid=?");
pre1.setString(1, workid);
int result = pre1.executeUpdate();
// 判断是否添加成功
if (result > 0) {
System.out.println("删除成功。");
} else {
System.out.println("删除失败。");
}
pre1.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 实现修改功能
public void updateUser(User user) throws RemoteException {
String workid = user.getWorkid();
String name = user.getName();
String sex = user.getSex();
String phone = user.getPhone();
// 数据库连接
DBConn db = new DBConn();
Connection conn = db.getConnection();
// 预处理语句
PreparedStatement pre1;
try {
pre1 = conn.prepareStatement("update user set name = ? , sex = ? ,phone=? where workid = ?");
pre1.setString(1, name);
pre1.setString(2, sex);
pre1.setString(3, phone);
pre1.setString(4, workid);
int result = pre1.executeUpdate();
// 判断是否添加成功
if (result > 0) {
System.out.println("修改成功。");
} else {
System.out.println("修改失败。");
}
pre1.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 实现查询功能
public List<User> findAllUser() throws RemoteException {
List<User> lists = new ArrayList<User>();
try {
// 数据库连接
DBConn db = new DBConn();
Connection conn = db.getConnection();
// 预处理语句
PreparedStatement pre1;
pre1 = conn.prepareStatement("select * from user");
ResultSet rs = pre1.executeQuery();
while (rs.next()) {
User user = new User();
user.setWorkid(rs.getString("workid"));
user.setName(rs.getString("name"));
user.setSex(rs.getString("sex"));
user.setPhone(rs.getString("phone"));
lists.add(user);
}
conn.close();
pre1.close();
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return lists;
}
public static void main(String args[]) {
try {
// 创建实际提供服务的对象
UserTableImpl obj = new UserTableImpl();
// 使用匿名端口导出远程对象, 以便能够接收传入的调用。
IUserTable stub = (IUserTable) UnicastRemoteObject.exportObject(obj, 0);
// Bind the remote object's stub in the registry
// 获得本地注册存根,默认端口1099,可以自定义端口
Registry registry = LocateRegistry.getRegistry();
// 注册远程对象stub的名字为addUser
registry.bind("userTable", stub);
// Naming.rebind("userTable", stub);
System.err.println("UserTableImpl Ready...");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
// 测试
UserTableImpl obj = new UserTableImpl();
List<User> lists = new ArrayList<User>();
try {
lists = obj.findAllUser();
for (User user : lists) {
Vector a = new Vector();
a.add(user.getWorkid());
a.add(user.getName());
a.add(user.getSex());
a.add(user.getPhone());
System.out.println(a);
}
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5.2 UserListImpl.java
package cn.edu.ujn.application;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.List;
import cn.edu.ujn.database.IUserTable;
import cn.edu.ujn.database.User;
import cn.edu.ujn.database.UserTableImpl;
public class UserListImpl implements IUserList {
// 构造方法
public UserListImpl() {
}
public static void main(String args[]) {
try {
// 创建实际提供服务的对象
UserListImpl obj = new UserListImpl();
// 使用匿名端口导出远程对象, 以便能够接收传入的调用。
IUserList stub = (IUserList) UnicastRemoteObject.exportObject(obj, 0);
// 获得本地注册存根,默认端口1099,可以自定义端口
// 主机和端口都是可选的,如果省略主机,则默认运行在本地;如果端口也省略,则默认端口是1099;
Registry registry = LocateRegistry.getRegistry();
// 注册远程对象stub的名字为addUser
registry.bind("userList", stub);
System.err.println("UserListImpl Ready...");
} catch (Exception e) {
System.err.println("UserListImpl exception: " + e.toString());
e.printStackTrace();
}
// UserListImpl obj = new UserListImpl();
// Vector a = new Vector();
// try {
// a=obj.findAllUser();
// } catch (RemoteException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
// 实现添加功能
public void addUser(User user) throws RemoteException {
// TODO Auto-generated method stub
try {
Registry registry = LocateRegistry.getRegistry(null);
IUserTable stub = (IUserTable) registry.lookup("userTable");
stub.addUser(user);
} catch (Exception e) {
System.err.println("UserListImpl exception: " + e.toString());
e.printStackTrace();
}
}
// 实现删除功能
public void deleteUser(String workid) throws RemoteException {
try {
Registry registry = LocateRegistry.getRegistry(null);
IUserTable stub = (IUserTable) registry.lookup("userTable");
stub.deleteUser(workid);
} catch (Exception e) {
System.err.println("UserListImpl exception: " + e.toString());
e.printStackTrace();
}
}
// 实现修改功能
public void updateUser(User user) throws RemoteException {
try {
Registry registry = LocateRegistry.getRegistry(null);
IUserTable stub = (IUserTable) registry.lookup("userTable");
stub.updateUser(user);
} catch (Exception e) {
System.err.println("UserListImpl exception: " + e.toString());
e.printStackTrace();
}
}
// 实现查询功能
public List<User> findAllUser() throws RemoteException {
List<User> lists = new ArrayList<User>();
try {
Registry registry = LocateRegistry.getRegistry(null);
IUserTable stub = (IUserTable) registry.lookup("userTable");
lists = stub.findAllUser();
} catch (Exception e) {
System.err.println("UserListImpl exception: " + e.toString());
e.printStackTrace();
}
return lists;
}
}
5.3 ClientJFrame.java
package cn.edu.ujn.client;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import java.awt.Font;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import cn.edu.ujn.application.IUserList;
import cn.edu.ujn.database.User;
import javax.swing.JButton;
import javax.swing.border.LineBorder;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class ClientJFrame extends JFrame {
private JPanel contentPane;
private JTable table;
private JButton findAllUser;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClientJFrame frame = new ClientJFrame();
frame.setVisible(true);
frame.setLocationRelativeTo(null); // 窗体居中显示
// frame.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public ClientJFrame() {
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
exit();
}
});
setTitle("\u5BA2\u6237\u7AEF");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 718, 371);
contentPane = new JPanel();
contentPane.setForeground(new Color(255, 255, 255));
contentPane.setBackground(new Color(255, 255, 255));
// contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblNewLabel = new JLabel("\u6B22\u8FCE\u4F7F\u7528\u5BA2\u6237\u7AEF\uFF01");
lblNewLabel.setBounds(5, 5, 690, 29);
lblNewLabel.setForeground(new Color(51, 0, 0));
lblNewLabel.setFont(new Font("宋体", Font.PLAIN, 24));
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
contentPane.add(lblNewLabel);
findAllUser = new JButton("\u67E5\u8BE2\u4FE1\u606F");
findAllUser.setBounds(378, 245, 135, 50);
findAllUser.addActionListener(new ActionListener() {
// 查询信息的事件
public void actionPerformed(ActionEvent e) {
DefaultTableModel dtm = (DefaultTableModel) table.getModel();
dtm.setRowCount(0);
try {
List<User> lists = new ArrayList<User>();
Registry registry = LocateRegistry.getRegistry(null);
IUserList stub = (IUserList) registry.lookup("userList");
lists = stub.findAllUser();
for (User user : lists) {
Vector a = new Vector();
a.add(user.getWorkid());
a.add(user.getName());
a.add(user.getSex());
a.add(user.getPhone());
System.out.println(a);
dtm.addRow(a);
System.out.println(lists);
// System.out.println("response: " + response);
}
} catch (Exception e1) {
System.err.println("Client exception: " + e1.toString());
e1.printStackTrace();
}
}
});
table = new JTable();
table.setRowHeight(25);// 设置表格行宽
table.setBounds(5, 47, 690, 160);
table.setFont(new Font("宋体", Font.PLAIN, 20));
table.setBorder(new LineBorder(new Color(0, 0, 0)));// 表格外边框
table.getTableHeader().setFont(new Font("宋体", Font.PLAIN, 20));// 表头字体
// 设置表格中的数据居中显示
DefaultTableCellRenderer tcr = new DefaultTableCellRenderer();// 设置table内容居中
// tcr.setHorizontalAlignment(JLabel.CENTER);
tcr.setHorizontalAlignment(SwingConstants.CENTER);// 这句和上句作用一样
table.setDefaultRenderer(Object.class, tcr);
table.setModel(new DefaultTableModel(
new Object[][] { { null, null, null, null }, { null, null, null, null }, { null, null, null, null },
{ null, null, null, null }, { null, null, null, null }, },
new String[] { "\u5DE5\u53F7", "\u59D3\u540D", "\u6027\u522B", "\u7535\u8BDD" }) {
boolean[] columnEditables = new boolean[] { false, false, false, false };
public boolean isCellEditable(int row, int column) {
return columnEditables[column];
}
});
// 将表格加入滚动窗口
this.setSize(new Dimension(728, 372));
JScrollPane jp = new JScrollPane(table);
jp.setBounds(5, 47, 690, 160);
contentPane = (JPanel) getContentPane();
contentPane.add(jp); // 如果直接将table放入容器ct中,表头不会显示
findAllUser.setFont(new Font("宋体", Font.PLAIN, 20));
contentPane.add(findAllUser);
JButton updateUser = new JButton("\u4FEE\u6539\u4FE1\u606F");
updateUser.setBounds(201, 245, 135, 50);
updateUser.addActionListener(new ActionListener() {
// 修改信息
public void actionPerformed(ActionEvent e) {
// 打开指定的窗口
UpdateUserJDialog updateUser = new UpdateUserJDialog();
updateUser.show();
updateUser.setLocationRelativeTo(null); // 窗体居中显示
}
});
updateUser.setFont(new Font("宋体", Font.PLAIN, 20));
contentPane.add(updateUser);
JButton addUser = new JButton("\u6DFB\u52A0\u7528\u6237");
addUser.setBounds(25, 245, 135, 50);
// 添加信息按钮
addUser.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
// 打开指定的窗口
AddUserJDialog addUser = new AddUserJDialog();
addUser.show();
addUser.setLocationRelativeTo(null); // 窗体居中显示
}
});
addUser.setFont(new Font("宋体", Font.PLAIN, 20));
contentPane.add(addUser);
JButton deleteUser = new JButton("\u5220\u9664\u7528\u6237");
deleteUser.setBounds(551, 245, 135, 50);
deleteUser.addActionListener(new ActionListener() {
// 删除用户
public void actionPerformed(ActionEvent e) {
DeleteUserJDialog deleteUser = new DeleteUserJDialog();
deleteUser.show();
deleteUser.setLocationRelativeTo(null); // 窗体居中显示
}
});
deleteUser.setFont(new Font("宋体", Font.PLAIN, 20));
contentPane.add(deleteUser);
}
private void exit() {
int opt = JOptionPane.showConfirmDialog(this, "确认要退出系统吗?");
if (opt == JOptionPane.YES_OPTION) {
System.exit(0);
}
}
}
6 结语
本实验设计实现一个三层架构的数据通讯程序,后台数据库使用MySQL。界面使用的Windows窗体,中间层、数据服务层使用的Java设计的。
从方法调用角度来看,RMI要解决的问题,是让客户端对远程方法的调用可以相当于对本地方法的调用而屏蔽其中关于远程通信的内容,即使在远程上,也和在本地上是一样的。客户端只与代表远程主机中对象的Stub对象进行通信,丝毫不知道Server的存在。客户端只是调用Stub对象中的本地方法,Stub对象是一个本地对象,它实现了远程对象向外暴露的接口。客户端认为它是调用远程对象的方法,实际上是调用Stub对象中的方法。可以理解为Stub对象是远程对象在本地的一个代理,当客户端调用方法的时候,Stub对象会将调用通过网络传递给远程对象。
文章有不妥的地方,或是有更好的想法和思路,欢迎大家在评论区留言。
声明:
若本人发布的作品涉及版权或存在其他问题,请联系我进行删除。
谢谢浏览!