230111 java 응용

kangjuju·2023년 1월 11일
0

Acorn

목록 보기
2/15

DTO,DAO,VO

DAO(Data Access Object)]

데이터베이스의 data에 접근하기 위한 객체.
DataBase에 접근 하기 위한 로직 & 비지니스 로직을 분리하기 위해 사용

VO(Value Object)

값 오브젝트로써 값을 위해 쓰인다.
read-Only 특징(사용하는 도중에 변경 불가능하며 오직 읽기만 가능)을 가진다
DTO와 유사하지만 DTO는 setter를 가지고 있어 값이 변할 수 있다.

DTO(Data Transfer Object)

계층 간 데이터 교환을 하기 위해 사용하는 객체로, 레코드(행)단위의 처리를 위함.
DTO는 로직을 가지지 않는 순수한 데이터 객체(getter & setter 만 가진 클래스)이다.

성격,타입이 다른 멤버들을 하나의 그룹으로 묶어서 데이터를 이동할때 적합하다. DB에 여러타입의 데이터들을 그룹화하여 저장시키기 위해 자주 사용됨.

[DTO클래스]

구조는 단순함. getter,setter와 필요할 멤버변수, 생성자뿐이다.
굳이 생성자와 get/setter를 필수로 둘다 넣을 필요는 없다.
기능에만 충실하면됨

public class _4StudentDTO {

	private String hakbun, irum;
	private int jumsu;

	public _4StudentDTO(String hakbun,String irum,int jumsu) {
		this.hakbun = hakbun;
		this.irum = irum;
		this.jumsu = jumsu;
	}
	public String getHakbun() {
		return hakbun;
	}
	public void setHakbun(String hakbun) {
		this.hakbun = hakbun;
	}
	public String getIrum() {
		return irum;
	}
	public void setIrum(String irum) {
		this.irum = irum;
	}
	public int getJumsu() {
		return jumsu;
	}
	public void setJumsu(int jumsu) {
		this.jumsu = jumsu;
	}
}

[_4DtoTest1]

ArrayList를 선언할때 제네릭으로 _4StudentDTO타입을 넣는것이 핵심이다.
데이터를 타입별로 넣을 insertList 메소드를 구현했다.
이 메소드는 학생들의 학번,이름,나이 받아 dto를 사용하여 ArrayList에 저장시킨다.

ArrayList<_4StudentDTO> list = new ArrayList<_4StudentDTO>();

	public void insertList() {        
		_4StudentDTO dto =null;
        
		dto = new _4StudentDTO();
		dto.setHakbun("han1");
		dto.setIrum("홍길동");
		dto.setJumsu(22);
		list.add(dto);  <<<<<<<< 
		
		dto = new _4StudentDTO();
		dto.setHakbun("han2");
		dto.setIrum("고길동");
		dto.setJumsu(52);
		list.add(dto); <<<<<<<<
		
		dto = new _4StudentDTO();
		dto.setHakbun("han3");
		dto.setIrum("신길동");
		dto.setJumsu(72);
		list.add(dto); <<<<<<<<
	}
  • 출력을 담당할 showList메소드를 구현했다.
public void showList() {
		System.out.println("학생수는 : " + list.size());
		for (int i = 0; i < list.size(); i++) {
			_4StudentDTO dto = new  _4StudentDTO();
			dto = list.get(i);
			System.out.println("학번 : "+dto.getHakbun());
			System.out.println("이름 : "+dto.getIrum());
			System.out.println("점수 : "+dto.getJumsu());
			System.out.println();
		}
	}

list.size로 리스트의 총 길이를 알아낼 수 있고 그걸 인원 수로 이용했다.
for문으로 list.size까지 증가하도록 하고
반복할때마다 dto객체 선언, 선언한 dto에 list.get으로 i번째 각각의 객체 주소를 가져온다. 그 후 getter로 출력.

[main]

public static void main(String[] args) {
		_4DtoTest1 dtoTest1 = new _4DtoTest1();
		dtoTest1.insertList();
		dtoTest1.showList();
	}

유저가 입력한 데이터를 DB에 넣는 과정

유저가 자신의 브라우저에서 데이터를 입력하여 form에 있는 데이터를 DTO에 넣어서 전송합니다.
해당 DTO를 받은 서버가 DAO를 이용하여 데이터베이스로 데이터를 집어넣습니다.

lombok 롬복

DTO클래스와 매우 밀접한 관련이 있는 어노테이션 기능이 있다.

롬복이란, 내부적으로 DTO와 같은 모델에서 변수를 지정하면 클래스에서 setter,getter,toString등 메소드를 자동으로 만들어 주는 기능이다.

@Setter  
@Getter
//@Data
@AllArgsConstructor //생성자
@NoArgsConstructor

public class _4StudentDTO2 {
	private String hakbun, irum;
	private int jumsu;
}

추가적인 메소드선언이 필요없음

문자열 분리클래스 StringTokenizer

StringTokenizer tokenizer = new StringTokenizer("문자열 객체 "," 기준을 삼고싶은 부호");

StringTokenizer tokenizer = new StringTokenizer("kbs,mbc,sbs",",");
		System.out.println(tokenizer);
		String s1 = tokenizer.nextToken();
		String s2 = tokenizer.nextToken();
		String s3 = tokenizer.nextToken();
		System.out.println(s1 + " / " + s2 + " / " + s3) ;

DTO 예제2

public class _5DtoTest2 {    <<<<<<<<<<<비즈니스 로직 정의>
	ArrayList<_5HaksaengDto> list;
    
	public _5DtoTest2() {
		 list = new ArrayList<_5HaksaengDto>();
	}
	public void inputList(String[] datas) {
		<문자열 분리 클래스- DTO  처리하기 좋게 분리하여 저장>
		for (int j = 0; j < datas.length; j++) {
			StringTokenizer tok = new StringTokenizer(datas[j],",");
			String irum = tok.nextToken();
			int kor =  Integer.parseInt(tok.nextToken());
			int eng =  Integer.parseInt(tok.nextToken());
			int mat =  Integer.parseInt(tok.nextToken());
			<여기서 DTO로 레코드단위로 만들자>
			_5HaksaengDto dto = new _5HaksaengDto();
			dto.setName(irum);
			dto.setKor(kor);
			dto.setEng(eng);
			dto.setMat(mat);
			list.add(dto); //총 한명의 자료가 list에 저장됨
		}
	}
	public void printList() {
		<list(컬렉션)에 저장된 자료로 뭔가를   있다. 여기서는 출력>
		System.out.println("학생명\t총점\t 평균");
		for (int i = 0; i < list.size(); i++) {
			_5HaksaengDto dto = new _5HaksaengDto();
			dto = list.get(i); <FIFO구조>
			int tot = dto.getEng()+dto.getKor()+dto.getMat();
			double avg = tot/3;
			System.out.println(dto.getName()+" \t"+tot+"\t "+avg);
		}
	}
	
	public static void main(String[] args) {
		String[] datas = new String[3];
		Scanner sc = new Scanner(System.in);
		System.out.println("이름, 국어, 영어, 수학 순으로 입력해주세요 : ");
		for (int i = 0; i < datas.length; i++) {
			datas[i] = sc.next();
		}
		_5DtoTest2 dtoTest2 = new _5DtoTest2();
		dtoTest2.inputList(datas);
		dtoTest2.printList();
	}
}

이름, 국어, 영어, 수학 순으로 입력해주세요 :
강주,100,20,30
주강,20,40,50
이강,40,20,70
학생명 총점 평균
강주 150 50.0
주강 110 36.0
이강 130 43.0

리뷰

_5HaksaengDto를 DTO모델 클래스로 만들어 놓았다.
main에서 3명의 자료를 입력받을 String타입 datas배열을 선언하였고
입력을 받았다.

input,print메소드를 사용하기 위해 _5DtoTest2 객체를 만들고 inputList메소드에 작성한 String배열을 넘겨주면서 호출했다.

한줄 한줄 순서대로 데이터를 처리하여 Arraylist에 저장하기 위해 for문을 사용했다.
한줄짜리 문자열 데이터를 DTO로 처리하려면 문자열을 구분자로 나눠 분리해서 변수에 저장해야한다. StringTokenizer 문자열 분리 클래스를 사용했다.

kor,eng,mat int변수를 만들고 박싱으로 String - int 변환하여 저장, 그것을 dto인스턴스 - getXX에 저장했다. 이렇게 만들어진 한명의 데이터객체를 list.add로 Arraylist에 저장했다. list의 첫번째 내용은 한명의 이름과 점수들이 저장되어있게 되는것.

DTO 예제 3

public class _6JikwonProcess {
	// 실행시 외부에서 사번, 이름, 기본급, 입사년도를 여러개 입력받고 출력
	ArrayList<_6JikwonDTO> list = new ArrayList<_6JikwonDTO>();
	int geunmu,geunsok,gongje,suryeong; //근무년수,근속수당,공제액,수령액
	
	public _6JikwonProcess(String[] args) {
		inputData(args);
		printData();
	}
	
	public void inputData(String[] args) {
		for (int i = 0; i < args.length; i++) {
			_6JikwonDTO dto = new _6JikwonDTO();
			StringTokenizer tok = new StringTokenizer(args[i],",");
			dto.setSabun(tok.nextToken());
			dto.setIrum(tok.nextToken());
			dto.setGibon(Integer.parseInt(tok.nextToken()));
			dto.setIbsa(tok.nextToken());
			list.add(dto); //dto처리 한 데이터를 컬렉션에 옮겨담기
		}
	}

	public void printData() {
		for (int i = 0; i < list.size(); i++) {
			_6JikwonDTO dto = new _6JikwonDTO();
			dto = list.get(i);
			
			LocalDate now = LocalDate.now();
			int year = now.getYear();
			geunmu = year-Integer.parseInt(dto.getIbsa()); <근무년수>
			
			<근속수당>
			if(geunmu <=3) geunsok = 150000;	
			else if(geunmu >= 4 && geunmu <= 8) geunsok = 450000;
			else geunsok = 1000000;
			
			if (dto.getGibon() + geunsok >= 3000000) {
				gongje = (int) ((dto.getGibon() + geunsok) * 0.05);
			} else if (dto.getGibon() + geunsok >= 2000000) {
				gongje = (int) ((dto.getGibon() + geunsok) * 0.03);
			} else {
				gongje = (int) ((dto.getGibon() + geunsok) * 0.015);
			}
			<수령액>
			suryeong = dto.getGibon() + geunsok - gongje; 
			
			System.out.println("사번" + "\t\t" + "이름" + "\t\t" + "기본급" + "\t\t" +"근무년수" + "\t" +"근속수당" + "\t\t" +"공제액" + "\t\t" +  "수령액");
			System.out.println(dto.getSabun()+" \t"+dto.getIrum()+"\t"+dto.getGibon()+" \t"+
													geunmu+" \t\t"+geunsok+"\t\t"+gongje+" \t"+suryeong);
		}
		System.out.println("처리 건수 : " + list.size());	
	}
	public static void main(String[] args) {
		if (args.length == 0) {
			System.out.println("입력 데이터 없음");
			System.exit(0);
		}		
		new _6JikwonProcess(args); //생성자로만 해결
	}
}

사번 이름 기본급 근무년수 근속수당 공제액 수령액
ko1 홍길동 300000 1 150000 6750 443250
ko2 나길동 4500000 7 450000 247500 4702500
ko3 김길동 2500000 23 1000000 175000 3325000
처리 건수 : 3

위처럼 생성자를 적극 이용해서 Main을 더 깔끔하게 사용할 수 있다.

파일 입출력

  • 스트림: 흐르는 데이터 혹은 파이프의 구조를 개념으로 한다.

  • 입출력 스트림: 데이터를 읽고 쓰는 구조를 프로그램의 구조로 만들어 놓은 것

  • 버퍼 : 데이터를 임시적으로 담아두는 공간

reference : https://cafe.daum.net/flowlife/HqLo/26

파일단위의 출력

		File f = new File("c:/work/iotest.txt");
		FileWriter fw = new FileWriter(f); 
		BufferedWriter bw1 = new BufferedWriter(fw,1024); 
		PrintWriter out1 = new PrintWriter(bw1);
		out1.println("문자열이 출력됨");
		out1.println("자바의 io는 불편하다");
		out1.close();
		bw1.close();
		fw.close();

File타입 객체를 만들고 Writer에게 파일객체를 넣어준다. 버퍼사용시 BufferedWriter를 거쳐준다.
흐름은 파일을 넣은 Writer를 넣은 버퍼에 넣은 객체를 PrintWriter에 넣은것이다.
사용을 위해 단계별로 객체를 다룬것.
close는 외부장치 열었을때의 역순으로 닫는다. 쓰던 자원을 다시 닫아줌

파일단위의 읽기

		try {
			File f2 = new File("c:/work/iotest.txt");
			FileReader fr = new FileReader(f2);
			BufferedReader br2 = new BufferedReader(fr);
			
			while(true) {
				String str = br2.readLine();
				if(str == null) break;
				System.out.println(str);
			}
			br2.close();
			fr.close();
		} catch (Exception e) {
			System.out.println("읽기오류 : " + e.getMessage());
		}

txt파일의 끝을 만날때까지 while문 반복을 사용.

입출력 Stream 응용

public class IOTest2File {
<1byte단위로 데이터 입출력 : 클래스 이름에 stream이 들어있다.>

	public void writeFile(File file, ArrayList<String> strList) { <파일 쓰기 메소드>
		try {
			BufferedWriter writer = new BufferedWriter
					(new OutputStreamWriter
							(new FileOutputStream(file),"UTF-8"));
			for(String str : strList) {
				writer.write(str,0,str.length()); <<<strList의 문자열  str. 0번째부터 str크기까지>
				writer.newLine(); <라인스킵>
			}
			writer.close();
		} catch (Exception e) {
			System.out.println("writeFile err: " + e.getMessage());
		}
	}

	public void readFile(File file) {  <파일 읽기 메소드>
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"));
			String one_line;
			StringBuffer sbuffer = new StringBuffer(); <문자열 담는용도>
			while((one_line = reader.readLine()) != null) {
				sbuffer.append(one_line+"\n");
			}
			reader.close();
			
			System.out.println(sbuffer.toString());
		} catch (Exception e) {
			System.out.println("readFile err: " + e.getMessage());
		}
	}

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<String>();
		list.add("ㅋㅋㅋㅋ");
		list.add("good");
		File file = new File("c:/work/iotest2.txt");

		IOTest2File test2file = new IOTest2File();
		test2file.writeFile(file, list);
		test2file.readFile(file);
	}
}

여러개의 문자열을 저장할 ArrayList를 선언했다.
list.add로 임의의 문자열을 추가해뒀고 File객체 선언시 매개변수로 경로와 txt파일 이름을 줬다.

위의 각 메소드(writeFile / readFile) 사용으로 파일 입출력을 했다.

파일에 문자열을 쓰기 위해 만든 writeFile 메소드

public void writeFile(File file, ArrayList<String> strList) { 
		try {
			BufferedWriter writer = new BufferedWriter
					(new OutputStreamWriter
							(new FileOutputStream(file),"UTF-8"));
			for(String str : strList) {
				writer.write(str,0,str.length()); //strList의 문자열  str. 0번째부터 str크기까지
				writer.newLine(); //라인스킵
			}
			writer.close();
		} catch (Exception e) {
			System.out.println("writeFile err: " + e.getMessage());
		}
	}

기본적으로 외부장치를 사용하는 것이기 때문에 try catch문으로 예외처리를 해놓는것이 좋다고 한다. try구간에 기능 구현을 하면 됨.

안정적인 데이터 입출력을 위해 데이터를 임시적으로 담아두는 공간인 버퍼를 사용했다.
첫 파일입출력 예제에서는 객체변수선언, 클래스 매개변수로 넣고 또다시 선언하는 과정으로 작성했지만 이번에는 매개변수란에 new 객체를 바로바로 적어줬다.

  • BufferedWriter : 문자출력 스트림에 연결되어 버퍼를 제공해 주는 보조 스트림
  • OutputStreamWriter : 바이트 출력 스트림에 연결되어 문자출력 스트림인 Writer로 변환시키는 등의 역할
  • FileOutputStream : 바이트 단위로 자료를 저장할 때 사용하는 바이트 기반 출력 스트림

보조 역할인 버퍼를 사이에 끼고 문자출력, 바이트 기반 출력 스트림을 이용하기 위해 3단계에 걸쳐 객체를 만든것. 맨 마지막엔 main에서 매개변수로 받았던 file(iotest2.txt)을 넘겨주면서 writer객체를 사용할 준비를 시켜놓았다.

향상 for문으로 ArrayList타입인 strList를 받고, writer.write();의 옵션으로 해당 문자열 배열의 0번째 부터 끝까지 txt파일에 쓰기를 진행했다.

파일의 문자열을 읽기 위해 만든 readFile 메소드

public void readFile(File file) {  
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(
            new FileInputStream(file),"UTF-8"));
			String one_line;
			StringBuffer sbuffer = new StringBuffer(); //문자열 담는용도
			while((one_line = reader.readLine()) != null) {
				sbuffer.append(one_line+"\n");
			}
			reader.close();
			
			System.out.println(sbuffer.toString());
		} catch (Exception e) {
			System.out.println("readFile err: " + e.getMessage());
		}
	}

위에서 writer객체를 만들기 위해 세가지 스트림을 사용했었다는 것을 기억해야한다. reader객체를 만들때는

  • BufferedReader
  • InputStreamReader
  • FileInputStream

라는 같은역할, 반대 성향을 가진 스트림을 사용했다.

임시로 사용할 String one_line변수와 문자열을 담는용도인 sbuffer를 선언했다.
while문으로 one_line이 null값이 아닐동안 반복하고 읽는다. append를 사용함

2바이트 이상의 파일 입출력은 객체선언시 아래 방법으로 대체가능하다.

BufferedReader reader = new BufferedReader(new FileReader(file));

BufferedWriter writer = new BufferedWriter(new FileWriter(file));

실제 데이터 파일 읽기

[data.go.kr 사이트가 지원하는 도서관 정보 csv문서 읽기]

data.go.kr 에서 용산구_도서관.csv 파일을 다운받았다.
StringTokenizer를 사용하기 위해 메모장 : 파일-바꾸기 기능으로 " 표시를 모두 지우고 ","로만 구분자로 사용할 수 있도록 텍스트 파일 전처리과정을 거쳤다.

public static void main(String[] args) {
		
		IOTest4Csv test4csv = new IOTest4Csv();
		test4csv.show();
	}

파일을 읽어 콘솔에 출력하는 show메소드를 정의

public void show() {
		try {
			File f = new File("c:/work/용산구_도서관.csv");
			FileReader fr = new FileReader(f);
			BufferedReader br = new BufferedReader(fr);
			
			int count = 0; 
            String ss = br.readLine();
			while(true) {
				count++;
				ss = br.readLine();       // 1행은 제목이므로 skip
				if(ss == null || count > 10) break; //ss가 끝나거나 10개만보기
				
				StringTokenizer tok = new StringTokenizer(ss,",");
				String s1 = tok.nextToken();
				String s2 = tok.nextToken();
				String s3 = tok.nextToken();
				System.out.println(s1 + "\t" + s2+ "\t" + s3);
			}
			System.out.println("건 수 :" + count);
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}

File타입 객체의 경로설정을 하고 그 객체를 읽기위해 FileReader, 안정적인 입출력을 위한 BufferedReader클래스를 사용했다. br을 사용하면 된다.

while 반복문 사용. 한바퀴 반복때마다 count변수를 1씩 증가시켜 확인 건 수 변수를 만들어 놓고, String ss변수는 txt파일의 한줄 한줄 저장하는 역할로 사용했다.
반복을 거듭할 수록 다음줄을 저장하는 역할이 될것

예를들면 String ss = 구립 청파도서관,서울특별시,용산구,공공도서관,월+법정공휴일,09:....

이렇게 문자열 한개가 ss에 저장되면 StringTokenizer의 구분자 ","을 사용해 각 열 요소를 저장,출력하고 다음차례 줄을 읽는 방식이다.

0개의 댓글