原文連結:https://blog.csdn.net/Sardar_/article/details/78887586
在原文的代碼基礎上
-
優化了異常檢測。
-
增加了線程安全,用vector替代了arraylist
-
優化了代碼結構
也就是加強版,無BUG版本
題目簡介:
主要功能
1) 使用Java RMI建立一個分布式議程共享服務。不同的使用者可以使用這個共享議程服務執行查詢、添加和删除會議的操作。伺服器支援會議的登記和清除等功能;
2) 議程共享服務包括以下功能:使用者注冊、添加會議、查詢會議、删除會議、清除會議;
3) 使用者注冊
新使用者注冊需要填寫使用者名和密碼,如果使用者名已經存在,則注冊失敗并列印提示資訊,否則注冊成功并列印成功提示。使用如下指令進行使用者注冊:
4) 添加會議
已注冊的使用者可以添加會議。會議必須涉及到兩個已注冊的使用者,一個隻涉及單個使用者的會議無法被建立。會議的資訊包括開始時間、結束時間、會議标題、會議參與者。當一個會議被添加之後,它必須出現在建立會議的使用者和參加會議的使用者的議程中。如果一個使用者的新會議與已經存在的會議出現時間重疊,則無法建立會議。最終,使用者收到會議添加結果的提示。使用如下指令進行會議的添加:
5) 查詢會議
已注冊的使用者通過給出特定時間區間(給出開始時間和結束時間)在議程中查詢到所有符合條件的會議記錄。傳回的結果清單按時間排序。在清單中,包括開始時間、結束時間、會議标題、會議參與者等資訊。使用如下指令進行會議的查詢:
6) 删除會議
已注冊的使用者可以根據會議的資訊删除由該使用者建立的會議。使用如下指令進行删除會議操作:
7) 清除會議
已注冊的使用者可以清除所有由該使用者建立的會議。使用如下指令進行清除操作:
使用方法:
1.啟動RMISever
2.啟動RMIClient,輸入指令
項目結構:
package ssd8.rmi.bean;
import java.util.Date;
public class Meeting {
private User sponsor;
private User otheruser;
private Date start;
private Date end;
private String title;
private int id;
public Meeting(User sponsor, User otheruser, Date start, Date end, String title) {
super();
this.sponsor = sponsor;
this.otheruser = otheruser;
this.start = start;
this.end = end;
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public User getSponsor() {
return sponsor;
}
public void setSponsor(User sponsor) {
this.sponsor = sponsor;
}
public User getOtheruser() {
return otheruser;
}
public void setOtheruser(User otheruser) {
this.otheruser = otheruser;
}
public Date getStart() {
return start;
}
public void setStart(Date start) {
this.start = start;
}
public Date getEnd() {
return end;
}
public void setEnd(Date end) {
this.end = end;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
package ssd8.rmi.bean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Vector;
public class User implements Serializable {
private String name;
private String password;
private Vector<Meeting> schedule;
public User(String name, String password) {
super();
this.name = name;
this.password = password;
this.schedule = new Vector<Meeting>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Vector<Meeting> getSchedule() {
return schedule;
}
}
package ssd8.rmi.interface_rmi;
import java.rmi.Remote;
import java.text.ParseException;
/**
* 遠端接口必須擴充接口java.rmi.Remote
* @author Sarda
*/
public interface RMIInterface extends Remote {
/**
* 注冊使用者
* 如果使用者名存在,傳回false,否則注冊新使用者,傳回true
*/
public boolean register(String name, String password)throws java.rmi.RemoteException;
/**
* 添加新會議
* 賬号密碼不正确,傳回0
* 會議發起者和參與者是同一個使用者,傳回-1
* 會議參與者沒有注冊,傳回-2
* 會議時間與發起者時間沖突,傳回-3
* 會議時間與參與者時間沖突,傳回-4
* 添加成功,傳回1
* @throws ParseException
*/
public int addMeeting(String name, String password, String start, String end, String title, String otherusername)throws java.rmi.RemoteException, ParseException;
/**
* 查詢相應時間段内是否有會議
* 賬号密碼不正确,傳回null
* 查詢成功,傳回查詢内容
* @throws ParseException
*/
public String[][] search(String name, String password, String start, String end)throws java.rmi.RemoteException, ParseException;
/**
* 删除使用者發起的某一個會議
* @param name
* @param password
* @param id 會議的ID
* @return 賬号密碼錯誤傳回false,添加成功,傳回true
* @throws java.rmi.RemoteException
*/
public boolean delete(String name, String password, int id)throws java.rmi.RemoteException;
/**
* 清除使用者發起的所有會議
* @param name
* @param password
* @return 賬号密碼錯誤傳回false,清除成功,傳回true
* @throws java.rmi.RemoteException
*/
public boolean clear(String name, String password)throws java.rmi.RemoteException;
}
package ssd8.rmi.service_rmi;
import ssd8.rmi.bean.Meeting;
import ssd8.rmi.bean.User;
import ssd8.rmi.interface_rmi.RMIInterface;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;
/**
* 擴充UnicastRemoteObject類,并實作遠端接口RMIInterface
*
* @author The Great Ke
*
*/
public class RMIService extends UnicastRemoteObject implements RMIInterface {
/**
*
*/
private static final long serialVersionUID = 1L;
private String status = "0000";
private int id = 0;
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//private List<User> userList = new ArrayList<User>(); 棄用,線程不安全的。
private Vector<User> userVector = new Vector<>(); // 保證線程安全。 hash_table,con
// private List<Meeting> meetingList = new ArrayList<Meeting>(); 棄用,線程不安全的。
private Vector<Meeting> meetingVector = new Vector<>();// 保證線程安全。 hash_table,con
/**
* 必須定義構造方法,即使是預設構造方法,也必須把它明确地寫出來,因為它必須抛出出RemoteException異常
*/
public RMIService() throws RemoteException {
}
/**
* 遠端接口方法的實作
*/
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public boolean register(String name, String password) throws RemoteException {
if(exist(name)){
return false;
}
userVector.add(new User(name, password));
return true;
}
/**
* 檢查使用者是否已注冊
* @param name
* @return
*/
private boolean exist(String name) {
for (User u : userVector) {
if(u.getName().equals(name)) {
return true;
}
}
return false;
}
@Override
public int addMeeting(String name, String password, String startTime, String endTime,
String title, String otherusername)
throws RemoteException, ParseException {
User sponsor = findUser(name);
User otheruser = findUser(otherusername);
Date start = sdf.parse(startTime);
Date end = sdf.parse(endTime);
if(!checkUser(name, password)) return 0;
if(name == otherusername) return -1;
if(!exist(otherusername)) return -2;
if(overlap(sponsor, start, end)) return -3;
if(overlap(otheruser, start, end)) return -4;
Meeting meeting = new Meeting(sponsor, otheruser, start, end, title);
meeting.setId(id++);
meetingVector.add(meeting);
sponsor.getSchedule().add(meeting);
otheruser.getSchedule().add(meeting);
return 1;
}
/**
* 檢查時間是否與已經存在的會議出現時間重疊
* @param user
* @param start
* @param end
* @return
*/
private boolean overlap(User user, Date start, Date end) {
if(user.getSchedule().size()==0) {
return false;
}
for (Meeting meeting : user.getSchedule())
if(max(meeting.getStart(),start).compareTo(min(meeting.getEnd(),end))<=0)
return true;
return false;
}
private Date max(Date start, Date start2) {
if(start.after(start2)) {
return start;
}else {
return start2;
}
}
private Date min(Date end, Date end2) {
if(end.before(end2)) {
return end;
}else {
return end2;
}
}
@Override
public String[][] search(String name, String password, String startTime, String endTime)
throws RemoteException, ParseException {
if(!checkUser(name, password)) return null;
User user = findUser(name);
Date start = sdf.parse(startTime);
Date end = sdf.parse(endTime);
//ArrayList<Meeting> list = new ArrayList<Meeting>();
Vector<Meeting> list = new Vector<>();
for (Meeting meeting : meetingVector) {
if(meeting.getStart().compareTo(start)>=0&&meeting.getStart().before(end)) {
list.add(meeting);
}
}
sort(list);
int n = list==null?0:list.size();
String[][] s = new String[n][5];
for(int j=0; j<list.size(); j++) {
s[j][0] = String.valueOf(list.get(j).getId());
s[j][1] = sdf.format(list.get(j).getStart());
s[j][2] = sdf.format(list.get(j).getEnd());
s[j][3] = list.get(j).getTitle();
s[j][4] = list.get(j).getSponsor().getName() + ", " + list.get(j).getOtheruser().getName();
}
return s;
}
/**
* 會議按開始時間升序排序
* @param list
*/
private void sort(Vector<Meeting> list) {
for(int i=0; i<list.size(); i++) {
for(int j=i; j<list.size(); j++) {
if(list.get(j).getStart().before(list.get(i).getStart())) {
swap(list.get(j),list.get(i));
}
}
}
}
/**
* 交換兩個會議内容
* @param m1
* @param m2
*/
private void swap(Meeting m1, Meeting m2) {
User user = m1.getSponsor();
m1.setSponsor(m2.getSponsor());
m2.setSponsor(user);
user = m1.getOtheruser();
m1.setOtheruser(m2.getOtheruser());
m2.setOtheruser(user);
Date date = m1.getStart();
m1.setStart(m2.getStart());
m2.setStart(date);
date = m1.getEnd();
m1.setEnd(m2.getEnd());
m2.setEnd(date);
String title = m1.getTitle();
m1.setTitle(m2.getTitle());
m2.setTitle(title);
}
@Override
public boolean delete(String name, String password, int id) throws RemoteException {
if(!checkUser(name, password)) return false;
User user = findUser(name);
for (int i = 0; i < meetingVector.size(); i++) {
if(meetingVector.get(i).getSponsor().equals(user) && meetingVector.get(i).getId() == id) {
meetingVector.get(i).getSponsor().getSchedule().remove(meetingVector.get(i));
meetingVector.get(i).getOtheruser().getSchedule().remove(meetingVector.get(i));
meetingVector.remove(meetingVector.get(i));
return true;
}
}
return false;
}
@Override
public boolean clear(String name, String password) throws RemoteException {
if(!checkUser(name, password)) return false;
int flag = 0;
User user = findUser(name);
Vector<Meeting> m = new Vector<Meeting>();
for (Meeting meeting : meetingVector) {
if(meeting.getSponsor().equals(user)) {
m.add(meeting);
}
}
for (Meeting meeting : m) {
meetingVector.remove(meeting);
flag = 1;
}
if(flag == 0) {
return false;
}else {
return true;
}
}
/**
* 按使用者名查找使用者
* @param name
* @return
* @throws RemoteException
*/
public User findUser(String name) throws RemoteException {
for (User u : userVector) {
if(u.getName().equals(name))
return u;
}
return null;
}
/**
* 檢查使用者輸入的賬号密碼是否正确
* @param name
* @param password
* @return
*/
private boolean checkUser(String name, String password) {
for (User u : userVector) {
if(u.getName().equals(name)&&u.getPassword().equals(password))
return true;
}
return false;
}
}
package ssd8.rmi;
import ssd8.rmi.interface_rmi.RMIInterface;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class RMIClient {
public static void main(String[] argv) throws RemoteException, NotBoundException, MalformedURLException {
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
RMIInterface rmi_interface = (RMIInterface) Naming.lookup("HelloRMI");
// 如果要從另一台啟動了RMI注冊服務的機器上查找hello執行個體
// HelloInterface hello =
// (HelloInterface)Naming.lookup("//192.168.1.105:1099/Hello");
//控制台輸入提示
System.out.println("RMI Menu:");
System.out.println("\t1. register");
System.out.println("\t2. add");
System.out.println("\t3. query");
System.out.println("\t4. delete");
System.out.println("\t5. clear");
while(true){
try {
String request = keyboard.readLine();
//注冊使用者
if(request.startsWith("regist")){
System.out.println("請輸入使用者名和密碼(用逗号隔開)");
String r = keyboard.readLine();
String[] s = r.split(",", 2);
String name = s[0];
String password = s[1];
if(rmi_interface.register(name, password)) {
System.out.println("注冊成功!");
}else {
System.out.println("注冊失敗!");
}
//添加會議
}else if(request.startsWith("add")){
System.out.println("請輸入使用者名,密碼,會議開始時間,會議結束時間,會議标題,會議參與者姓名(用逗号隔開)");
String r = keyboard.readLine();
String[] s = r.split(",", 6);
String name = s[0];
String password = s[1];
String start = s[2];
String end = s[3];
String title = s[4];
String otherusername = s[5];
int i = rmi_interface.addMeeting(name, password, start, end, title, otherusername);
switch (i) {
case 0:
System.out.println("使用者名或密碼錯誤!");
break;
case -1:
System.out.println("使用者名未注冊!");
break;
case -2:
System.out.println("會議參與者未注冊!");
break;
case -3:
System.out.println("使用者時間沖突!");
break;
case -4:
System.out.println("會議參與者時間沖突!");
break;
case 1:
System.out.println("添加會議成功!");
break;
default:
break;
}
//查詢會議
}else if(request.startsWith("query")){
System.out.println("請輸入使用者名,密碼,開始時間,結束時間(用逗号隔開)");
String r = keyboard.readLine();
String[] s = r.split(",", 4);
String name = s[0];
String password = s[1];
String start = s[2];
String end = s[3];
String[][] list = rmi_interface.search(name, password, start, end);
if(list != null) {
for (String[] i : list) {
System.out.print("ID: "+ i[0] + " ");
System.out.print("開始時間: "+ i[1] + " ");
System.out.print("結束時間: "+ i[2] + " ");
System.out.print("标題: "+ i[3] + " ");
System.out.print("參與者: "+ i[4] + " ");
System.out.println();
}
}else {
System.out.println("查詢失敗!");
}
//删除會議
}else if(request.startsWith("delete")){
System.out.println("請輸入使用者名,密碼,id(用逗号隔開)");
String r = keyboard.readLine();
String[] s = r.split(",", 3);
String name = s[0];
String password = s[1];
int id = Integer.parseInt(s[2]);
if(rmi_interface.delete(name, password, id)) {
System.out.println("删除成功!");
}else {
System.out.println("删除失敗!");
}
//清除會議
}else if(request.startsWith("clear")){
System.out.println("請輸入使用者名,密碼(用逗号隔開)");
String r = keyboard.readLine();
String[] s = r.split(",", 2);
String name = s[0];
String password = s[1];
if(rmi_interface.clear(name, password)) {
System.out.println("清除成功!");
}else {
System.out.println("清除失敗!");
}
}else{
System.out.println("bad request!");
}
}
catch (Exception e) {
System.out.println("RMIClient exception: " + e + "請糾錯後重新輸入");
}
}
}
}
package ssd8.rmi;
import ssd8.rmi.interface_rmi.RMIInterface;
import ssd8.rmi.service_rmi.RMIService;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
/**
* RMI Hello Server
*
* @author The Great Ke
*
*/
public class RMIServer {
/**
* 啟動 RMI 注冊服務并進行對象注冊
*/
public static void main(String[] args) {
try {
// 啟動RMI注冊服務,指定端口為1099 (1099為預設端口)
// 也可以通過指令 $java_home/bin/rmiregistry 1099啟動
// 這裡用這種方式避免了再打開一個DOS視窗
// 而且用指令rmiregistry啟動注冊服務還必須事先用RMIC生成一個stub類為它所用
LocateRegistry.createRegistry(1099);
// 建立遠端對象的一個或多個執行個體,下面是hello對象
// 可以用不同名字注冊不同的執行個體
RMIInterface hello_rmi = new RMIService();
// 把hello注冊到RMI注冊伺服器上,命名為Hello
Naming.rebind("HelloRMI", hello_rmi);
// 如果要把hello執行個體注冊到另一台啟動了RMI注冊服務的機器上
// Naming.rebind("//192.168.1.105:1099/Hello",hello_rmi);
System.out.println("Hello_rmi Server is ready.");
} catch (Exception e) {
System.out.println("Hello_rmi Server failed: " + e);
}
}
}
運作測試輸入截圖:
輸入部分: 可直接粘接輸入
add
zhouke,123,1999-05-09 14:00:00,1999-05-09 16:00:00,title,afei
zhouke,123,1999-05-09 15:00:00,1999-05-09 15:30:00,title_02,afei //沖突
zhouke,123,1999-05-09 17:00:00,1999-05-09 17:30:00,title_03,afei //不沖突
query
zhouke,123,1999-05-09 12:00:00,1999-05-09 19:30:00
afei,123,1999-05-09 12:00:00,1999-05-09 19:30:00
delete
zhouke,123,0 //成功 會議的建立者才有權限删除這個會議
afei,123,0 //失敗,afei是參與者沒權限
clear
zhouke,123