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 |