• Home
  • About
    • Young's Github Pages photo

      一日不作一日不食

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

Java 정리 44

17 Jan 2019

Reading time ~4 minutes

Java 정리 44 - 도시락 주문 프로그램(4)


개발

  • 도시락 주문 관리 프로그램 패키지

  • 도시락 수정 시 유효성 검증

public void  modifyLunch() {
        
        // 유효성 검증 : 도시락명, 가격,  특장점이 ""이 아닐 때, 가격은 숫자인지,
        // 이미지가 변경되지 않았는지(변경  안되었다면 다시 올릴 필요가 없음),
        // 변경되었다면 s_가 붙은 이미지가  존재하는 이미지인지 검증(검증 완료 후 업데이트  처리)
        JTextField tfName =  ldv.getJtfLunchName();
        JTextField tfPrice =  ldv.getJtfLunchPrice();
        JTextArea taSpec =  ldv.getJtaLunchSpec();
        
        if(tfName.getText().trim().equals("")) {
            tfName.setText("");
            JOptionPane.showMessageDialog(ldv,  "도시락명을 입력해주세요.");
            tfName.requestFocus();
            return;
        }

        if(tfPrice.getText().trim().equals(""))  {
            tfPrice.setText("");
            JOptionPane.showMessageDialog(ldv,  "도시락의 가격을 입력해주세요.");
            tfPrice.requestFocus();
            return;
        }

        if(taSpec.getText().trim().equals("")) {
            taSpec.setText("");
            JOptionPane.showMessageDialog(ldv,  "도시락의 특장점을 입력해주세요.");
            taSpec.requestFocus();
            return;
        }
        
        int price = 0;
        try {
            price =  Integer.parseInt(tfPrice.getText().trim());
        } catch (NumberFormatException nfe) {
            tfPrice.setText("");
            JOptionPane.showMessageDialog(ldv,  "도시락 가격은 숫자만 입력가능합니다.");
            tfPrice.requestFocus();
            return;
        }
        
        // 선택한 이미지 파일과 접두사 s_를 가진  동일한 이미지파일이 없는 경우
        // ->이미지 작업이 되어있지 않은 경우.  uploadImage를 사용
        if (!uploadImage.equals("")) { // 이미지  변경을 수행한 경우
            File tempFile = new  File(uploadImage); // 큰 이미지
            
            File smallFile = new  File(tempFile.getParent()+"/s_"+tempFile.getName()); // 작은 이미지
            
            if (!smallFile.exists()) {
                JOptionPane.showMessageDialog(ldv, "선택하신  파일은 작은 이미지가 존재하지 않습니다.");
                uploadImage = "";
                return;
            }
        }
    ...
}
  • 다이나믹 쿼리
    • 조건에 따라 다른 쿼리를 작성할 때 쓰임
StringBuilder updateLunch = new StringBuilder();

updateLunch
.append("UPDATE LUNCH ")
.append("SET LUNCH_NAME=?, PRICE=?, SPEC=? ");
if (!luvo.getImg().equals("")) { // 이미지명이 변경되었다면 이미지 업데이트
    updateLunch.append(", IMG=? ");
}
updateLunch.append("WHERE LUNCH_CODE=?");

pstmt =  con.prepareStatement(updateLunch.toString());

pstmt.setString(1, luvo.getLunchName());
pstmt.setInt(2, luvo.getPrice());
pstmt.setString(3, luvo.getSpec());

if (!luvo.getImg().equals("")) {
    pstmt.setString(4, luvo.getImg());
    pstmt.setString(5, luvo.getLunchCode());
} else {
    pstmt.setString(4, luvo.getLunchCode());
}
// 위 pstmt에 값을 넣는 코드는 이렇게 줄일 수 있다.
int index = 4;
if (!luvo.getImg().equals("")) {
    pstmt.setString(index++, luvo.getImg());
}
pstmt.setString(index, luvo.getLunchCode());
  • 중복된 기능을 하는 method들은 utility 패키지를 새로 만들어서 같이 모아 관리하는게 좋음
    • 예를 들어 AddController와 DetailController 둘 다 사용된 uploadImg 메소드
public void uploadImg(File file) throws IOException {
     FileInputStream fis = null;
     FileOutputStream fos = null;
     
     try {
          // 큰 이미지 업로드
          fis = new FileInputStream(file);
          byte[] readData = new byte[512];
          
          int len = 0;
          String uploadPath =  "C:/Users/owner/youngRepositories/SSangYoung/dev/workspace/lunch_prj/src/kr/co/sist/lunch/admin/img/";
          
          fos = new FileOutputStream(new  File(uploadPath+file.getName()));
          
          while((len = fis.read(readData)) != -1) {
              fos.write(readData, 0, len);
              fos.flush();
          }
          
          fis.close();
          fos.close();
          
          // 작은 이미지 업로드
          fis = new  FileInputStream(file.getParent()+"/s_"+file.getName());
          len = 0;
          fos = new FileOutputStream(new  File(uploadPath+"s_"+file.getName()));
          
          while((len = fis.read(readData)) != -1) {
              fos.write(readData, 0, len);
              fos.flush();
          }
          
     } finally {
          if (fis != null) { fis.close(); }
          if (fos != null) { fos.close(); }
     }
}
  • 정산을 위한 쿼리작성
-- 다음과 같은 결과를 보여주는 쿼리를 작성하시오
-- 포크칠리, L_00000001, 총 판매수량 4, 총액 18000
-- 돈가스, L_00000002, 총 판매수량 1, 총액 3800

-- 내가 짠 쿼리
SELECT l.lunch_name, l.lunch_code, quan, o.quan*l.price total
FROM (SELECT lunch_code, sum(quan) quan
      FROM ordering
      GROUP BY lunch_code) o, lunch l
WHERE o.lunch_code = l.lunch_code;

-- 강사님이 짜신 쿼리
SELECT l.lunch_name, l.lunch_code, sum(o.quan) total, sum(o.quan)*l.price price
FROM lunch l, ordering o
WHERE o.lunch_code = l.lunch_code
    AND TO_CHAR(o.order_date, 'yyyy-mm-dd') = TO_CHAR(TO_DATE('2019-1-15', 'yyyy-mm-dd'), 'yyyy-mm-dd')
GROUP BY l.lunch_code, l.lunch_name, l.price
ORDER BY l.lunch_code;

01

  • 자바에서 ‘2019-1-1’형태로 바인드변수가 들어가도 함수를 통해 ‘2019-01-01’형태로 바뀌어야 한다..
    • 따라서 아래와 같은 오라클 함수를 사용하여 형식을 맞춰준다.
"TO_CHAR(TO_DATE(?, 'yyyy-mm-dd'), 'yyyy-mm-dd')"
// ?가 바인드 변수로 '2019-1-1'이 들어가도 '2019-01-01'로 바뀜
  • DB클라이언트에서 쿼리 실행 확인 후 (다 짠 후) 자바에 적용
    • 적용 시 미리 얖 뒤로 공백을 주고 붙여서 사용한다.
    • 자바에선 쿼리 끝에 ‘;’를 꼭 빼야 에러가 안남!
selectCalc
.append(" SELECT l.lunch_name, l.lunch_code, sum(o.quan)  total, sum(o.quan)*l.price price  ")
.append(" FROM lunch l, ordering o     ")
.append(" WHERE o.lunch_code = l.lunch_code ")
.append(" AND TO_CHAR(o.order_date, 'yyyy-mm-dd') =  TO_CHAR(TO_DATE(?, 'yyyy-mm-dd'), 'yyyy-mm-dd') ")
.append(" GROUP BY l.lunch_code, l.lunch_name, l.price     ")
.append(" ORDER BY l.lunch_code;  ");
  • Swing 탭 클릭 이벤트 처리
@Override
public void mouseClicked(MouseEvent me) {
     if (me.getSource() == lmv.getJtb()) { // 탭에서  클릭이 발생했을 때만
          if (lmv.getJtb().getSelectedIndex() == 1) { //  처음 탭에서 이벤트 발생
              System.out.println("------"); // 수행할 내용
          }
     }
}
  • 마우스 우클릭 처리
@Override
public void mouseClicked(MouseEvent me) {
    if (me.getSource() == lmv.getJtOrder() && me.getButton() == MouseEvent.BUTTON3) {
         System.out.println("우클릭");
    }
}
  • 벡터를 이용하여 DefaultTableModel에 값 넣기
OrderVO ovo = null;
Vector<Object> vec = null;
for(int i=0; i<list.size(); i++) {
     ovo = list.get(i);
     vec = new Vector<Object>();
     vec.add(new Integer(i+1));
     vec.add(ovo.getOrderNum());
     vec.add(ovo.getLunchCode());
     vec.add(ovo.getLunchName());
     vec.add(ovo.getOrderName());
     vec.add(new Integer(ovo.getQuan()));
     vec.add(new Integer(ovo.getPrice()));
     vec.add(ovo.getOrderDate());
     vec.add(ovo.getPhone());
     vec.add(ovo.getIpAddress());
     vec.add(ovo.getStatus());
     
     dtmOrder.addRow(vec);
}
  • 우클릭 시 메뉴 컴포넌트를 구현할 땐 JPopupMenu와 JMenuItem을 사용
if (me.getSource() == lmv.getJtOrder() && me.getButton()  == MouseEvent.BUTTON3) {
     JPopupMenu jp = lmv.getJpOrderMenu();
     jp.setLocation(me.getXOnScreen(),  me.getYOnScreen());
     jp.setVisible(true);
} else {
     JPopupMenu jp = lmv.getJpOrderMenu();
     jp.setVisible(false);
}

02

  • 우클릭은 클릭이 아님
    • 따라서 테이블에서 우클릭하면 getSelectRow()를 사용할 수 없는 문제가 발생
    • 마우스 포인터가 클릭되면 테이블에서 클릭한 행을 선택하는 코드
int r = jt.rowAtPoint(me.getPoint()); // jt는 JTable, me는 MouseEvent
if (r >= 0 && r < jt.getRowCount()) {
     jt.setRowSelectionInterval(r, r); // 선택된 행 사이를 선택
} else {
     jt.clearSelection();
}

03



Java