너굴 개발 일지

TIL_210324_추상클래스, 라이브러리 추가, 엑셀파일 다루기 본문

Java

TIL_210324_추상클래스, 라이브러리 추가, 엑셀파일 다루기

너굴냥 2021. 3. 24. 21:58

오전 수업

문제

사전 준비 작업 : 

1. C 드라이브의 filetest 폴더에 naver_news_stand_data_edit.txt 파일과 newsImages 폴더가 존재해야 합니다.

2.  naver_news_stand_data_edit.txt : 첨부파일을 넣어 놓고, newsImages 폴더 : 첨부파일을 압축 푸시면 됩니다.

newsImages.zip
0.39MB

프로젝트 생성 

 

 

패키지명은 변경해도 상관없다

 

 각 클래스 역할

1. MainClass : 전체 흐름을 담당 (일종의 Controller) / main() 포함

2. PressClass :  신문사명, 종류 변수를 보유 <= 해당 변수들은 모두 외부 접근 불가!!!

3. NewsClass : 대표 이미지, 네이버 주소 변수를 보유 <= 해당 변수들은 모두 외부 접근 불가!!! (PressClass 상속받아)

4. DataClass : 전체 데이터를 보유 (NewsClass 사용)

5. MethodClass : 실행 메서드들만  보유  /  해당 메서드들은 객체 생성 없이 사용할 수 있도록 선언 

6. PrintClass :  출력 전용 클래스  / "c:/filetest/news_test.html" 파일을 생성하는 역할 담당 / 해당 메서드들은 객체생성 없이 사용할 수 있도록 선언

※ 파일 정보들과 이미지 파일의 확장자를 확인하고 어떤 변수들이 필요한지, 몇 개인지 확인하고 설계도 그리기 

 

직접 짠 코드들

 

MainClass 

package com.bjy;

import com.bjy.data.DataClass;
import com.bjy.out.PrintClass;
import com.bjy.util.MethodClass;

public class MainClass {

	public static void main(String[] args) {
		
		/** NewsClass의 정보들이 들어있는 변수 **/
		String uri = "c:/filetest/naver_news_stand_data_edit.txt";
		
		/** uri로 DataClass의 ArrayList 배열의 각 요소들에게 객체 저장해줌  **/
		MethodClass.makeNewsData(uri);
		
		/** DataClass에 정보 잘 들어갔는지 확인차 **/
//		for(int i=0;i<DataClass.news.size();i++) {
//			System.out.println(DataClass.news.get(i).TesttoString());
//		}
		
		/** tags 생성 메서드 이용하여 String 변수에 저장 **/
		String tags = MethodClass.makeTags();
		
		/** tags가 잘 생성되었는지 확인차 코드 실행 **/
		// System.out.println(tags);
		
		/** 원하는 파일의 경로 + 파일명 입력한 변수 생성 **/
		String url =  "c:/filetest/news_test.html";
		
		/** tags와 url 넣어줘 html 파일 생성하는 메서드 호출 **/
		PrintClass.makeHTML(tags, url);

	}
}

PressClass

package com.bjy.data;

public class PressClass {
	private String press = "";
	private String kind = "";
	
	/** 기본생성자 **/
	public PressClass() {
		
	}
	
	/** 매개변수 생성자 **/
	public PressClass(String press, String kind) {
		this.press = press;
		this.kind = kind;
	}
	
	/** 멤버변수가 private이기에 간접접근 할 수 있는 getter 메서드 생성 **/
	public String getPress() {
		return press;
	}

	public String getKind() {
		return kind;
	}

}

NewsClass

package com.bjy.data;

public class NewsClass extends PressClass {
	private String img = "";
	private String address = "";
	
	/** 기본 생성자 **/
	public NewsClass() {
		
	}
	
	/** 멤버변수가 private이기에 간접접근 할 수 있는 getter 메서드 생성 **/
	public NewsClass(String press, String img, String address, String kind) {
		super(press, kind);
		this.img = img + ".gif"; // 이미지 파일 확장자 붙여주기 
		this.address = address;
	}

	public String getImg() {
		return img;
	}

	public String getAddress() {
		return address;
	}
	
	
	/** 객체가 올바르게 생성됐는지 확인용 메서드 **/ 
	public String TesttoString() {
		return this.address + "," + this.img;
	}

}

DataClass

package com.bjy.data;

import java.util.ArrayList;

public class DataClass {
	/** 인스턴스 생성 없이 사용하기에 static 제어자 사용 **/
	public static ArrayList<NewsClass> news = new ArrayList<NewsClass>();
	
	public DataClass() {
		
	}

}

MethodClass

package com.bjy.util;

import java.io.*;

import com.bjy.data.DataClass;
import com.bjy.data.NewsClass;

public class MethodClass {

	public MethodClass() {
		
	}
	
	/** 신문사 관련 정보(uri)를 읽어 DataClass의 멤버에게 인스턴스 넣어주는 메서드 **/
	public static void makeNewsData(String uri) {
		FileReader fr = null;     // 파일 읽어주는 변수
		BufferedReader bf = null; // 파일 내의 텍스트를 한줄씩 읽어주는 변수
		
		String line = "";         // bf.readLine 정보 저장하는 변수
		String[] word = null;     // 한줄에서 ,로 쪼갠 단어들 저장하는 변수
		NewsClass nc = null;      // 객체 저장하여 data 클래스에 저장할 변수
		
		try {
			fr = new FileReader(uri);
			bf = new BufferedReader(fr);
			
			while( (line=bf.readLine()) != null ) {
				word = line.split(",");
				nc = new NewsClass(word[0], word[1], word[2], word[3]);
				DataClass.news.add(nc);
			}	
		}catch (IOException e) {
			System.out.println("DataClass의 news배열 객체 생성 Err : " +e.getMessage());
		}	
	} // end of makeNewsData()
	
	
	/** DataClass 스태틱 멤버들을 이용하여 tags 만드는 메서드 **/
	public static String makeTags() {
		String tags = ""; 		// 태그 저장할 변수
		int count = 0;          // 객체 배열 인덱스 번호
		int RowCount = 10;      // 10행
		int ColumnCount = 10;    // 10열 
		
		tags += "<!doctype html>";
		tags += "<html>";
		tags += "<head><title>News Stand</title></head>";
		tags += "<body>";
		
		tags += "<table border='1'>";

		
		for(int i=1;i<=RowCount;i++) {
			tags = tags + "<tr>"; // 행 시작
			for(int j=1;j<= ColumnCount;j++) {
				
				tags = tags + "<td>"; // 열 시작
				tags += "<a href='http://" + DataClass.news.get(count).getAddress() + "'>";
				tags = tags + "<img src='./newsImages/" + DataClass.news.get(count).getImg() + "' />";
				tags = tags + "</td>"; // 열 닫기
				
				// 행*열 = 100이기에 news 배열 인덱스를 넘어가면 오류발생
				// 95번째 인덱스에 도달하면 break 실행 
				if(count==94) {
					break;
				}
				count++;
			}
			tags = tags + "</tr>"; // 행 닫기	
		}
		
		tags += "</table>";
		tags += "</body>";
		tags += "</html>";
		return tags;
	} // end of makeTags() 
	
	
} // end of MethodClass 

PrintClass

package com.bjy.out;

import java.io.*;

public class PrintClass {
	
	
	/** 기본 생성자 **/
	public PrintClass() {
		
	}
	
	/** 객체 생성 없이 사용하는 메서드 ( tags, url 입력 받아 html 파일 생성) **/
	public static void makeHTML(String tags, String url) {
		FileWriter fd = null;          // 파일 생성하는 변수 
		
		try {
			
			fd = new FileWriter(url);  // 원하는 파일의 url 입력
			fd.write(tags);			   // 해당 파일에 tags 입력 
	
		}catch (IOException e) {
			System.out.println("HTML파일 생성 ERR : " + e.getMessage());
		}finally {
			try {
				fd.close();
			} catch (IOException e) {
				System.out.println("HTML파일 닫기 ERR : " + e.getMessage());
			}
		}
		
	} // end of matkHTML()

}

 

 

배운 것 및 느낀점

import 패키지명.*; 사용 시 해당 패키지의 클래스들만 사용 가능하고 패키지의 하위 패키지는 사용 불가능하다. 따라서 원하는 클래스가 있으면 해당 클래스의 정확한 패키지명을 기재해야 한다 ( MainClass에서 import com.bjy.*; => X ,  import com.bjy.data => O ) 

메서드의 변수 사용시 꼭 초기화해줘야 한다는 것도 잊지 말자.

 


오후수업

문제

검색하고 싶은 신문의 종류를 입력받고 그에 대한 신문의 종류를 보여주고 링크를 연결해주는 html 파일을 만드세요.

 

해결 방안

1. 원하는 신문 종류의 데이터를 따로 추출 후 저장하여 html 파일 생성한다.

2. 모든 종류의 신문 데이터를 저장한 후 따로 비교하여 원하는 신문 종류를 분류하고 html 파일 생성한다.

 

 

MainClass 실행시 출력결과

MainClass

package com.bjy;

import java.util.Scanner;

import com.bjy.data.DataClass;
import com.bjy.out.PrintClass;
import com.bjy.util.MethodClass;

public class MainClass {

	public static void main(String[] args) {
		/** NewsClass의 정보들이 들어있는 변수 **/
		String uri = "c:/filetest/naver_news_stand_data_edit.txt";
		
		System.out.println("검색할 신문사의 종류를 아래를 참고하여 입력하고 ENTER ~~");
		System.out.println("전체, 종합지, 방송통신, 경제지, 인터넷, IT영자지, 스포츠연예, 매거진전문지, 지역지");
		System.out.println("--------------------------------------------------------");
		System.out.println("검색어 입력 : ");
		
		Scanner scan = new Scanner(System.in);
		String input = scan.next();
		
		if(input.equals("전체")) {
			/** uri로 DataClass의 ArrayList 배열의 각 요소들에게 객체 저장해줌  **/
			MethodClass.makeNewsData(uri);
		}else {
			MethodClass.makeKindNewsData(uri, input);
			
		}
		
		// 검색 결과 코드 
		for(int i=0;i<DataClass.news.size();i++) {
			System.out.println(DataClass.news.get(i).TesttoString());
		}
		
		
		/** DataClass에 정보 잘 들어갔는지 확인차 **/
//		for(int i=0;i<DataClass.news.size();i++) {
//			System.out.println(DataClass.news.get(i).TesttoString());
//		}
		
		/** tags 생성 메서드 이용하여 String 변수에 저장 **/
		String tags = MethodClass.makeTags();
		
		/** tags가 잘 생성되었는지 확인차 코드 실행 **/
		// System.out.println(tags);
		
		/** 원하는 파일의 경로 + 파일명 입력한 변수 생성 **/
		String url =  "c:/filetest/news_test.html";
		
		/** tags와 url 넣어줘 html 파일 생성하는 메서드 호출 **/
		PrintClass.makeHTML(tags, url);

	}
}

MethodClass

package com.bjy.util;

import java.io.*;

import com.bjy.data.DataClass;
import com.bjy.data.NewsClass;

public class MethodClass {

	public MethodClass() {
		
	}
	
	/** 신문사 관련 정보(uri)를 읽어 DataClass의 멤버에게 인스턴스 넣어주는 메서드 **/
	public static void makeNewsData(String uri) {
		FileReader fr = null;     // 파일 읽어주는 변수
		BufferedReader bf = null; // 파일 내의 텍스트를 한줄씩 읽어주는 변수
		
		String line = "";         // bf.readLine 정보 저장하는 변수
		String[] word = null;     // 한줄에서 ,로 쪼갠 단어들 저장하는 변수
		NewsClass nc = null;      // 객체 저장하여 data 클래스에 저장할 변수
		
		try {
			fr = new FileReader(uri);
			bf = new BufferedReader(fr);
			
			while( (line=bf.readLine()) != null ) {
				word = line.split(",");
				nc = new NewsClass(word[0], word[1], word[2], word[3]);
				DataClass.news.add(nc);
			}	
		}catch (IOException e) {
			System.out.println("DataClass의 news배열 객체 생성 Err : " +e.getMessage());
		}	
	} // end of makeNewsData()
	
	
	/** DataClass의 news 배열에 원하는 신문사 정보들만 저장하기 위한 메서드
	         입력받은 신문사 정보를 알아야 하기에 경로 및 파일명 (uri), 신문사 종류(input) 매개변수로 받아
	        만약 여러 번 프로젝트 실행하면 DataClass의 객체들은 계속 저장되므로 
	        메서드 실행할 때마다 news 배열 요소의 각 객체들 삭제하는 코드 추가 **/
	
	public static void makeKindNewsData(String uri, String input) {
		DataClass.news.clear();
		
		FileReader fr = null;     // 파일 읽어주는 변수
		BufferedReader bf = null; // 파일 내의 텍스트를 한줄씩 읽어주는 변수
		
		String line = "";         // bf.readLine 정보 저장하는 변수
		String[] word = null;     // 한줄에서 ,로 쪼갠 단어들 저장하는 변수
		NewsClass nc = null;      // 객체 저장하여 data 클래스에 저장할 변수
		
		try {
			fr = new FileReader(uri);
			bf = new BufferedReader(fr);
			
			while( (line=bf.readLine()) != null ) {
				word = line.split(",");
				if(word[3].equals(input)) {
					nc = new NewsClass(word[0], word[1], word[2], word[3]);
					DataClass.news.add(nc);
				}	
			}	
		}catch (IOException e) {
			System.out.println("DataClass의 news배열 객체 생성 Err : " +e.getMessage());
		}	
	}
	
	
	/** DataClass 스태틱 멤버들을 이용하여 tags 만드는 메서드 **/
	public static String makeTags() {
		String tags = ""; 		// 태그 저장할 변수
		int count = 0;          // 객체 배열 인덱스 번호
		int RowCount = 10;      // 10행
		int ColumnCount = 10;    // 10열 
		
		tags += "<!doctype html>";
		tags += "<html>";
		tags += "<head><title>News Stand</title></head>";
		tags += "<body>";
		
		tags += "<table border='1'>";

		
		for(int i=1;i<=RowCount;i++) {
			tags = tags + "<tr>"; // 행 시작
			for(int j=1;j<= ColumnCount;j++) {
				if(count<DataClass.news.size()) {
					tags = tags + "<td>"; // 열 시작
					tags += "<a href='http://" + DataClass.news.get(count).getAddress() + "'>";
					tags = tags + "<img src='./newsImages/" + DataClass.news.get(count).getImg() + "' />";
					tags = tags + "</td>"; // 열 닫기
				}else {
					break;
				}
				count++;
			}
			tags = tags + "</tr>"; // 행 닫기	
		}
		
		tags += "</table>";
		tags += "</body>";
		tags += "</html>";
		return tags;
	} // end of makeTags() 
	
	
} // end of MethodClass 

MethodClass에서 DataClass.news 배열에 원하는 신문 종류의 정보만 저장해주는 메서드 추가하고 태그 추가하는 makeTags()를 약간 수정하였다. 

 


추상클래스 

일반 클래스 + 추상 메서드로 일반 클래스처럼 변수, 상수, 메서드, 생성자 생성이 가능하다.

생성자 선언도 가능하지만 일반 클래스처럼 new 연산자 이용하여 객체 생성은 불가하다. (생성자 갖는 이유 : 상속시 조상의 객체가 만들어져야 하기 때문)

추상 클래스는 단독 사용이 불가하며, 일반 클래스의 조상(상속)으로만 가능하다.

 

다음은 인터페이스와 추상 클래스의 예시다.

 

PhoneInterface

package com.bjy.poly;

public interface PhoneInterface {
	
	public void call(); // 추상 메서드 : abstract 생략
	
	public void message(); // 추상 메서드 : abstract 생략
	
	
}

PhoneInterface를 구현한 LGPhoneClass, SamsungPhoneClass

package com.bjy.phone;

import com.bjy.poly.PhoneInterface;

public class LGPhoneClass implements PhoneInterface{

	public LGPhoneClass() {
		
	}

	@Override // annotation 지우면 속도 느려져 (이 메서드가 누구 것인지 확인해야 해서)
	public void call() {
		System.out.println("LG 전화걸기");
	}

	@Override
	public void message() {
		System.out.println("LG 문자 앱 실행");
		
	}
		
}
package com.bjy.phone;

import com.bjy.poly.PhoneInterface;

public class SamsungPhoneClass implements PhoneInterface {
	
	public SamsungPhoneClass() {
		
	}

	@Override
	public void call() {
		System.out.println("삼성 전화 앱 실행");
		
	}

	@Override
	public void message() {
		System.out.println("삼성 문자 앱 실행");
	}

}

PhoneInterface의 추상메서드 중 하나라도 구현하지 않게 되면 일반 클래스가 아닌 인터페이스가 된다.

따라서 인터페이스를 구현하기 위해선 메서드를 재정의해야 하기에 강제성을 띈다.

 

다음은 LGPhoneClass와 SamsungPhoneClass의 인스턴스를 MainClass에 생성한 코드다.

 

MainClass

package com.bjy;

import com.bjy.phone.LGPhoneClass;
import com.bjy.phone.SamsungPhoneClass;
import com.bjy.poly.AndroidAbstactClass;

public class MainClass {

	public static void main(String[] args) {
		
		LGPhoneClass lg = new LGPhoneClass();
		SamsungPhoneClass samsung = new SamsungPhoneClass();
		
		lg.call();
		lg.message();
		
		samsung.call();
		samsung.message();
		
	}
}

MainClass 실행 결과

 

삼성폰, LG폰 모두 핸드폰이지만 핸드폰 종류에 따라 다른 문구를 출력하기 위해 폰인터페이스를 구현하였다.

따라서, 인터페이스는 선언(껍데기)과 구현(알맹이)를 분리시켜 원하는 의미로 구현할 수 있기에 변경에 유리하며 서로 상속관계에 있지 않은 클래스에게 관계를 맺어줄 수 있다.

 

AndroidAbstractClass

package com.bjy.poly;

/** 삼성, 엘지, 화웨이 ... 폰 제조사 : 안드로이드OS
 * 안드로이드 OS : 버전 => 상수
 * 구글 앱 : 구글플레이, 유튜브, 지도... => 메서드 **/

public abstract class AndroidAbstactClass {
	
	public static final float version = 1.2f; // 상수
	public String versionName = "오레오";
	
	public void AndroidAbstractClass() {
		
	} // 기본생성자 
	
	public abstract void os();
	// 추상메서드
	
	public void play() {
		
	} // 일반 메서드 
	
	
	
} // end of AndroidAbstractClass 

AndroidAbstractClass를 구현한 DafaultClass

package com.bjy;

import com.bjy.poly.AndroidAbstactClass;

public class DefaultClass extends AndroidAbstactClass {
	
	public DefaultClass() {
		
	}

	@Override
	public void os() {
		
		
	}
}

간단한 예시를 위해 구현부에 특정 기능을 작성하진 않았다.

 

MainClass에 DefaultClass 인스턴스를 생성한 코드

package com.bjy;

import com.bjy.phone.LGPhoneClass;
import com.bjy.phone.SamsungPhoneClass;
import com.bjy.poly.AndroidAbstactClass;

public class MainClass {

	public static void main(String[] args) {
		
		LGPhoneClass lg = new LGPhoneClass();
		SamsungPhoneClass samsung = new SamsungPhoneClass();
		
		lg.call();
		lg.message();
		
		samsung.call();
		samsung.message();
		
		AndroidAbstactClass aac = new AndroidAbstractClass();
		// 추상클래스는 독립적이지 않아 생성자가 있다해도 인스턴스 생성 불가 
		// 추상클래스가 생성자 갖는 이유 : 상속시 객체가 만들어져야 하기 때문이다
		
		DefaultClass dc = new DefaultClass();
		
	}
}

코드를 보면 안드로이드 추상클래스는 객체를 생성하게 되면 오류가 발생하지만 안드로이드 추상 클래스를 상속한 디폴트 클래스의 인스턴스는 생성이 되었다. 안드로이드 추상 클래스에도 기본 생성자가 있지만 인스턴스 생성을 위해서가 아닌 상속시 조상 클래스의 객체가 생성되어야하기 때문이다. (상속 후 객체 생성 과정은 TIL_210323 참고)

 


라이브러리 추가 및 자바로 엑셀 파일 다루기

이클립스_자바 라이브러리 추가 확인

 

이클립스_자바 라이브러리 추가

라이브러리 추가하는 방법 자바 관련 라이브러리를 추가하는 방법 1. Build Path - Configure Bulid Path 혹은 Properties 2. Libraries 탭 클릭 3. Add External JARs.. 클릭 후 외부라이브러리 추가 4. Libra..

jy-beak.tistory.com

 

외부 라이브러리를 이클립스에 추가한 후 해당 라이브러리를 이용하여 이클립스에서 자바로 엑셀파일을 생성하고 직접 작성할 수 있다. 아래는 엑셀 파일 생성 및 쓰고 저장하는 과정이다.

 

1. 파일 다루기 위한 File 객체 생성

   File f = new File("uri " + ".xls"); (구버전은 .xls , 신버전은 .xlst)

 

2. 엑셀 파일 구조 : Workbook.createWorkbook(File 객체); => WritableWorkbook 객체 반환 (Workbook은 클래스명)

    WritableWorkbook wb = Workbook.createWorkbook(File 객체);

 

3. sheet 생성 : wb.createSheet(sheet 생성 : wb.createSheet("sheet명", sheet 위치(index)); => WritableSheet 반환 

    WritableSheet s1 = wb.createSheet("첫번째 시트", 0);

 

4. 입력 받을 수 있는 Label 객체 생성 : new Label(열번호, 행번호, "데이터")  

    Label label = new Label(0, 0, "데이터"); (첫번째 열, 첫번째 행)

 

5. 생성된 시트의 기본 셀에 라벨 객체 추가

    s1.addCell(label);

 

6. 실제 적용(쓰기)

    wb.write();

7. 파일 저장 후 닫기

    wb.closee();

 

 

엑셀 파일을 생성하고 데이터를 작성하는 ExcelWriterClass

package com.bjy;

import java.io.File;

import jxl.Workbook;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;

public class ExcelWriterClass {

	public ExcelWriterClass() {
		
	}
	
	public void createExcel() {
		String uri =  "c:/filetest/data.xls";
		File f = new File(uri);
		// 외부 라이브러리도 같이 사용하기에 import시 주의
		
		WritableWorkbook wb = null;
		// jxl.write.WritableWorkbook
		
		
		
		try {
			wb = Workbook.createWorkbook(f);
			
			WritableSheet s1 = wb.createSheet("첫번째 시트", 0);
			
			for(int i=0;i<10;i++){
				Label label = new Label(0,i, "data.." + i);
				s1.addCell(label);
			}
			
			wb.write();
			wb.close();
			
		}catch (Exception e) {
			System.out.println("파일 저장 오류 : " +e.getMessage());
		}
	}

}

MainClass에서 ExcelWriterClass 실행시 

 

c:/filetest에 data.xls 파일 생성

 

data.xls 실행하면 시트명, data가 맞게 입력된 걸 볼 수 있다