메모장

JDBC - MVC패턴으로 만들기(웹크롤링) 본문

DB/개념정리

JDBC - MVC패턴으로 만들기(웹크롤링)

Itchild 2024. 4. 10. 22:18
728x90
반응형

 

영화 제목과 개봉일을 웹 크롤링 하여 데이터베이스를 확보하고

JDBC작업을 하여 그것을 MVC 패턴에 맞게 나눠보자 !

 

일단 Model부분에 중요한 내용이 많으므로 controller 와 view의 코드를 먼저 살펴보자

Controller

package controller;

import java.util.ArrayList;

import model.Crawling;
import model.MovieDAO;
import model.MovieVO;
import view.View;

public class Controller {

	private MovieDAO mDAO;
	private View view;
	public Controller() {
		mDAO=new MovieDAO();
		view=new View();
	}

	public void startApp() {
		
		view.printMenu();

		ArrayList<MovieVO> mdatas=Crawling.sample(); //크롤링한 샘플을 배열리스트에 저장한다.
		// Q. 배열리스트를 받아오는데, insert()를 그럼 1번하나요? 라고 생각할수 있음
		// A. NO! insert()를 배열리스트.size()만큼 for문(반복) 돌려야 한다.
		for(int i=0;i<mdatas.size();i++) { // 데이터 사이즈만큼
			MovieVO mdata=mdatas.get(i); // 정보들을 담는다.
			boolean flag=mDAO.insert(mdata); //정보 추가 // boolean 타입이라 flag
			if(!flag) { // false일시
				view.printFalse();
				return;
			}
		}

		view.printTrue(); // 안거치고 내려오면 성공
		 

		// selectAll 전체출력
		MovieVO mVO=new MovieVO(0,"",null); // 빈칸으로 넘기기 ""
		ArrayList<MovieVO> mdatas2=mDAO.selectAll(mVO); // %% 일시 전체 출력이므로 
                                                        // 검색과 전체 출력을 합쳐볼수 있다.
		view.printMovieList(mdatas2);// 목록을 출력해준다.


		// selectOne 하나 출력
		int num1=view.getNum(); // 숫자를 사용자에게 받아서 뷰가 넘겨준다.
		MovieVO mVO1=new MovieVO(num1,null,null); // 모델에게 보낼때 PK를 넘겨줌  
		MovieVO mdata1=mDAO.selectOne(mVO1); // 사용자에게 받은 번호 자리 영화를 불러와 
		view.printMovie(mdata1); // 영화를 출력해준다.


		// delete 삭제하기 
		int num2=view.getNum(); // 사용자에게 번호를 받아 
		MovieVO mVO2=new MovieVO(num2,null,null); // pk로 넘겨줘 
		boolean flag2=mDAO.delete(mVO2); // 삭제는 boolean 타입이라 flag 써줘 
		if(flag2) { // true 
			view.printTrue();
		}
		else { // false
			view.printFalse();
		}

		
		// update 영화 번호 받고 이름 받아서 그 해당하는 번호의 영화 이름 바꿔줘 
		int num3=view.getNum(); // 번호를 받아 
		String name3=view.getName(); // 이름도 입력 받아 
		MovieVO mVO3=new MovieVO(num3,name3,null); // 넘겨줘 모델로 
		boolean flag3=mDAO.update(mVO3); //선택한 영화 번호의 이름을 뭘로 바꾸고 싶어 ? 바꿔줘 
		if(flag3) { // true
			view.printTrue();
		}
		else { // false
			view.printFalse();
		}

	
		// selectAll 이름 검색 
		String name4=view.getName(); // 이름을 입력받아줘 
		MovieVO mVO4=new MovieVO(0,name4,null); // 이름 부분에 받아서 모델로 넘겨줄게 
		ArrayList<MovieVO> mdatas4=mDAO.selectAll(mVO4); // 검색에 해당하는 단어 목록 출력받았어 
		view.printMovieList(mdatas4); // 목록 출력 해줘 

	}
}
 

컨트롤러 부분에서는 정확히 입력메뉴를 구분하여 만들지 않았고 구현만 될 수 있도록 만들어 놓았다 .

 

View

package view;

import java.util.ArrayList;
import java.util.Scanner;

import model.MovieVO;

public class View {

	private static Scanner sc=new Scanner(System.in);
	
	public String getName() {
		System.out.println("영화의 이름을 입력하세요.");
		System.out.print("입력) ");
		String name=sc.nextLine();
		return name;
	}
	public int getNum() {
		System.out.println("영화의 번호를 입력하세요.");
		System.out.print("입력) ");
		int num=sc.nextInt();
		sc.nextLine();
		return num;
	}
	public void printMovie(MovieVO mVO) {
		System.out.println("=== 영 화 정 보 ===");
		if(mVO==null) {
			System.out.println("없음!");
			return;
		}
		System.out.println(mVO);
	}
	
	public void printMenu() {
		System.out.println("영화 프로그램입니다.");
		System.out.println("샘플 데이터를 크롤링합니다...");
	}
	
	public void printTrue() {
		System.out.println("작업 성공!");
	}
	public void printFalse() {
		System.out.println("작업 실패.....");
	}
	
	public void printMovieList(ArrayList<MovieVO> mdatas) {
		System.out.println("=== 영 화 목 록 ===");
		if(mdatas.size()==0) {
			System.out.println("없음!");
			return;
		}
		for(MovieVO mdata:mdatas) {
			System.out.println(mdata);
		}
	}
}
 

View 부분도 최소 필요한 부분만 만들어 놓았다 .


오늘의 중요한 부분 Model 파트

먼저 , Crawling

package model;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

//멤버변수 없이 메서드만 존재하는 클래스
//존재이유 : 메서드 실행이 목적이다. 이런 클래스들은 보편적으로 static 이 붙는다.
public class Crawling {

	public static ArrayList<MovieVO> sample() {
		final String url = "http://www.cgv.co.kr/movies/?lt=1&ft=0";
		Connection conn = Jsoup.connect(url);
		Document doc = null;
		try {
			doc = conn.get();
		} catch (IOException e) {
			e.printStackTrace();
		}

		Elements elems = doc.select("strong.title");
		Elements elems2 = doc.select("span.txt-info");

		Iterator<Element> itr = elems.iterator();
		Iterator<Element> itr2 = elems2.iterator();

		//////////////////////////////
		ArrayList<MovieVO> mdatas=new ArrayList<MovieVO>();
		//////////////////////////////

		while(itr.hasNext()) {
			String str = itr.next().toString();
			String str2 = itr2.next().toString();

			int index = str.indexOf(">");
			str = str.substring(index+1);
			index = str.indexOf("<");
			str = str.substring(0, index);

			int index2 = str2.indexOf("<strong>");
			str2 = str2.substring(index2+9);
			index2 = str2.indexOf("<span>");
			str2 = str2.substring(0, index2);

			mdatas.add(new MovieVO(0,str,str2));
		}

		return mdatas;
	}
}
 

MovieVO

package model;

public class MovieVO {
   private int num;
   private String name;
   private String odate;
   public MovieVO(int num,String name,String odate) {
      this.num=num;
      this.name=name;
      this.odate=odate;
   }
   public int getNum() {
      return num;
   }
   public void setNum(int num) {
      this.num = num;
   }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getOdate() {
      return odate;
   }
   public void setOdate(String odate) {
      this.odate = odate;
   }
   @Override
   public String toString() {
      return this.num+". "+this.name+" ["+this.odate+"]";
   }
}
 

별도의 class를 하나 더 만들어서 캡슐화 해주기

JDBCUtil

오늘의 중요한 부분

package model;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

// 반복해서 사용하는 
//JDBC와 관련된 1번 드라이버 load부분 ,2번 connection 확보 부분 => connect()
//4.DB연결 해제 부분 => disconnect()  < 이 세가지 코드를 "모듈화" >
//-> 별도의 클래스로 캡슐화하는 것이 더 유리함!

//-> 공통의 로직을 모듈화한 클래스
// == Util 클래스

// 장점
//  : 유지보수 용이
//  : 코드 재사용성이 증가
//  : 중복코드 최소화
//  : 오류의 파급효과 줄어듦
//  : 개발 시간,비용 단축
//  : 영업이익증가
public class JDBCUtil {
// 상단에서 상수화 시켜주기 
   static final String driverName_MySQL="com.mysql.cj.jdbc.Driver";
   static final String driverName_Oracle="oracle.jdbc.driver.OracleDriver";
   static final String url_MySQL="jdbc:mysql://localhost/hong";
   static final String url_Oracle="jdbc:oracle:thin:@localhost:1521:xe";
   static final String userName="root";
   static final String passwd="1234";

   public static Connection connect() {
      Connection conn=null;
      try {
         Class.forName(driverName_MySQL);
      } catch (ClassNotFoundException e) {
         e.printStackTrace();
      }

      try {
         conn=DriverManager.getConnection(url_MySQL, userName, passwd);
      } catch (SQLException e) {
         e.printStackTrace();
      }

      return conn;
   }

   public static void disconnect(Statement stmt,Connection conn) {
      try { // UPDATE,DELETE,INSERT
         stmt.close();
         conn.close();
      } catch (SQLException e) {
         e.printStackTrace();
      }
   }
   public static void disconnect(ResultSet rs,Statement stmt,Connection conn) {
      try { // SELECTALL, SELECTONE  // 메서드를 오버로딩 해준다 
         rs.close(); // SELECT 같은 쿼리류 에서는 받아올 것이 있어서 ResultSet을 써줘야 한다.
         stmt.close(); // jsoup의 element 같은 역할을 하는 친구
         conn.close();
      } catch (SQLException e) {
         e.printStackTrace();
      }
   }

}
 

MovieDAO

package model;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;



// JDBC와 관련된 1,2 => connect()
// 4. 코드를 "모듈화" => disconnect()
// -> 별도의 클래스로 캡슐화 하는것이 더 유리함 !

//  공통의 로직을 모듈화 한 클래스를 부르는말  == Util 클래스 

public class MovieDAO {

	private Connection conn; // 자주쓰이는 것을 상단에 선언
	private Statement stmt;
	private ResultSet rs;

	// Q. 크롤링 할 때 배열리스트를 받아오는데,insert()를 그럼 1번하나요?
	// A. NO! insert()를 배열리스트.size()만큼 for문(반복) 돌린다.

	public boolean insert(MovieVO mVO) {
		conn=JDBCUtil.connect(); // conn 연결을 확보해줘 1,2번

		final String sql_INSERT="INSERT INTO MOVIE (NAME,ODATE) VALUES('"+mVO.getName()+"','"+mVO.getOdate()+"');";
		try {                  //추가해줘    테이블movie에  제목과 개봉일          제목           개봉일    
			stmt=conn.createStatement();
			int result=stmt.executeUpdate(sql_INSERT);
			// Query -> SELECT
			// Update -> INSERT,UPDATE,DELETE

			if(result<=0) { // 결과 값이 음수 일때 
				// 적용된 row가 없음! //변한게 없다.
				return false;
			}

		} catch (SQLException e1) {
			e1.printStackTrace();
			return false;
		} finally { // finally 마지막에 한번은 실행되야 할때 사용 - 마지막 DB와 연결해제 시 close로 잘 닫아줘야한다.
			JDBCUtil.disconnect(stmt, conn); 
		}

		return true;
	}

	public boolean update(MovieVO mVO) {
		conn=JDBCUtil.connect(); // 모듈화로 JDBCUtil 활용하기 

		String sql_UPDATE="UPDATE MOVIE SET NAME='"+mVO.getName()+"' WHERE NUM="+mVO.getNum()+";";
                          수정해줘 테이블    이름을    이 이름으로       어디있는?  번호가  이 번호인 이름을
		try {
			stmt=conn.createStatement(); // 만들고 // statement 가 read,write를 제공해주는 것 
			int result=stmt.executeUpdate(sql_UPDATE);
			// Query -> SELECT
			// Update -> INSERT,UPDATE,DELETE

			if(result<=0) {
				// 적용된 row가 없음!
				return false;
			}

		} catch (SQLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
			return false;
		}
		finally {
			JDBCUtil.disconnect(stmt, conn);
		}

		return true;
	}
	public boolean delete(MovieVO mVO) {
		conn=JDBCUtil.connect();

		String sql_DELETE="DELETE FROM MOVIE WHERE NUM="+mVO.getNum()+";";
                          삭제해줘     테이블   어디를?   번호가  이 번호인 부분을 
		try {
			stmt=conn.createStatement(); // 만들고 // statement 가 read,write를 제공해주는 것 
			int result=stmt.executeUpdate(sql_DELETE);
			// Query -> SELECT
			// Update -> INSERT,UPDATE,DELETE

			if(result<=0) {
				// 적용된 row가 없음!
				return false;
			}

		} catch (SQLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		finally {
			JDBCUtil.disconnect(stmt, conn);
		}

		return true;
	}

	public ArrayList<MovieVO> selectAll(MovieVO mVO) {
		conn=JDBCUtil.connect();
                                      여기서 잠깐  이 부분은 밑에서 짚고 넘어가자 !
		final String sql_SELECTALL="SELECT NUM,NAME,ODATE FROM MOVIE WHERE NAME LIKE '%"+mVO.getName()+"%';";
		ArrayList<MovieVO> mdatas=new ArrayList<MovieVO>();
		try {
			stmt=conn.createStatement();
			rs=stmt.executeQuery(sql_SELECTALL);
			// Query -> SELECT
			// Update -> INSERT,UPDATE,DELETE

			while(rs.next()) {
				int num=rs.getInt("NUM");
				String name=rs.getString("NAME");
				String odate=rs.getString("ODATE");
				MovieVO mdata=new MovieVO(num,name,odate);
// 이렇게도 작성가능 MovieVO mdata = new MovieVO(rs.getInt("NUM"),rs.getString("NAME"),rs.getString("ODATE"));
				mdatas.add(mdata);
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
			return null;
		} finally {
			JDBCUtil.disconnect(rs, stmt, conn); //오버로딩한 메서드 사용 
		}

		return mdatas;
	}
	public MovieVO selectOne(MovieVO mVO) {
		conn=JDBCUtil.connect();

		final String sql_SELECTONE="SELECT NUM,NAME,ODATE FROM MOVIE WHERE NUM="+mVO.getNum()+";";
		try {
			stmt=conn.createStatement();
			rs=stmt.executeQuery(sql_SELECTONE);
			// Query -> SELECT
			// Update -> INSERT,UPDATE,DELETE

			if(rs.next()) {
				int num=rs.getInt("NUM");
				String name=rs.getString("NAME");
				String odate=rs.getString("ODATE");
				MovieVO mdata=new MovieVO(num,name,odate);
// 이렇게도 작성가능 MovieVO mdata = new MovieVO(rs.getInt("NUM"),rs.getString("NAME"),rs.getString("ODATE"));
				return mdata;
			}
		} catch (SQLException e1) {
			e1.printStackTrace();
			return null;
		} finally {
			JDBCUtil.disconnect(rs, stmt, conn);
		}
		
		return null;
	}


}
 

SELECTALL 부분에서

final String sql_SELECTALL="SELECT NUM,NAME,ODATE FROM MOVIE WHERE NAME LIKE

찾아줘 번호 , 이름, 개봉일 테이블에서 어디? 이름에

'%"+mVO.getName()+"%';";

이 이름이 들어가면

 

---------------------------------------------------------------------------------------------------------------------

이 부분에서 우리는 목록 전체 검색이 있고, 이름검색이 따로 있어서 둘을 나눠서 코드를 작성하였는데

그 둘을 하나로 합쳐 짧은 코드를 만들수 있다 !

-----> 가능한 이유 : SQL 에서 WHERE 조건절 뒤에 컬럼 LIKE 단어를 찾는 '%%'; 이것이 들어가는데

%와 % 사이에 아무것도 안들어간 상태로 출력시 똑같이 전체 목록이 출력된다 !!

코드가 공통적인 부분 으로

final String sql_SELECTALL="SELECT NUM,NAME,ODATE FROM MOVIE WHERE NAME LIKE'%"+mVO.getName()+"%';";
 

들어갈 getName이 있다면 그 단어를 검색 해주고 , 전체 목록을 출력하고 싶다면 "" 큰 따옴표를 이용하여 빈값을 ModelDAO 로 전달 시켜준다.

-----> 이로써, 전체목록출력과 이름검색을 하나의 코드로 실행할 수 있다 !!

 

 

728x90
반응형

'DB > 개념정리' 카테고리의 다른 글

JDBC - 임시 멤버 변수 구현  (0) 2024.04.10
JDBC PrepareStatement  (0) 2024.04.10
MySQL 날짜 , 날짜함수  (0) 2024.04.10
JDBC  (0) 2024.04.10
DB ,DBMS  (0) 2024.04.10