• Home
  • About
    • Young's Github Pages photo

      一日不作一日不食

    • About
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

Java 정리 46

21 Jan 2019

Reading time ~3 minutes

Java 정리 46 - 도시락 주문 프로그램(6), 데이터를 전달하는 방식


개발

  • 핵심 기능 구현 완료..
  • 도시락 주문 관리 프로그램 패키지

  • 완성된 클래스다이어그램 01

  • Thread로 서버측에서 클라이언트 주문을 읽기
    • 서버측에서 DB내용을 계속 읽어들이면 변경 내용을 바로 JTable에 표현가능
      • 다만 부하가 많이 발생
      • Thread.sleep()을 사용하여 일정시간마다 갱신하는 방법을 사용가능
    • 또는 소켓으로 데이터를 받으면 갱신하는 방법도 가능
      • read()메소드는 무한루프에 있더라도 읽어들일 내용이 있을때만 동작
      • 부하가 적다.
// LunchMainController, Runnable을 implements

@Override
public void run() {
     // 30초마다 한번씩 조회를 수행
     try {
          while (true) {
              searchOrder();
              Thread.sleep(1000 * 30);
          }
     } catch (InterruptedException e) {
          JOptionPane.showMessageDialog(lmv, "조회 중  문제가 발생");
          e.printStackTrace();
     }
}

...

@Override
public void mouseClicked(MouseEvent me) {
     if (me.getSource() == lmv.getJtb()) { // 탭에서  클릭이 발생했을 때만
          if (lmv.getJtb().getSelectedIndex() == 1) { //  두번째 탭(주문)에서 이벤트 발생
              // 실시간으로 DB를 조회하여 주문현황을  갱신
              if (threadOrdering == null) {
                   threadOrdering = new Thread(this);
                   threadOrdering.start();
              }
          }
     }
...
  • 클라이언트 주문 목록 조회를 프로시저로 구현
    • Out Parameter로 커서를 전달할 땐 SYS_REFCURSOR 사용
-- procedure lunch_order_select.sql

CREATE OR REPLACE PROCEDURE lunch_order_select(
    i_order_name IN VARCHAR2,
    i_phone IN VARCHAR2,
    cur_order_list OUT SYS_REFCURSOR
)
IS                                           

BEGIN                                        

    OPEN cur_order_list FOR
        SELECT l.lunch_name,
            TO_CHAR(o.order_date, 'yyyy-mm-dd day hh24:mi:ss') order_date,
             o.quan
        FROM ordering o, lunch l
        WHERE l.lunch_code = o.lunch_code
         AND o.order_name=i_order_name AND o.phone=i_phone
        ORDER BY o.order_date DESC;

END;
/

02

03

  • 자바에서 프로시저를 사용할 땐 CallableStatement를 사용
// LunchClientDAO
...
public List<OrderListVO> selectOrder(OrderInfoVO oivo)  throws SQLException {
     List<OrderListVO> list = new  ArrayList<OrderListVO>();
     
     Connection con = null;
     CallableStatement cstmt = null;
     ResultSet rs = null;
     
     try {
          
          con = getConn();
          cstmt = con.prepareCall(" { call  lunch_order_select(?,?,?) }");
          // in parameter : 외부 값을 프로시저 안으로  넣을 때
          cstmt.setString(1, oivo.getOrderName());
          cstmt.setString(2, oivo.getOrderTel());
          // out parameter : 프로시저 내부 값을 외부에서  받을 때
          cstmt.registerOutParameter(3,  OracleTypes.CURSOR);
          
          cstmt.execute();
          
          rs = (ResultSet)cstmt.getObject(3);
          
          OrderListVO olvo = null;
          while(rs.next()) {
              olvo = new  OrderListVO(rs.getString("lunch_name"),
                        rs.getString("order_date"),  rs.getInt("quan"));
              System.out.println(olvo);
              list.add(olvo);
          }
          
     } finally {
          if (rs != null) { rs.close(); }
          if (cstmt != null) { cstmt.close(); }
          if (con != null) { con.close(); }
     }
     return list;
}
...
  • 접두사, 접미사가 정해진 파일을 한정지을 땐 contains말고 startsWith나 endsWith를 사용한다!
private String[] lunchImageList() {
     String[] fileList = null;
     String path =  "C:/Users/owner/youngRepositories/SSangYoung/dev/workspace/lunch_prj/src/kr/co/sist/lunch/user/img/";
     File dir = new File(path);

     // 큰 이미지(s_가 붙지 않은)만 배열에 넣으세요.
     List<String> listFileName = new ArrayList<String>();
     for(String f_name : dir.list()) {
          if (!f_name.startsWith("s_")) { // contains사용하면 위험!!!
              listFileName.add(f_name);
          }
     }
     
     fileList = new String[listFileName.size()];
     listFileName.toArray(fileList);
     
     return fileList;
}
  • 서버에 도시락 추가 시 클라이언트가 가지지 않은 이미지 파일을 전송하는 기능이 필요

04

  • 도시락 프로그램은 2 Tier 구조
    • DB 서버 - 서버
    • DB 서버 - 클라이언트
  • 메뉴를 추가하면 추가된 이미지가 서버에만 추가됨
    • 클라이언트에서 서버에 이미지명 배열을 보내면 서버가 없는 파일을 판단 후 파일로 전달
    • 클라이언트와 서버에 Tier가 추가되어 n Tier 구조가 된다.

05

  • 웹에선 DB 서버- Web 서버 - Web 클라이언트 3 Tier 구조가 일반적
    • DB서버와 Web 서버 사이에 Middleware가 들어가 n Tier 구조가 될 수 있음

06

데이터를 전달하는 방식

  • Server Push
    • 서버가 모든 클라이언트에게 발생된 데이터를 보내주는 방식
      • 클라이언트는 가만히 있어도 데이터가 갱신된다
      • 단점은 서버가 모든 클라이언트를 관리해야 함
        • 자원 소모가 심함(웹에선 불가능)
  • Client Pull
    • 클라이언트가 서버로 데이터를 요청하여 변경된 데이터를 받는 방식
    • 서버가 클라이언트를 관리할 필요가 없다.
  • 도시락앱에선 이미지명을 담은 배열을 서버에 보내 Client Pull 수행
    • 서버
      • LunchAdminMain
        • 서버가 시작되자마자 서버가 가진 이미지파일목록을 static list변수에 저장하고 FileServer Thread를 실행시킨다.
      • FileServer
        • FileServer는 접속한 클라이언트가 있으면 클라이언트가 보내온 이미지파일목록과 비교하여 없는 파일을 보내주는 Thread
    • 클라이언트 LunchClientController
      • 클라이언트는 이벤트객체가 생성되면서 현재 이미지파일목록을 서버에 전송하고 없는 파일을 전달받는다.
  • 다시 정리
    • 서버는 시작되면서 static list변수로 현재 가진 이미지파일목록을 저장
    • 클라이언트는 시작하면 자신이 가진 이미지파일목록을 서버에 전달
    • 서버는 클라이언트가 보낸 목록과 static변수와 비교, 없는 파일의 수를 클라이언트에게 전달
      • 클라이언트가 가지지 않은 파일명과 파일조각(바이트배열)을 파일의 수만큼 반복해서 서버는 전송, 클라이언트는 전달 받는다.


Java