본문 바로가기

웹_프론트_백엔드/JAVA프레임윅기반_풀스택

2020.03.31

1. client   ---(요청 : request     [URL])-->  server
   client  <--(응답 : response [HTML])---   server

 

 

2. HTTP 상태 코드 정리 잘되어 있는 홈페이지
 : https://developer.mozilla.org/ko/docs/Web/HTTP/Status

 

 

3. 웹 크롤링(Web Crawling, Web Scraping)

 : Web상에 존재하는 Contents를 수집하는 작업

   HTML 페이지를 가져와서, HTML/CSS등을 파싱하고, 필요한 데이터만 추출하는 기법

 

 

4. <시작태그> content </끝태그>

 


5. 요소(element) 

 : <시작태그> + content + </끝태그>

 


6. 현재 HTML 5버전이 가장 최신 버전임 

 


7. Attribute 

 : name과 value의 쌍으로 존재

   여러 개 가질 수 있음

 


8. 웹 필수 

 : HTML, CSS, JavaScript

 

 

9. GET 방식
 : 요청 URL에 파라미터를 붙여서 전송
   [장점] 북마크 가능
   [단점] 브라우저마다 보낼 수 있는 데이터 한정, 파일 업로딩이 안됨, 보안 취약

 

** URL에는 특수문자, 띄어쓰기, 한글 안된다 

    [그렇기 때문에] 특수문자와 한글은 URL 인코딩해서 리퀘스트 해줘야함
    [왜냐하면] 특수문자와 한글은 사용 불가능하기 때문에...!!

 

** utf-8 한글 3byte, euc-kr 한글 2byte **

 

** 브라우저마다 다른데 크롬 기준으로 파라미터가 한글로 받는 것처럼 보일 수 있으나
    실질적으로 메모장으로 복사해서 붙여넣으면 한글이 아니다는 것을 알 수 있음 **

 

 

10. HTML 구조

https://www.w3schools.com/html/html_intro.asp

 

11. element, content, tag

https://www.w3schools.com/html/html_elements.asp

 

12. attribute

https://www.w3schools.com/html/html_attributes.asp

 

13. 식별용 attribute - id

https://www.w3schools.com/html/html_id.asp

 

14. 식별용 attribute - class

https://www.w3schools.com/html/html_classes.asp

 

15. 식별용 attribute - name

https://www.w3schools.com/html/html_forms.asp

 

16. URL

https://www.w3schools.com/html/html_urlencode.asp

 

17. URL Encoding

https://www.w3schools.com/tags/ref_urlencode.asp

 

18. CSS 기본 구문

https://www.w3schools.com/css/css_syntax.asp

 

19. CSS Selector : id, clsss

https://www.w3schools.com/css/css_selectors.asp

 

20. CSS Selector : Combinator

https://www.w3schools.com/css/css_combinators.asp

 

21. CSS Selector :  Pseudo-class

https://www.w3schools.com/css/css_pseudo_classes.asp

 

22. CSS Selector : Pseudo-element

https://www.w3schools.com/css/css_pseudo_elements.asp

 

23. CSS Selecotr : Attribute selector

https://www.w3schools.com/css/css_attribute_selectors.asp 

 

24. Document Object Model(DOM)

https://www.w3schools.com/js/js_htmldom.asp

25. requeet method : GET, POST

https://www.w3schools.com/tags/ref_httpmethods.asp

26. request header, response header

https://gmlwjd9405.github.io/2019/01/28/http-header-types.html

 

[실습코드]

 

1. [과제] 전화번호부 5.0 : 입출력을 이용하여 프로그램 종료하면 파일 저장, 실행하면 불러오기

* 내 과제 코드의 문제점 :  과제할때 없을때 파일 생성은 가능했으나 불러오기를 구현하지 못했음..!!

 

[중요] close() 메소드에서 oout.close가 제대로 안되어 있으면 이거 나중에 문제 생길 수 있음..!! 

 

** 쌤이 선택한 학생 코드..!! : 이 코드에서는 전화번호부가 저장된 폴더가 없으면 에러 발생

    : 쌤이 내용 추가, 폴더를 삭제하면 지정된 경로를찾을 수 없습니다라는 에러 해결

package phonebook05.file;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;

// CONTROLLER 객체
//   어플리케이션의 동작, 데이터 처리(CRUD), (Business logic 담당)

public class PhonebookManager implements Pb, Closeable {

	public static final String PB_DATA_DIR = "data";
	public static final String PB_DATE_FILE = "phonebook.dat";
	private File pbDir;
	private File pbFile;

	private ArrayList<PhonebookModel> pbList = new ArrayList<PhonebookModel>();

	// singleton적용
	private PhonebookManager() {

		// 파일이 존재하면 파일 읽어 들이기 --> pbList;
		// FileNotFoundException 여부로 확인
		// 파일이 존재하면 파일 읽어 들이기 --> pbList;
		// FileNotFoundException 여부로 확인
		
		pbDir = new File(PB_DATA_DIR);
		if(!pbDir.exists()) {
			if(pbDir.mkdir()) {
				System.out.println("폴더 생성 성공");
			} else {
				System.out.println("폴더 생성 실패");
			}
		} else {
			System.out.println("폴더 존재: " + pbDir.getAbsolutePath());
		}
		
		pbFile = new File(pbDir, PB_DATE_FILE);
		
		if(pbFile.exists()) {
			System.out.println("파일에서 데이터 읽습니다...");
			try (
					InputStream in = new FileInputStream(pbFile); 
					ObjectInputStream oin = new ObjectInputStream(in);
					) {
				
				pbList = (ArrayList<PhonebookModel>) oin.readObject();
				System.out.println(pbList.size() + " 개의 데이터를 읽었습니다");
			} catch (FileNotFoundException e) {
				System.out.println("엄써영");
			} catch (IOException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		} else {
			System.out.println("읽어올 파일이 없습니다");
		}		

	}

	private static PhonebookManager instance = null;

	public static PhonebookManager getInstance() {
		if (instance == null) {
			instance = new PhonebookManager();
		}
		return instance;
	} // end getInstance()

	// 전화번호부 생성 등록
	@Override
	public int insert(String name, String phoneNum, String memo) {

		// 매개변수 검증 : 이름 필수
		if (name == null || name.trim().length() == 0) {
			throw new PhonebookException("insert() 이름입력오류: ", Pb.ERR_EMPTY_STRING);
		}

		PhonebookModel p = new PhonebookModel(name, phoneNum, memo);
		p.setUid(getMaxUid() + 1);
		pbList.add(p);

		return 1;
	}

	@Override
	public PhonebookModel[] selectAll() {
		PhonebookModel[] pb = new PhonebookModel[pbList.size()];
		for (int i = 0; i < pbList.size(); i++) {
			pb[i] = pbList.get(i);
		}
		return pb;

		// 아래와 같이 한줄로 가능! toArray() : List<> --> 배열로 변환
//		return pbList.toArray(new PhonebookModel[pbList.size()]);
	}

	// 특정 uid 의 데이터 검색 리턴
	// 못찾으면 null 리턴
	@Override
	public PhonebookModel selectByUid(int uid) {

		for (int i = 0; i < pbList.size(); i++) {
			if (pbList.get(i).getUid() == uid) {
				return pbList.get(i);
			}
		}

		return null; // 못찾으면 null 리턴
	}// end selectByUid()

	@Override
	public int updateByUid(int uid, String name, String phoneNum, String memo) {

		// 매개변수 검증
		if (uid < 1)
			throw new PhonebookException("update() uid 오류: " + uid, Pb.ERR_UID);

		if (name == null || name.trim().length() == 0) // 이름 필수
			throw new PhonebookException("update() 이름입력 오류: ", Pb.ERR_EMPTY_STRING);

		// 특정 uid 값을 가진 데이터의 배열 인덱스 찾기
		int index = findIndexByUid(uid);
		if (index < 0)
			throw new PhonebookException("update() 없는 uid: " + uid, Pb.ERR_UID);

		pbList.get(index).setName(name);
		pbList.get(index).setPhoneNum(phoneNum);
		pbList.get(index).setMemo(memo);

		return 1;
	}

	@Override
	public int deleteByUid(int uid) {
		// 매개변수 검증
		if (uid < 1)
			throw new PhonebookException("deleteByUid() uid 오류: " + uid, Pb.ERR_UID);

		int index = findIndexByUid(uid);
		if (index < 0)
			throw new PhonebookException("deleteByUid() 없는 uid: " + uid, Pb.ERR_UID);

		pbList.remove(index);

		return 1;
	}

	// 현재 데이터중 가장 큰 uid 값을 찾아서 리턴
	private int getMaxUid() {
		int maxUid = 0;

		if (pbList.size() > 0) {
			int uid = pbList.get((pbList.size() - 1)).getUid();
			if (maxUid < uid)
				maxUid = uid;
		}

//		for (PhonebookModel p : pbList) {
//		if(maxUid < p.getUid()) {
//			maxUid = p.getUid();
//		}
//	}

		return maxUid;
	}

	// 특정 uid 값을 가진 데이터의 배열 인덱스 찾기
	// 못찾으면 -1 리턴
	private int findIndexByUid(int uid) {

		for (int i = 0; i < pbList.size(); i++) {
			if (pbList.get(i).getUid() == uid)
				return i;
		}

		return -1;
	}

	@Override
	public void close() throws IOException {

		// 데이터 저장
		// pbList -> 파일
		try(	
				OutputStream out = new FileOutputStream(new File(pbDir, PB_DATE_FILE));
				ObjectOutputStream oout = new ObjectOutputStream(out);
				){
			oout.writeObject(pbList);
			System.out.println("파일 저장 완료");
		}

	}

} // end PhonebookManager

// 예의 클래스 정의
// 예외발생하면 '에러코드' + '에러메세지'를 부여하여 관리하는게 좋다.
class PhonebookException extends RuntimeException {

	private int errCode = Pb.ERR_GENERIC;

	public PhonebookException() {
		super("Phonebook 예외 발생");
	}

	public PhonebookException(String msg) {
		super(msg);
	}

	public PhonebookException(String msg, int errCode) {
		super(msg);
		this.errCode = errCode;
	}

	// Throwable 의 getMessage 를 오버라이딩 가능
	@Override
	public String getMessage() {
		String msg = "ERR-" + errCode + "]" + Pb.ERR_STR[errCode] + " " + super.getMessage();
		return msg;
	}

} // end PhonebookException
package phonebook05.file;

import java.io.IOException;
import java.util.InputMismatchException;
import java.util.Scanner;

// VIEW 객체
// 사용자와의 입출력 담당 (UI,..) 
public class PhonebookMain {

	private Scanner sc;
	private PhonebookManager pbCtrl;   // CONTROLLER 객체
	
	public static void main(String[] args) {
		PhonebookMain app = new PhonebookMain();
		app.init();   // 초기화
		app.run();   // 실행
		app.exit();   // 종료
	} // end main()
	
	// 응용프로그램을 초기화 
	public void init() {
		sc = new Scanner(System.in);
		pbCtrl = PhonebookManager.getInstance();  // CONTROLLER 생성
	}
	
	// 응용프로그램 구동
	public void run() {
		System.out.println(Pb.VERSION);
		
		int menu;
		
		while(true) {
			showMenu();  // 메뉴 표시
			try {				
				menu = sc.nextInt(); // 메뉴 입력
				sc.nextLine();
				
				switch(menu) {
				case Menu.MENU_INSERT:
					insertPhoneBook();
					break;
				case Menu.MENU_LIST:
					listPhonebook();
					break;
				case Menu.MENU_DELETE:
					deletePhonebook();
					break;
				case Menu.MENU_UPDATE:
					updatePhonebook();
					break;
				case Menu.MENU_QUIT:
					pbCtrl.close();   // 파일 저장
					System.out.println("프로그램을 종료합니다");
					return;
				default:
					System.out.println("잘못 입력하셨습니다");
				} // end switch			
			} catch (PhonebookException ex) {
				System.out.println(ex.getMessage());
			} catch (InputMismatchException ex) {
				System.out.println("잘못된 입력입니다");
				sc.nextLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} // end while	
	} // end run()
	
	// 응용프로그램 종료
	public void exit() {
		sc.close();
	}	
	
	// 전화번호부 입력
	public void insertPhoneBook() {
		// VIEW 역할 : 사용자 입출력
		System.out.println("-- 입력 메뉴 --");
		
		// 이름, 전화번호, 이메일 입력
		System.out.print("이름 입력:");
		String name = sc.nextLine();

		System.out.print("전화번호 입력:");
		String phoneNum = sc.nextLine();
		
		System.out.print("메모 입력:");
		String memo = sc.nextLine();

		// CONTROLLER에 연결 
		int result = pbCtrl.insert(name, phoneNum, memo);
		System.out.println(result + " 개의 전화번호 입력 성공");
	} // end insertPhoneBook()
	
	// 전화번호부 열람 (전체)
	public void listPhonebook() {
		// CONTROLLER 연결
		PhonebookModel[] data = pbCtrl.selectAll();
		
		// VIEW 역할 : 사용자 입출력
		System.out.println("총 " + data.length + " 명의 전화번호 출력");
		for(PhonebookModel e : data) {
			System.out.println(e);
		}
	} // end listPhonebook()
	
	// 전화번호부 수정
	public void updatePhonebook() {
		// VIEW : 사용자 입출력
		System.out.println("--- 수정 메뉴 ---");
		System.out.println("수정할 번호 입력:");
		int uid = sc.nextInt();
		sc.nextLine();
		
		if(pbCtrl.selectByUid(uid) == null) {
			System.out.println("존재하지 않는 uid : " + uid);
			return;
		}		
		
		// 이름, 전화번호, 이메일 입력
		System.out.print("이름 입력:");
		String name = sc.nextLine();

		System.out.print("전화번호 입력:");
		String phoneNum = sc.nextLine();
		
		System.out.print("메모 입력:");
		String memo = sc.nextLine();

		
		// CONTROLLER 연결
		int result = pbCtrl.updateByUid(uid, name, phoneNum, memo);
		System.out.println(result + " 개의 전화번호 수정 성공");
		
	} // end updatePhonebook()
	
	// 전화번호부 삭제
	public void deletePhonebook() {
		// VIEW : 사용자 입출력
		System.out.println("--- 삭제 메뉴 ---");
		
		System.out.println("삭제할 번호 입력:");
		int uid = sc.nextInt();
		sc.nextLine();
		
		// CONTROLLER
		int result = pbCtrl.deleteByUid(uid);
		System.out.println(result + " 개의 전화번호 삭제 성공");
		
	} // end deletePhonebook()
	
	
	
	public void showMenu() {
		System.out.println();
		System.out.println("전화번호부 프로그램");
		System.out.println("------------------");
		System.out.println(" [0] 종료");
		System.out.println(" [1] 입력");
		System.out.println(" [2] 열람");
		System.out.println(" [3] 수정");
		System.out.println(" [4] 삭제");
		System.out.println("------------------");
		System.out.print("선택: ");
	}

} // end class
package phonebook05.file;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;

// MODEL 객체
// 데이터 표현 객체
public class PhonebookModel implements Serializable{
	
	private static final long serialVersionUID = -7457878413286439105L;
	// 멤버변수
	private int uid;	// unique id
	private String name;	// 이름
	private String phoneNum;// 전화번호
	private String memo;	// 메모
	private Date regDate;	// 등록일시
	
	// 기본생성자
	public PhonebookModel() {
		this.name = "";
		this.phoneNum = "";
		this.memo = "";
		this.regDate = new Date();  // 생성되는 현재시간.
	}
	// 매개변수 생성자
	public PhonebookModel(String name, String phoneNum, String email) {
		this();
		this.name = name;
		this.phoneNum = phoneNum;
		this.memo = email;
	}
	
	public PhonebookModel(int uid, String name, String phoneNum, String email, Date regDate) {
		super();
		this.uid = uid;
		this.name = name;
		this.phoneNum = phoneNum;
		this.memo = email;
		this.regDate = regDate;
	}
	
	
	// getter & setter
	public int getUid() {return uid;}
	public void setUid(int uid) {this.uid = uid;}
	public String getName() {return name;}
	public void setName(String name) {this.name = name;}
	public String getPhoneNum() {return phoneNum;}
	public void setPhoneNum(String phoneNum) {this.phoneNum = phoneNum;}
	public String getMemo() {return memo;}
	public void setMemo(String memo) {this.memo = memo;}
	public Date getRegDate() {return regDate;}
	public void setRegDate(Date regDate) {this.regDate = regDate;}
	
	@Override
	public String toString() {
		String str = String.format("%3d|%s|%s|%s|%20s", 
				uid, name, phoneNum, memo, 
				new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(regDate));
		return str;
	}
	
}
package phonebook05.file;

// Controller 인터페이스
//	동작 정의하기 전에 '동작 설계'
public interface Pb {
	
	public static final String VERSION = "전화번호부 5.0";
	
	// 만들고자 하는 응용프로그램의 
	// '동작' 을 설계하는 것이 인터페이스다.
	// 이 인터페이스는  View 와 Controller 의 연결고리 역할을 하여.  모듈단위 유지관리를 용이하게 해준다. 
	
	// [동작 설계]
	// 1. 이름(name)과 전화번호(phoneNum)과 (memo) 값이 주어지면 전화번호 데이터(PhonebookModel)를   
	//		생성하여 저장, 날짜(regDate) 는 생성한 날짜로, uid 값은 자동 증가 값으로 
	//		성공하면 1, 실패하면 0 리턴
	// 2. 현재 전화번호부에 저장된 전화번호 데이터(PhonebookModel)들을 
	//		전부 불러들여서 리턴(PhonebookModel 배열로)
	// 3. 특정 uid 값을 가진 전화번호 데이터(PhonebookModel)을 찾아서 
	//		리턴, 없으면 null 리턴
	// 4. 특정 uid 값을 가진 전화번호 데이터(PhonebookModel)을 찾아서 
	//		주어진 이름(name) 과 전화번호(phoneNum) 과 (memo) 값 으로 변경.  
	//		성공하면 1, 실패하면 0 리턴
	// 5. 특정 uid 값을 가진 전화번호 데이터(PhonebookModel) 을 찾아서 삭제.  
	//		성공하면 1, 실패하면 0 리턴
	
	
	public abstract int insert(String name, String phoneNum, String memo);	/* 1 */
	public abstract PhonebookModel[] selectAll();	/* 2 */
	public abstract PhonebookModel selectByUid(int uid);	/* 3 */
	public abstract int updateByUid(int uid, String name, String phoneNum, String meno);	/* 4 */
	public abstract int deleteByUid(int uid);	/* 5 */

	
	//public static final int QUERY_FAIL = 0;
	
	
	// 에러코드 상수
	public static final int ERR_GENERIC = 0;			// 일반 오류
	public static final int ERR_INDEXOUTOFRANGE = 1;	// 인덱스 범위 벗어남
	public static final int ERR_EMPTY_STRING = 2;		// 입력문자열이 empty (혹은 null)인 경우
	public static final int ERR_UID = 3;		// uid가 없는경우
	
	// 에러문자열
	public static final String[] ERR_STR = {
			"일반오류",	// 0
			"인덱스오류",	// 1
			"문자열오류",	// 2
			"UID 오류"	// 3
	};
	

}
package phonebook05.file;

public interface Menu {
	public static final int MENU_QUIT = 0;
	public static final int MENU_INSERT = 1;
	public static final int MENU_LIST = 2;
	public static final int MENU_UPDATE = 3;
	public static final int MENU_DELETE = 4;
}

 

 

2. Lec26_FileIO
1) com.lec.java.file14 패키지, File14Main 클래스

package com.lec.java.file14;

import java.nio.charset.Charset;

public class File14Main {

	public static void main(String[] args) {
		System.out.println("시스템 정보 확인");
		
		System.out.println();
		System.out.println(System.getProperty("os.name"));
		
		// 출력 amd64: amd사의 64비트라는 의미
		System.out.println(System.getProperty("os.arch"));	
		
		System.out.println(System.getProperty("os.version"));
		
		System.out.println();
		// JRE 경로 : Java Runtime Environment <-- JVM
		System.out.println(System.getProperty("java.home"));
		
		System.out.println(System.getProperty("java.version"));
		
		System.out.println();
		// current working directory : 현재 작업 경로
		System.out.println(System.getProperty("user.dir"));
		
		// user home directory("내 문서"가 있는 폴더)
		System.out.println(System.getProperty("user.home"));
		
		System.out.println();
		// 그 운영체제에서 제공되는 파일 구분점 출력, 윈도우는 역슬래시를 씀
		System.out.println(System.getProperty("file.separator"));
		
		System.out.println();
		// OS 기본 인코딩 값!
		System.out.println("Default Charset = " + Charset.defaultCharset());
		System.out.println("file.encoding = " + System.getProperty("file.encoding"));

		
		System.out.println("\n프로그램 종료");
		
	} // end main()

} // end class

 

[추가] 파일 구분점 출력, 운영체제마다 다름, 윈도우는 역슬래시를 사용

2) com.lec.java.file15 패키지, File15Main 클래스

package com.lec.java.file15;

import java.io.File;

public class File15Main {

	public static void main(String[] args) {
		System.out.println("디렉토리 정보 확인");
		System.out.println();
		// current working directory : 현재작업경로
		String curWorkingDir = System.getProperty("user.dir");
		System.out.println("현재 작업 폴더: " + curWorkingDir);
		
		System.out.println();
		// 디렉토리(폴더) : 파일을 담는 공간
		// 현재 작업 디렉토리의 파일 리스트 출력
		// File 클래스: 파일(txt, doc, ...) 객체 또는 디렉토리(폴더) 객체
		File curDir = new File(curWorkingDir);	// 현재 작업 디렉토리 객체
		File[] list = curDir.listFiles();	// listFiles() : 디렉토리 안에 있는 '파일' 과 
							//              '디렉토리' 를 File배열로 리턴
		
		System.out.println(list.length);	// '파일' 과 '디렉토리' 의 개수
		
		for (int i = 0; i < list.length; i++) {
			if(list[i].isDirectory()) {
				// isDirectory(): File 객체가 디렉토리이면 true 리턴
				// isFile(): File 객체가 파일이면 true 리턴
				System.out.print("DIR\t");
			} else {
				System.out.print("FILE\t");
			}
			System.out.print(list[i].getName() + "\t");
			System.out.println(list[i].length());	// length() '파일'의 크기(byte)
								// '디렉토리' 인 경우는 의미 없다
		}
		System.out.println();
		// 디렉토리의 내용 출력, enhanced for 문 이용
		// current working directory에 있는 temp 폴더..!!
		//File tempDir = new File("temp");	// '상대경로'를 이용한 File 객체 생성
		
		// '절대경로(absolute path)'를 이용한 File 객체 생성
		String tempDirPath = System.getProperty("user.dir")
				+ File.separator	// 윈도우(\), LINUX와 Mac(/)
				+ "temp";
		System.out.println("절대경로 : " + tempDirPath);
		File tempDir = new File(tempDirPath);
		
		
		File[] list2 = tempDir.listFiles();
		for (File f : list2) {
			if(f.isDirectory()) {
				System.out.print("DIR\t");
			} else {
				System.out.print("FILE\t");
			}
			System.out.print(f.getName() + "\t");
			System.out.println(f.length());
		}
		
		System.out.println();
		// 파일 하나에 대한 정보
		String path = "dummy.txt";
		File f = new File(path);	// 새로운 File 객체 생성!
						// 명심! 파일 객체를 생성(new) 했다고 해서
						// 물리적인 파일 혹은 디렉토리가 만들어지는 것이 아님!
		System.out.println("파일 이름: " + f.getName());	// 상대 경로명
		System.out.println("절대경로: " + f.getAbsolutePath());	// 절대 경로명
		System.out.println("있냐? " + f.exists());		// 물리적으로 존재하는지 여부
		
		
		System.out.println("\n프로그램 종료");
		
	} // end main()

} // end File11Main

 

3) com.lec.java.file16 패키지, File16Main 클래스

package com.lec.java.file16;

import java.io.File;
import java.io.IOException;

public class File16Main {

	public static final String TEST_DIRECTORY = "test";
	public static final String TEMP_DIR = "temp";
	public static final String TEST_FILE = "dummy.txt";
	public static final String TEST_RENAME = "re_dummy.txt";
	
	public static void main(String[] args) {
		System.out.println("폴더/파일 생성, 이름변경, 삭제");
		System.out.println();
		
		String path = System.getProperty("user.dir")
				+ File.separator
				+ TEST_DIRECTORY;   // "test"
		System.out.println("절대경로: " + path);
		
		// File 객체 생성. --> [중요] 디스크에 물리적인 파일 혹은 디렉토리가 만들어진 것은 아니다!!!
		File f = new File(path);
				 
		
		System.out.println();
		// 폴더 생성: mkdir()
		if(!f.exists()) {	// 디렉토리가 존재하는지 체크
			// 디렉토리가 존재하지 않는다면 생성!
			if(f.mkdir()) {	// mkdir() 리턴값은 true, false
				System.out.println("폴더 생성 성공!");
			} else {
				// 용량이 작아서 생성 못한다던지.. os 권한이  없다던지.. 등등
				// 다양한 물리적인 상황에 의해 폴더 생성을 못할 때!
				System.out.println("폴더 생성 실패!");
			}
		} else {
			System.out.println("폴더가 이미 존재합니다!");
		}
		
		
		System.out.println();
		// 파일 생성 : createNewFile()
		File f2 = new File(f, TEST_FILE);  // "test/dummy.txt" , File(디렉토리 File, 파일명)
		System.out.println(f2.getAbsolutePath());
		
		if(!f2.exists()) {  // 파일이 존재하는지 체크
			// 파일이 존재하지 않으면 생성
			try {
				if(f2.createNewFile()) {  // 물리적으로 파일 생성
					System.out.println("파일 생성 성공!");
				} else {
					System.out.println("파일 생성 실패!");
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			// 파일이 존재한다면
			System.out.println("파일이 이미 존재합니다");
		}
		
		
		System.out.println();
		// 파일 이름 변경: renameTo()
		// renameTo()를 이용해서 다른 폴더로 이동(move)를 할 수도 있다.
		File f3 = new File(f, TEST_RENAME);	// "test/dummy.txt"
		System.out.println(f3.getAbsolutePath());
		
		if(f2.exists()) {	// "test/dummy.txt" 가 존재하는지 체크
			// "test/dummy.txt" 가 존재하면 파일명 변경
			if(f2.renameTo(f3)) {	// renameTo() 리턴값은 true, false
				System.out.println("파일 이름 변경 성공!");
			} else {
				// 이미 "re_dummy.txt"가 존재하면 실패한다.
				System.out.println("파일 이름 변경 실패!!");
			}	
		} else {
			System.out.println("변경할 파일이 없습니다.");
		}
		
		
		System.out.println();
		// 파일 삭제: delete()
		File f4 = new File(f, TEST_RENAME);	// "re_dummy.txt"
		
		if(f4.exists()) {
			// 파일이 존재하면 삭제
			if(f4.delete()) {
				System.out.println("파일 삭제 성공!");
			} else {
				System.out.println("파일 삭제 실패!");
			}
		} else {
			System.out.println("삭제할 파일이 없습니다!");
		}
		
		
		System.out.println("\n프로그램 종료");

	} // end main()

} // end class

 

[추가] mkdir() 폴더 생성 : test 폴더 생성

[추가] createNewFile() 파일 생성 : dummy.txt 파일 생성

[추가] renameTo() 파일 이름 변경 : dummy.txt가 re_dummy.txt로 변경

[추가] delete() 파일 삭제 : re_dummy.txt 파일 삭제

4) com.lec.java.file17 패키지, File17Main 클래스

package com.lec.java.file17;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/* HTML 데이터, 웹데이터 (텍스트)
 * Java 에서 웹 연결을 위한 객체 두가지
 * 	1. URL : 웹 상의 주소, 
 * 	2. HttpURLConnection : 웹연결
 * 		URLConnection
 * 		   └─ HttpURLConnection
 * 
 * java.io.Reader    프로그램이 '문자 단위' 데이터를 읽어들이는(read) 통로
 *  ├─ java.io.InputStreamReader	// 스트림 기반의 reader
 *  └─ java.io.BufferedReader 	// 문자(character) 기반 reader
 */

public class File17Main {

	public static void main(String[] args) {
		System.out.println("웹데이터 가져오기(텍스트)");
		
		//String url = "https://www.daum.net";
		String url = "https://www.naver.com/srchrank?frm=main&ag=all&gr=1&ma=-2&si=0&en=0&sp=0";
		
		StringBuffer sb = readFromUrl(url);
		
		// 다 뽑고 싶지 않아요, 상위 200 글자만 뽑을거에요~
		//System.out.println(sb.toString().substring(0, 200));
		System.out.println(sb);
		
		System.out.println("\n프로그램 종료");
	} // end main()
	
    
	/**
	 * 
	 * @param urlAddress : 주어진 url 주소
	 * @return 서버로부터 받은 텍스트데이터(HTML) 리턴
	 */
	public static StringBuffer readFromUrl(String urlAddress) {
		
		StringBuffer sb = new StringBuffer();	// response 받은 데이터 담을 객체
		
		URL url = null;		// java.net.URL
		HttpURLConnection conn = null;	// java.net.HttpURLConnectrion
		
		InputStream in = null;
		InputStreamReader reader = null;	// byte 스트림 --> 문자기반 Reader
		BufferedReader br = null;
		
		char[] buf = new char[512];	// 문자용 버퍼
		
		// BufferedReader <- InputStreamReader <- InputStream <- HttpURLConnection 
		
		try {
			url = new URL(urlAddress);
			conn = (HttpURLConnection)url.openConnection();  // Connection 객체 생성
			
			if(conn != null) {
				conn.setConnectTimeout(2000);	// 2초이내에 '연결'이 수립안되면
								// java.net.SocketTimeoutException 발생
				
				conn.setRequestMethod("GET");	// GET 방식	request
				// "GET", "POST", ...
				conn.setRequestProperty("Content-Type", 
						"application/x-www-form-urlencoded; charset=UTF-8");
				conn.setUseCaches(false);	// 캐시사용안함
				
				System.out.println("request 시작: " + urlAddress);
				conn.connect();	// request 발생 --> 이후 response 받을때까지 delay
				System.out.println("response 완료");
				
				// response 받은 후 가장 먼저 response code 값 확인
				int restponseCode = conn.getResponseCode();
				System.out.println("response code: " + restponseCode);
				// 참조 : https://developer.mozilla.org/ko/docs/Web/HTTP/Status
				if(restponseCode == HttpURLConnection.HTTP_OK) {
					
					in = conn.getInputStream();	// InputStream<-HttpURLConnection
					reader = new InputStreamReader(in,"utf-8");// InputStreamReader<-InputStream
					br = new BufferedReader(reader); // BufferedReader<-InputStreamReader
					
					int cnt;	// 읽은 글자 개수
					while((cnt = br.read(buf)) != -1) {
						sb.append(buf, 0, cnt);	// response 받은 텍스트를 StringBuffer에 추가
					}
					
				} else {
					System.out.println("response 실패");
					return null;
				}
				
			} else {
				System.out.println("conn null");
				return null;
			}
			
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			if(conn != null) {conn.disconnect();}	// 작업 끝나고 Connection 해제
		}
		return sb;
	} // end readFromUrl()
	
} // end class

 

 

3. Lec32_WebCrawl
1) com.lec.java.crawl01 패키지, Crawl01Main 클래스

package com.lec.java.crawl01;

import java.io.IOException;

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

/*
 * 외부 라이브러리 사용한 자바 프로젝트
 * 
 * 1. 라이브러리 다운로드
 * 2. 프로젝트내(혹은 특정 경로)에 라이브러리 저장
 * 3. 프로젝트의 BuildPath 설정
 */

/*
 * 1. https://jsoup.org/ 에서 다운로드
 * 2. 프로젝트에 폴더 만들고 (ex: libs) 라이브러리 복사
 * 3. 프로젝트 우클릭 -> Configure Build Path -> Library탭 
 *    -> Add Jars (혹은 라이브러리 추가) -> 추가할 라이브러리 선택
 */

/*
 * 네이버 뉴스 캐스트 (상단의 실시간 뉴스)
 */

// 외부 라이브러리 추가하면서 기존에 반복되던 코드가 간편해졌다.
public class Crawl01Main {
	
	public static void main(String[] args) throws IOException {
		System.out.println("네이버 뉴스 캐스트 크롤링");
		
		String url;		// 크롤링할 주소 url
		Response response;	// response 객체
		Document doc;		// JSOUP의 document
		Element element;	// HTML 의 element 표현 객체
		
		url = "http://www.naver.com";
		response = Jsoup.connect(url).execute();
				// GET 방식 request 는 다음과 같이 해도 된다.
				// Jsoup.connect(url).get();
		
		System.out.println(response.statusCode());
		// request 결과코드
		// 200 성공
		// 404 url 존재하지 않음
		// 500 서버 내부 
		// 400 Bad Request : request 문법상의 오류
		// 401 권한에러 : 권한 관현 적절한 header 정보가 없는 경우 많이 발생
		// 402 권한에러 : 자원에 대한 접근 권한 에러
		// 403 권한에러 Forbidden 
		//     : 파일권한, 읽기권한, SSL, IP, 등...  <--- 웹 크롤링 하다가 은근히 자주 마주치게 되는 에러
		System.out.println(response.statusMessage());
		
		doc = response.parse();
		
		System.out.println(doc.title());	// <title> element 의 텍스트
		System.out.println(doc.location());	// 현재 웹문서의 url
		
		String outerHtml = doc.outerHtml();	// 현재 node 의 outer html 텍스트
		//System.out.println(outerHtml);
		// 위의 코드 syso 출력하면 너무 길어서 아래의 syso를 이용해 상위 200자만 출력할 수 있게 함
		System.out.println(outerHtml.substring(0, 200) + "...");

		// Document 나 Element 객체의
		// select(), selectFirst() 메소드로 특정 element(들)을 추출
		System.out.println("[네이버 뉴스 캐스트]");
		
		element = doc.selectFirst("#news_cast");// 검색된 Element 들 중 최초 1개만 Element로 리턴
		//System.out.println(element.outerHtml());
		
		// 검색된 Element들이 담겨있는 Elements 리턴
		Elements newsElements = doc.select("#news_cast li.ca_item"); 
		
		// 복수개 목록 크롤링 할시, 내가 원하는 개수만큼 크롤링 되었는지 우선 확인해보자!
		// 크롬의 F12의  Element 탭의 개수와 페이지 소스 보기 Ctrl + U와 개수는 다를 수 있다
		// 페이지 소스보기의 개수로 출력이 된다.
		// 다른 이유는 크롬의 F12는 실시간으로 변동되면서 response되기 때문이다
		System.out.println(newsElements.size() + " 개");
		
		for(Element e : newsElements) {
			//System.out.println(e.outerHtml());
			element = e.selectFirst("a");
			System.out.println(element.text()); // Element의 text()->text들을 묶어서 하나로 리턴
			System.out.println(element.attr("href"));
		}
		
		
		System.out.println("\n프로그램 종료");
	} // end main() 

} // end class

 

[추가] 폴더 생성하기

 : 우클릭 > New > Folder 클릭

> 파일 이름 설정 > Finish 클릭

[추가] jsoup은 자바(Java)로 만들어진 HTML 파서(Parser)
 : https://jsoup.org/download > Download 클릭

> jsoup-1.13.1.jar core library 다운

> 다운로드 완료~~!!

** 최종적으로 lib 폴더 안에 Java HTML Parser가 잘 다운되었는지 확인하기 **

[추가] 외부 라이브러리 추가하기 : 자바 HTML 파서(Java HTML Parser)

 : 프로젝트 폴더 클릭 > 우클릭 > Build Path > Configure Build Path

> Java Build Path > Libraries > Add Jars...

> jsoup-1.13.1.jar 클릭 > OK 클릭

> 잘 추가되었는지 확인 후 Apply and Close 클릭

> 추가 완...!!

'웹_프론트_백엔드 > JAVA프레임윅기반_풀스택' 카테고리의 다른 글

2020.04.02  (0) 2020.04.02
2020.04.01  (0) 2020.04.01
2020.03.30  (0) 2020.03.30
2020.03.27  (0) 2020.03.27
2020.03.26  (0) 2020.03.26