작업파일 : miniProject(090612)_VideoShop_RMI.zip
서버용 인터페이스 : Server.java
- /*-------------------------------------------------------------------------------------------
* 작성일 : 2009년 6월 10일 ~ 6월 12일(2박 3일), 미니프로젝트 비디오샵 프로그램
* 작성목적 : RMI 기능을 이용한 비디오샵 프로그램을 개발하여 RMI 와 콜백 기능을 익힌다.
* 작성자 : 김지헌 (Honeymon, iammine@korea.com)
*
* 프로그램 구성 :
*
* - 인터페이스 : Server.java, Client.java
* - 실행파일 : ServerImpl.java, ClientImpl.java
*
* 주의사항 :
*
* - 컴파일 후, 실행파일들은 RMIC에 등록작업을 해주어야 한다.
* - 클라이언트 실행시 2개의 파라메터(who = 접속자, server = DB Table 명)를 필요로 한다.
* ex) java ClientImpl 양재 client3
* - 서버와 클라이언트 간에 주고받는 자료는 Vector로 구성된다.
--------------------------------------------------------------------------------------------*/
import java.rmi.*;
import java.util.Vector;
public interface Server extends Remote {
// 공지사항 관련 메소드
public void showNoticeDB() throws RemoteException;
public Vector noticeTitle() throws RemoteException;
public Vector noticeContent() throws RemoteException;
public void broadcastNotice() throws RemoteException;
//인기비디오 관련 메소드
public void showFavoriteVideoDB() throws RemoteException;
public Vector favoriteTitle() throws RemoteException;
public Vector broadcastFavoriteContent() throws RemoteException;
//신작 비디오 관련 메소드
public void showNewVideoDB() throws RemoteException;
public Vector newTitle() throws RemoteException;
public Vector newContent() throws RemoteException;
public void broadcastNewVideo() throws RemoteException; // 신작비디오(본사 등록시 실행)
// 각 지점의 로그인 관리
public void register(Client client, String name) throws RemoteException;
public void unregister(Client client, String name) throws RemoteException;
}
원격객체 : ServerImpl.java
- RMI 등록되고 실행되고 있으면, 원격접속 클라이언트들에게 관련한 작업들 처리해줌
- /*-------------------------------------------------------------------------------------------
* 작성일 : 2009년 6월 10일 ~ 6월 12일(2박 3일), 미니프로젝트 비디오샵 프로그램
* 작성목적 : RMI 기능을 이용한 비디오샵 프로그램을 개발하여 RMI 와 콜백 기능을 익힌다.
* 작성자 : 김지헌 (Honeymon, iammine@korea.com)
*
* 프로그램 구성 :
*
* - 인터페이스 : Server.java, Client.java
* - 실행파일 : ServerImpl.java, ClientImpl.java
*
* 주의사항 :
*
* - 컴파일 후, 실행파일들은 RMIC에 등록작업을 해주어야 한다.
* - 클라이언트 실행시 2개의 파라메터(who = 접속자, server = DB Table 명)를 필요로 한다.
* ex) java ClientImpl 양재 client3
* - 서버와 클라이언트 간에 주고받는 자료는 Vector로 구성된다.
--------------------------------------------------------------------------------------------*/
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SingleSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.DefaultTableModel;
public class ServerImpl extends UnicastRemoteObject implements Server, ActionListener {
private String url = "jdbc:oracle:thin:@61.103.103.184:1521:cjedu";
private String user = "scott";
private String passwd = "tiger";
private DefaultTableModel nmodel, newmodel, fmodel, lmodel;
private Vector ntitle = new Vector();
private Vector ncontent = new Vector();
private Vector newtitle = new Vector();
private Vector newcontent = new Vector();
private Vector ftitle = new Vector();
private Vector fcontent = new Vector();
private Vector ltitle = new Vector();
private Vector lcontent = new Vector();
private Vector clientList = new Vector();
private JTextField ntfield, listTitleTfield, listGenreTfield;
private JButton nwrite, nedit, ndel, listInsert, listDelete, fbutton;
private JComboBox listcbox;
private String who = "관리자";
Connection con;
Statement stat;
private JTable ntable;
private JTextField numtfield;
private JPasswordField pw;
private JButton login;
private JTextField idt;
private CardLayout card;
private JPanel cpane;
private JTable ltable;
public ServerImpl() throws RemoteException {
database();
makeGui();
//창이 닫힐 경우 자원들을 종료하는 Listner
/* addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent x){
try {
Window w = (Window)x.getSource();
w.setVisible(false);
w.dispose();//화면에 썼던 자원을 해지하는것.
close();
System.exit(0); //프로세스 종료
}catch(Exception e){}
}
});*/
}
//DB연결관련 처리
public void database(){
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection( url, user, passwd );
stat = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
} catch( Exception e) {
e.printStackTrace();
}
}
public void makeGui() throws RemoteException{
JFrame frame = new JFrame("Fun Video Company");
frame.pack();
frame.setDefaultCloseOperation(3);
frame.setSize(800,800);
frame.setVisible(true);
final JTabbedPane tab = new JTabbedPane();
frame.add(tab);
//noticePanel
nmodel = new DefaultTableModel();
ntable = new JTable(nmodel);
JScrollPane nspane = new JScrollPane(ntable);
//nmodel.setDataVector(dataVector, columnIdentifiers);
ntable.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent m){
int row = ntable.getSelectedRow();
Vector in = (Vector)ncontent.elementAt(row);
numtfield.setText((String)in.elementAt(0));
ntfield.setText((String)in.elementAt(1));
}
});
//DB 연동해주기.
showNoticeDB();
JLabel numlabel = new JLabel("번호");
numtfield = new JTextField(3);
JLabel nlabel = new JLabel("내용");
ntfield = new JTextField(30);
nwrite = new JButton("작성");
ndel = new JButton("삭제");
nwrite.addActionListener(this);
ndel.addActionListener(this);
JPanel noticePanel = new JPanel();
noticePanel.add(numlabel);
noticePanel.add(numtfield);
noticePanel.add(nlabel);
noticePanel.add(ntfield);
noticePanel.add(nwrite);
noticePanel.add(ndel);
JPanel notice = new JPanel();
notice.setLayout(new BorderLayout());
notice.add(nspane, "Center");
notice.add(noticePanel, "South");
//newVideo Panel
newmodel = new DefaultTableModel();
JTable newtable = new JTable(newmodel);
JScrollPane newspane = new JScrollPane(newtable);
//newmodel.setDataVector(dataVector, columnIdentifiers);
showNewVideoDB();
JPanel newVideo = new JPanel();
newVideo.setLayout(new BorderLayout());
newVideo.add(newspane, "Center");
//favoriteVideo Panel
fmodel = new DefaultTableModel();
JTable ftable = new JTable(fmodel);
JScrollPane fspane = new JScrollPane(ftable);
//fmodel.setDataVector(dataVector, columnIdentifiers);
JPanel favoritePanel = new JPanel();
favoritePanel.setLayout(new BorderLayout());
fbutton = new JButton("집계");
fbutton.addActionListener(this);
favoritePanel.add(fbutton, "East");
JPanel favoriteVideo = new JPanel();
favoriteVideo.setLayout(new BorderLayout());
favoriteVideo.add(fspane, "Center");
favoriteVideo.add(favoritePanel, "South");
//listVideo Panel
lmodel = new DefaultTableModel();
ltable = new JTable(lmodel);
JScrollPane lspane = new JScrollPane(ltable);
//lmodel.setDataVector(dataVector, columnIdentifiers);
showListVideoDB("servervideo");
ltable.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent m){
int row = ltable.getSelectedRow();
Vector in = (Vector)lcontent.elementAt(row);
listTitleTfield.setText((String)in.elementAt(1));
listGenreTfield.setText((String)in.elementAt(2));
}
});
JPanel listPanel = new JPanel();
String data[] = {"본사","양재", "강남", "논현"};
listcbox = new JComboBox(data);
listcbox.addActionListener(this);
JLabel listTitle = new JLabel("제목");
listTitleTfield = new JTextField(30);
JLabel listGenre = new JLabel("장르");
listGenreTfield = new JTextField(10);
listInsert = new JButton("추가");
listInsert.addActionListener(this);
listDelete = new JButton("삭제");
listDelete.addActionListener(this);
listPanel.add(listcbox);
listPanel.add(listTitle);
listPanel.add(listTitleTfield);
listPanel.add(listGenre);
listPanel.add(listGenreTfield);
listPanel.add(listInsert);
listPanel.add(listDelete);
JPanel listVideo = new JPanel();
listVideo.setLayout(new BorderLayout());
listVideo.add(lspane, "Center");
listVideo.add(listPanel, "South");
//tab.add() 1. notice, 2.newViedo 3.favoriteVideo 4.ListVideo
tab.add(notice,"공지사항");
tab.add(newVideo,"신작비디오");
tab.add(favoriteVideo, "인기비디오");
tab.add(listVideo, "비디오목록");
tab.getModel().addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent e) {
SingleSelectionModel model = (SingleSelectionModel) e.getSource();
if(model.getSelectedIndex() == tab.getTabCount()-1) {
}
}
}
);
}
// ------------------------------------------------------------------------------------------- //
// --------------------- showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
public void showNoticeDB() throws RemoteException {
ncontent.clear();
ntitle = noticeTitle();
ncontent = noticeContent();
nmodel.setDataVector(ncontent, ntitle);
}
public Vector noticeTitle() throws RemoteException {
String sql = "SELECT num as 번호, content as 내용, writer as 작성자, TO_CHAR(indate, 'YYYY / MM / DD') as 작성일 FROM notice ORDER BY num desc";
try {
ntitle.clear();
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
ntitle.clear();
for ( int i = 1 ; i <= count ; i++){
String t = rsmd.getColumnName(i);
ntitle.add(t);
}
} catch( Exception e) {
e.printStackTrace();
}
return ntitle;
}
public Vector noticeContent() throws RemoteException {
String sql = "SELECT num, content, writer, TO_CHAR(indate, 'YYYY / MM / DD') FROM notice ORDER BY num desc";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
ncontent.clear();
while( rs.next() ){
Vector in = new Vector();
in.add(rs.getString(1));
in.add(rs.getString(2));
in.add(rs.getString(3));
in.add(rs.getString(4));
ncontent.add(in);
}
rs.close();
} catch( Exception e) {
e.printStackTrace();
}
return ncontent;
}
// --------------------- showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
// ------------------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------------------- //
// --------------------- showNewVideoDB() : 신작 비디오 관련 출력부 ----------------------- //
public void showNewVideoDB(){
newtitle.clear();
newcontent.clear();
newtitle = newTitle();
newcontent = newContent();
newmodel.setDataVector(newcontent, newtitle);
}
public Vector newTitle(){
newtitle.clear();
String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM servervideo ORDER BY indate desc";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
newtitle.clear();
for ( int i = 1; i <= count; i++ ){
String t = rsmd.getColumnName(i);
newtitle.add(t);
}
} catch ( Exception e ){
e.printStackTrace();
}
return newtitle;
}
//신작 비디오의 기준은 입고일 14일 이내의 작품들 : 기간 설정변수 int limitday
public Vector newContent(){
newcontent.clear();
int limitday = 14;
String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM servervideo WHERE indate > sysdate - " + limitday + "ORDER BY indate desc";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
while( rs.next() ){
Vector in = new Vector();
for ( int i = 1; i <= count; i++){
in.add(rs.getString(i));
}
newcontent.add(in);
}
} catch ( Exception e ) {
e.printStackTrace();
}
return newcontent;
}
// --------------------- showNewVideoDB() : 신작 비디오 관련 출력부 ----------------------- //
// ------------------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------------------- //
// --------------------- showFavoriteVideo() : 인기 비디오 관련 출력부 -------------------- //
// ------------------- 집계버튼 클릭시 접속된 모든 클라이언트에 영향을 끼침 ------------------ //
public void showFavoriteVideoDB() throws RemoteException {
ftitle.clear();
ftitle = favoriteTitle();
fcontent = favoriteContent();
fmodel.setDataVector(fcontent, ftitle);
}
public Vector favoriteTitle()throws RemoteException{
ftitle.clear();
ftitle.add("번호");
ftitle.add("제목");
ftitle.add("장르");
ftitle.add("지점");
return ftitle;
}
public Vector favoriteContent() throws RemoteException{
System.out.println("집계 자료를 요청받았음");
fcontent = broadcastFavoriteContent();
System.out.println("집계자료 반납, 가져!!");
return fcontent;
}
// --------------------- showFavoriteVideo() : 인기 비디오 관련 전체 출력부 -------------------- //
// ------------------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------------------- //
// ------------------- showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //
public void showListVideoDB(String shop){
lcontent.clear();
ltitle.clear();
ltitle = listTitle(shop);
lcontent = listContent(shop);
lmodel.setDataVector(lcontent, ltitle);
}
public Vector listTitle(String shop){
if ( shop == "servervideo"){
String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM servervideo ORDER BY indate desc";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
ltitle.clear();
for ( int i = 1 ; i <= count ; i++ ){
String t = rsmd.getColumnName(i);
ltitle.add(t);
}
} catch ( Exception e ){
e.printStackTrace();
}
} else {
String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
for ( int i = 1 ; i <= count ; i++ ){
String t = rsmd.getColumnName(i);
ltitle.add(t);
}
} catch ( Exception e ){
e.printStackTrace();
}
}
return ltitle;
}
public Vector listContent(String shop){
if ( shop == "servervideo") {
String sql = "SELECT id as 번호, title as 제목, sgroup as 장르, TO_CHAR(indate, 'YYYY / MM / DD') as 입고일 FROM " + shop + " ORDER BY indate desc";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
lcontent.clear();
while( rs.next() ){
Vector in = new Vector();
for (int i = 1; i <= count; i++ ){
in.add(rs.getString(i));
}
lcontent.add(in);
}
rs.close();
} catch( Exception e) {
e.printStackTrace();
}
} else {
String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
lcontent.clear();
while( rs.next() ){
Vector in = new Vector();
for (int i = 1; i <= count; i++ ){
in.add(rs.getString(i));
}
lcontent.add(in);
}
rs.close();
} catch( Exception e) {
e.printStackTrace();
}
}
return lcontent;
}
// ------------------- showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //
// ------------------------------------------------------------------------------------------- //
public void broadcastNotice() throws RemoteException{
synchronized(clientList){
Enumeration e = clientList.elements();
while(e.hasMoreElements()) {
Client c = (Client)e.nextElement();
c.showNoticeDB();
}
showNoticeDB();
}
}
public void broadcastNewVideo() throws RemoteException{
synchronized(clientList){
Enumeration e = clientList.elements();
while(e.hasMoreElements()){
Vector in = new Vector();
Client c = (Client)e.nextElement();
c.showNewVideoDB();
}
}
}
// --------------------- showFavoriteVideo() : 인기 비디오 관련 전체 출력부 -------------------- //
// ------------------------------------------------------------------------------------------- //
public Vector broadcastFavoriteContent() throws RemoteException{
fcontent.clear();
synchronized(clientList){
Enumeration e = clientList.elements();
while(e.hasMoreElements()) {
Client c = (Client)e.nextElement();
fcontent.add(c.sendfavoriteContent());
}
}
synchronized(clientList){
Enumeration e = clientList.elements();
while(e.hasMoreElements()) {
Client c = (Client)e.nextElement();
c.showFavoriteVideoDB(fcontent);
}
}
System.out.println("집계처리 완료");
fmodel.setDataVector(fcontent, ftitle);
return fcontent;
}
public synchronized void register(Client client, String name) throws RemoteException{
clientList.add(client);
System.out.println(name + "지점이 접속하였습니다.");
}
public synchronized void unregister(Client client, String name) throws RemoteException{
clientList.removeElement(client);
System.out.println(name + " 지점이 접속을 종료하였습니다.");
}
public void close(){
try {
stat.close();
con.close();
} catch ( Exception e ){
e.printStackTrace();
}
}
@Override
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
if ( o == nwrite ){
noticeInsert();
} else if ( o == ndel ) {
noticeDelete();
}else if ( o == fbutton ){
try {
//broadcastFavorite();
Vector v = broadcastFavoriteContent();
fmodel.setDataVector(v,ftitle );
} catch (RemoteException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} else if ( o == listcbox ){
listShopChange();
} else if ( o == listInsert ){
insertVideo(returnShop());
} else if ( o == listDelete ){
deleteVideo(returnShop());
try {
broadcastNewVideo();
} catch (RemoteException e1) {
e1.printStackTrace();
}
}
}
//notice 관련 Query 처리 : 서버는 추가/삭제 자유롭게, 지점은 추가만 가능
// 서버, 지점 공지사항 추가 가능 가능
public void noticeInsert(){
int num = incrementNum("notice");
String sql = "INSERT INTO notice VALUES(" + num + ", '" + ntfield.getText() + "', sysdate, '" + who + "')";
try {
stat.executeQuery(sql);
} catch( Exception e ){
e.printStackTrace();
}
ntfield.setText("");
try {
showNoticeDB();
broadcastNotice();
} catch ( Exception e ) {
e.printStackTrace();
}
//
}
// 서버에서만 공지사항 삭제 가능 가능
public void noticeDelete(){
String num = numtfield.getText();
String sql = "DELETE notice WHERE num ='" + num + "'";
try {
stat.executeUpdate(sql);
} catch ( Exception e ){
e.printStackTrace();
}
ntfield.setText("");
numtfield.setText("");
try {
showNoticeDB();
broadcastNotice();
} catch ( Exception e ) {
e.printStackTrace();
}
}
//------------------------ 서버에 접속한 클라이언트들 호출하기 ---------------------//
//-------------- listVideo 에서 추가 버튼 눌렀을 때 발생하는 이벤트 --------------//
public void insertVideo(String shop){
String sql = "";
int id = incrementNum(shop);
String name = listTitleTfield.getText();
String genre = listGenreTfield.getText();
if (shop == "servervideo" ){
sql = "INSERT INTO " + shop + " VALUES(" + id + ",'" + name + "','" + genre + "',sysdate)";
} else {
sql = "INSERT INTO " + shop + " VALUES(" + id +", '" + name + "','" + genre +"',0,'대여가능')";
}
try {
stat.executeUpdate(sql);
showListVideoDB(shop);
broadcastNewVideo();
listTitleTfield.setText("");
listGenreTfield.setText("");
} catch ( Exception e ) {
e.printStackTrace();
}
}
//listVideo에서 삭제 버튼을 눌렀을 때 발생하는 이벤트
public void deleteVideo(String shop){
String sql = "";
int id = incrementNum(shop);
String name = listTitleTfield.getText();
String genre = listGenreTfield.getText();
if (shop == "servervideo" ){
sql = "DELETE " + shop + " WHERE title = '" + name + "' AND sgroup = '" + genre +"'";
} else {
sql = "DELETE " + shop + " WHERE name = '" + name + "' AND genre = '" + genre + "'";
}
try {
stat.executeUpdate(sql);
showListVideoDB(shop);
listTitleTfield.setText("");
listGenreTfield.setText("");
} catch ( Exception e ) {
e.printStackTrace();
}
}
//listvideo listcbox 값 변경시 발생되는 이벤트.
public void listShopChange(){
String shop = returnShop();
showListVideoDB(shop);
}
public String returnShop(){
String shop = (String)listcbox.getSelectedItem();
if (shop == "본사"){
shop = "servervideo";
} else if ( shop == "강남") {
shop = "client1";
} else if ( shop == "논현") {
shop = "client2";
} else if ( shop == "양재"){
shop = "client3";
}
return shop;
}
//DB 등록시 최고 번호가 반환됨(조회된 것 + 1);
public int incrementNum(String table){
String sql = "SELECT max(id) FROM " + table;
int num=0;
try {
if( table == "notice") {
sql = "SELECT max(num) FROM " + table;
}
ResultSet rs = stat.executeQuery(sql);
rs.next();
num = rs.getInt(1);
} catch ( Exception e ) {
e.printStackTrace();
}
return num + 1 ;
}
public static void main(String args[]) {
try {
ServerImpl s = new ServerImpl();
Naming.rebind("rmi://61.103.103.184/video",s);
System.out.println("Fun Video Company Server is Ready!!");
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
인터페이스 : Client.java
- /*-------------------------------------------------------------------------------------------
* 작성일 : 2009년 6월 10일 ~ 6월 12일(2박 3일), 미니프로젝트 비디오샵 프로그램
* 작성목적 : RMI 기능을 이용한 비디오샵 프로그램을 개발하여 RMI 와 콜백 기능을 익힌다.
* 작성자 : 김지헌 (Honeymon, iammine@korea.com)
*
* 프로그램 구성 :
*
* - 인터페이스 : Server.java, Client.java
* - 실행파일 : ServerImpl.java, ClientImpl.java
*
* 주의사항 :
*
* - 컴파일 후, 실행파일들은 RMIC에 등록작업을 해주어야 한다.
* - 클라이언트 실행시 2개의 파라메터(who = 접속자, server = DB Table 명)를 필요로 한다.
* ex) java ClientImpl 양재 client3
* - 서버와 클라이언트 간에 주고받는 자료는 Vector로 구성된다.
--------------------------------------------------------------------------------------------*/
import java.rmi.*;
import java.util.Vector;
public interface Client extends Remote {
public void showNoticeDB() throws RemoteException;
public Vector sendfavoriteContent() throws RemoteException;
public void showFavoriteVideoDB(Vector v) throws RemoteException;
public void showNewVideoDB() throws RemoteException;
public void showListVideoDB(String shop) throws RemoteException;
}
원격접속 클라이언트 : ClientImpl.java
- import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.rmi.*;
import java.rmi.server.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SingleSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.DefaultTableModel;
public class ClientImpl implements Client, ActionListener {
private String url = "jdbc:oracle:thin:@61.103.103.184:1521:cjedu";
private String user = "scott";
private String passwd = "tiger";
private DefaultTableModel nmodel, newmodel, fmodel, lmodel;
private Vector ntitle = new Vector();
private Vector ncontent = new Vector();
private Vector newtitle = new Vector();
private Vector newcontent = new Vector();
private Vector ftitle = new Vector();
private Vector fcontent = new Vector();
private Vector ltitle = new Vector();
private Vector lcontent = new Vector();
private JTextField ntfield, listTitleTfield, listGenreTfield;
private JButton nwrite, nedit, ndel, listInsert, listDelete, fbutton, rent, receive;
private JComboBox listcbox;
private String server, selectNum, state, selectNo;
private JTable ntable,ltable;
private JTextField numtfield, idt;
private JPasswordField pw;
private JButton login;
private JPanel cpane;
private int rentcount;
final String who;
Server s;
Connection con;
Statement stat;
private JButton retry;
public ClientImpl(final String who, String server) throws RemoteException {
try {
UnicastRemoteObject.exportObject(this);
s = (Server)Naming.lookup("rmi://61.103.103.184/video");
s.register(this, who);
} catch ( Exception e ) {
e.printStackTrace();
}
this.who = who;
this.server = server;
database();
makeGui();
}
//DB연결관련 처리
public void database(){
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection( url, user, passwd );
stat = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
} catch( Exception e) {
e.printStackTrace();
}
}
public void makeGui() throws RemoteException{
JFrame frame = new JFrame(who + "점 Video SHOP");
frame.pack();
//frame.setDefaultCloseOperation(3);
frame.setSize(800,800);
frame.setVisible(true);
final JTabbedPane tab = new JTabbedPane();
frame.add(tab);
//창이 닫힐 경우 자원들을 종료하는 Listner
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent x){
try {
Window w = (Window)x.getSource();
w.setVisible(false);
w.dispose();//화면에 썼던 자원을 해지하는것.
s.unregister(ClientImpl.this, who);
close();
System.exit(0); //프로세스 종료
}catch(Exception e){}
}
});
//noticePanel
nmodel = new DefaultTableModel();
ntable = new JTable(nmodel);
JScrollPane nspane = new JScrollPane(ntable);
//nmodel.setDataVector(dataVector, coflumnIdentifiers);
//DB 연동해주기.
ntable.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent m){
int row = ntable.getSelectedRow();
Vector in = (Vector)ncontent.elementAt(row);
numtfield.setText((String)in.elementAt(0));
ntfield.setText((String)in.elementAt(1));
}
});
showNoticeDB();
JLabel numlabel = new JLabel("번호");
numtfield = new JTextField(3);
JLabel nlabel = new JLabel("내용");
ntfield = new JTextField(30);
nwrite = new JButton("작성");
nwrite.addActionListener(this);
JPanel noticePanel = new JPanel();
noticePanel.add(numlabel);
noticePanel.add(numtfield);
noticePanel.add(nlabel);
noticePanel.add(ntfield);
noticePanel.add(nwrite);
JPanel notice = new JPanel();
notice.setLayout(new BorderLayout());
notice.add(nspane, "Center");
notice.add(noticePanel, "South");
//newVideo Panel
newmodel = new DefaultTableModel();
JTable newtable = new JTable(newmodel);
JScrollPane newspane = new JScrollPane(newtable);
//newmodel.setDataVector(dataVector, columnIdentifiers);
showNewVideoDB();
JPanel newVideo = new JPanel();
newVideo.setLayout(new BorderLayout());
newVideo.add(newspane, "Center");
//favoriteVideo Panel
fmodel = new DefaultTableModel();
JTable ftable = new JTable(fmodel);
JScrollPane fspane = new JScrollPane(ftable);
//fmodel.setDataVector(dataVector, columnIdentifiers);
JPanel favoritePanel = new JPanel();
favoritePanel.setLayout(new BorderLayout());
fbutton = new JButton("집계");
fbutton.addActionListener(this);
favoritePanel.add(fbutton, "East");
JPanel favoriteVideo = new JPanel();
favoriteVideo.setLayout(new BorderLayout());
favoriteVideo.add(fspane, "Center");
favoriteVideo.add(favoritePanel, "South");
//listVideo Panel
lmodel = new DefaultTableModel();
ltable = new JTable(lmodel);
JScrollPane lspane = new JScrollPane(ltable);
//lmodel.setDataVector(dataVector, columnIdentifiers);
showListVideoDB(server);
ltable.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent m){
int row = ltable.getSelectedRow();
Vector in = (Vector)lcontent.elementAt(row);
selectNum = (String)in.elementAt(0);
rentcount = Integer.parseInt((String)in.elementAt(3));
state = (String)in.elementAt(4);
}
});
JPanel listPanel = new JPanel();
rent = new JButton("대여");
receive = new JButton("반납");
retry = new JButton("다시 읽기");
rent.addActionListener(this);
receive.addActionListener(this);
retry.addActionListener(this);
listPanel.add(rent);
listPanel.add(receive);
listPanel.add(retry);
JPanel listVideo = new JPanel();
listVideo.setLayout(new BorderLayout());
listVideo.add(lspane, "Center");
listVideo.add(listPanel, "South");
//tab.add() 1. notice, 2.newViedo 3.favoriteVideo 4.ListVideo
tab.add(notice,"공지사항");
tab.add(newVideo,"신작비디오");
tab.add(favoriteVideo, "인기비디오");
tab.add(listVideo, "비디오목록");
tab.getModel().addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent e) {
SingleSelectionModel model = (SingleSelectionModel) e.getSource();
if(model.getSelectedIndex() == tab.getTabCount()-1) {
}
}
}
);
}
// ------------------------------------------------------------------------------------------- //
// --------------------- showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
public synchronized void showNoticeDB() throws RemoteException {
ntitle = s.noticeTitle();
ncontent = s.noticeContent();
nmodel.setDataVector(ncontent, ntitle);
}
// --------------------- showNoticeDB() : 공지사항 관련 출력부 ----------------------------- //
// ------------------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------------------- //
// --------------------- showNewVideoDB() : 신작 비디오 관련 출력부 ----------------------- //
public synchronized void showNewVideoDB() throws RemoteException{
try {
newcontent.clear();
newtitle.clear();
newtitle = s.newTitle();
newcontent = s.newContent();
newmodel.setDataVector(newcontent, newtitle);
} catch (Exception e) {
e.printStackTrace();
}
}
// ------------------------------------------------------------------------------------------- //
// --------------------- showFavoriteVideo() : 인기 비디오 관련 출력부 -------------------- //
public void showFavoriteVideoDB(Vector v) throws RemoteException {
//System.out.println("집계된 자료 가져가겠음");
ftitle.clear();
ftitle = s.favoriteTitle();
// System.out.println("집계제목 수신중");
// fcontent = s.favoriteContent();
// System.out.println("집계자료 전송중");
fmodel.setDataVector(v, ftitle);
}
public Vector sendfavoriteContent()throws RemoteException {
fcontent.clear();
String sql = "SELECT id, name, genre FROM " + server + " where rentcount = (SELECT max(rentcount) FROM " + server + ")";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
rs.next();
for ( int i = 1; i <= count ; i++ ){
fcontent.add(rs.getString(i));
}
fcontent.add(who);
} catch (Exception e) {
e.printStackTrace();
}
return fcontent;
}
// --------------------- showFavoriteVideo() : 인기 비디오 관련 출력부 -------------------- //
// ------------------------------------------------------------------------------------------- //
// ------------------------------------------------------------------------------------------- //
// ------------------- showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //
public void showListVideoDB(String shop){
lcontent.clear();
ltitle.clear();
ltitle = listTitle(shop);
lcontent = listContent(shop);
lmodel.setDataVector(lcontent, ltitle);
}
public Vector listTitle(String shop){
String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
for ( int i = 1 ; i <= count ; i++ ){
Vector in = new Vector();
String t = rsmd.getColumnName(i);
in.add(t);
ltitle.add(in);
}
} catch ( Exception e ){
e.printStackTrace();
}
return ltitle;
}
public Vector listContent(String shop){
String sql = "SELECT id as 번호, name as 제목, genre as 장르, rentcount as 대여횟수, state as 대여상태 FROM "+ shop +" ORDER BY rentcount desc";
try {
ResultSet rs = stat.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
int count = rsmd.getColumnCount();
lcontent.clear();
while( rs.next() ){
Vector in = new Vector();
for (int i = 1; i <= count; i++ ){
in.add(rs.getString(i));
}
lcontent.add(in);
}
rs.close();
} catch( Exception e) {
e.printStackTrace();
}
return lcontent;
}
// ------------------- showListVideoDB() : 비디오 리스트 관련 출력부 ------------------------ //
// ------------------------------------------------------------------------------------------- //
//notice 관련 Query 처리 : 서버는 추가/삭제 가능, 지점은 추가만 가능
public void noticeInsert(){
int num = incrementNum("notice");
String sql = "INSERT INTO notice VALUES(" + num + ", '" + ntfield.getText() + "', sysdate, '" + who + "')";
try {
stat.executeQuery(sql);
} catch( Exception e ){
e.printStackTrace();
}
ntfield.setText("");
try {
s.broadcastNotice();
} catch ( Exception e ) {
e.printStackTrace();
}
}
public int incrementNum(String table){
String sql = "SELECT max(id) FROM " + table;
int num=0;
try {
if( table == "notice") {
sql = "SELECT max(num) FROM " + table;
}
ResultSet rs = stat.executeQuery(sql);
rs.next();
num = rs.getInt(1);
} catch ( Exception e ) {
e.printStackTrace();
}
return num + 1 ;
}
public void close(){
try {
stat.close();
con.close();
} catch ( Exception e ){
e.printStackTrace();
}
}
//listVideo에서 대여 버튼을 눌렀을 때 발생하는 이벤트
public void rentVideo(){
if (state.equals("대여가능")){
String sql = "UPDATE " + server + " SET state = '대여중', rentcount = "+ (rentcount + 1) +" WHERE id = "+ selectNum;
try {
stat.executeUpdate(sql);
showListVideoDB(server);
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
//listVideo에서 반납 버튼을 눌렀을 때 발생하는 이벤트
public void receiveVideo(){
if (state.equals("대여중")){
String sql = "UPDATE " + server +" SET state = '대여가능' WHERE id = "+ selectNum;
try {
stat.executeUpdate(sql);
showListVideoDB(server);
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
@Override
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
if ( o == nwrite ){
noticeInsert();
try {
s.broadcastNotice();
} catch (Exception ex){
ex.printStackTrace();
}
}else if ( o == fbutton ){
try {
s.broadcastFavoriteContent();
} catch (RemoteException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
} else if ( o == rent ){
rentVideo();
} else if ( o == receive ){
receiveVideo();
} else if ( o == retry ){
showListVideoDB(server);
}
}
public static void main(String args[]) {
try {
String who = args[0];
String server = args[1];
ClientImpl c = new ClientImpl(who, server);
} catch ( Exception e ) {
e.printStackTrace();
}
}
}
ServerImpl 실행화면
|
ClientImpl 실행화면
|
|
|
제일 어려웠던 부분은, 인기비디오 목록 처리 부분.
처음에는 인기비디오 수집시, synchronized 처리로 인한 락이 걸리면서 작업이 중지되는 현상을 보였다.
이를 해결하기 위해 하나의 메소드 안에서 자료 수집과 뿌려주는 작업을 순차적으로 진행시키도록 하였다.
화면구성 자체는 간결하다.
추후에 유사한 작업을 진행할 때에는, 각 화면별 구성과 컴포넌트들의 이름을 기록하고 이를 구분하기 쉽도록 해야겠다.
스스로 해결하지 못해서, 선생님께 조언을 구했다. 어려울 때 도움을 요청할 수도 있겠지만, 스스로 깊게 사색하고,
문제점을 찾아 해결할 수 있는 능력을 길러보도록 하자. 너는 할 수 있다. ㅡㅅ-)b
이 글은 스프링노트에서 작성되었습니다.