네트워크 프로그래밍

TCP, UDP 통신

 

네트워크 프로그래밍

 

 

소켓을 사용하여 server 와 client 구성하여 데이터 수, 발신

 

package tcp;

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Ex01_server {
	public static void main(String[] args) throws Exception {
		// 서버소켓 클래스 객체 생성
		// 예외처리 필요, 12345 는 Port 번호
		ServerSocket server = new ServerSocket(12345);
		System.out.println("접속을 기다립니다!!!");
		
		// accept() - 클라이언트가 연결될때까지 기다리는 메소드
		// 즉, 클라이언트가 연결되어야 "클라이언트 연결되었습니다!!!" 문구가 실행됨
		// server.accept() 를 소켓 객체로 담아 접속 클라이언트의 정보를
		// sock 이라는 이름으로 저장한다
		Socket sock = server.accept();
		System.out.println("클라이언트 연결되었습니다!!!");
		
		// InputStream 이라는 객체 입력 클래스 객체를
		// 소켓을 통해 사용하겠다.
		InputStream is = sock.getInputStream();
		
		// 데이터 수신
		int readData = is.read();
		System.out.println("수신 데이터 : " + readData);
		
		is.close(); sock.close(); server.close();
	}
}

Server

 

package tcp;

import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Ex01_client {
	public static void main(String[] args) throws Exception {
		// 현재 학원 PC 아이피 : 192.168.42.118
		// Server socket 설정 포트번호 : 12345
		// 클라이언트는 소켓 클래스 객체로 서버에 연결 요청
		// 객체 생성 시 아이피 정보, 포트 정보가 들어감
		Socket sock = new Socket("192.168.42.118", 12345);
		System.out.println("클라이언트 실행!!!");
		
		// OutputStream ㅇ;라는 데이터 출력 클래스 객체를
		// sock 이라는 소켓을 통해 사용하겠다
		OutputStream os = sock.getOutputStream();
		
		Scanner input = new Scanner(System.in);
		System.out.print("수 입력 : ");
		int data = input.nextInt();
		
		// 데이터 전송
		os.write(data);
		os.close(); sock.close();
	}
}

Client

 

기본 스트림이 전송할 수 있는 값은 1 byte 단위이다.

1 byte = 0 ~ 255

 

만약 256 을 전송하였다면 0 으로 server 가 받으며, 257 을 전송하였다면 1 로 server 가 받는다.

그러므로 보조 스트림을 사용하여 문자열, 객체 등을 전송할 수 있게 해줘야 한다.

 

 

 

 

 

 

 

 

 

 

보조스트림을 사용하여 문자열을 수, 발신 하기

보조스트림 DataInput, DataOutput 클래스를 사용하여 문자열 수, 발신

 

package tcp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Ex02_server {
	public static void main(String[] args) throws Exception {
		// 서버 소켓 생성, 포트번호 10000
		ServerSocket server = new ServerSocket(10000);
		System.out.println("접속 대기....");
		
		// Socket 클래스로 클라이언트의 정보를 담아둠
		Socket sock = server.accept();
		
		// 현재 서버 접속자의 정보 출력
		System.out.println(sock.getInetAddress());
		
		InputStream in = sock.getInputStream();
		DataInputStream dis = new DataInputStream(in);
		
		// 수신한 데이터(문자열) 저장
		String readData = dis.readUTF();
		
		System.out.println("수신 데이터 : " + readData);
		
		// sock 에는 이미 클라이언트에 대한 정보가 들어있으므로
		// sock 을 이용하여 클라이언트로 데이터를 전송할 수 있음
		OutputStream os = sock.getOutputStream();
		DataOutputStream dos = new DataOutputStream(os);
		
		Scanner input = new Scanner(System.in);
		System.out.print("클라이언트로 전송할 데이터 입력 : ");
		String sendData = input.nextLine();
		dos.writeUTF(sendData);
		
		dis.close(); in.close();
		dos.close(); os.close();
		sock.close(); server.close();
	}
}

Server

 

package tcp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Ex02_client {
	public static void main(String[] args) throws Exception {
		// 로컬 루프백 주소인 127.0.0.1 로 지정, 포트 10000 으로 접속 시도
		Socket sock = new Socket("127.0.0.1", 10000);
		
		OutputStream out = sock.getOutputStream();
		DataOutputStream dos = new DataOutputStream(out);
		
		Scanner input = new Scanner(System.in);
		System.out.print("전송할 문자열 입력 : ");
		String data = input.nextLine();
		
		dos.writeUTF(data);
		
		InputStream is = sock.getInputStream();
		DataInputStream dis = new DataInputStream(is);
		String readData = dis.readUTF();
		
		System.out.println("수신 데이터 : " + readData);
		
		dos.close(); out.close();
		dis.close(); is.close();
		sock.close();
	}
}

Client

 

 

 

 

 

 

 

 

 

 

클라이언트 두 곳과 연결

클라이언트 두 곳과 연결, 우선 연결에 따라 연결 정보가 sock1, sock2 로 저장된다

 

package tcp;

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Ex03_server {
	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(12345);
		System.out.println("접속을 기다립니다...");
		
		// 접속 순서에 따라 sock01, sock02 로 클라이언트에 대한 정보를 저장한다
		Socket sock01 = server.accept();
		Socket sock02 = server.accept();
		System.out.println("접속 되었습니다.");
		
		// sock01 로부터 날아오는 데이터를 저장한다.
		// sock02 에서 날아온 데이터는 따로 저장되지 않는다...!!
		InputStream in = sock01.getInputStream();
		DataInputStream dis = new DataInputStream(in);
		
		String readData = dis.readUTF();
		System.out.println("수신 데이터 : " + readData);
		
		dis.close(); in.close(); sock01.close(); sock02.close();
		server.close();
	}
}

Server

 

package tcp;

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Ex03_client01 {
	public static void main(String[] args) throws Exception {
		Scanner input = new Scanner(System.in);
		Socket sock = new Socket("127.0.0.1", 12345);
		
		OutputStream out = sock.getOutputStream();
		DataOutputStream dos = new DataOutputStream(out);
		
		System.out.print("송신 데이터 입력 : ");
		String data = input.nextLine();
		dos.writeUTF(data);
		
		dos.close(); out.close(); sock.close(); input.close();
	}
}

Client01

 

package tcp;

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Ex03_client02 {
	public static void main(String[] args) throws Exception {
		Scanner input = new Scanner(System.in);
		Socket sock = new Socket("127.0.0.1", 12345);
		
		OutputStream out = sock.getOutputStream();
		DataOutputStream dos = new DataOutputStream(out);
		
		System.out.print("송신 데이터 입력 : ");
		String data = input.nextLine();
		dos.writeUTF(data);
		
		dos.close(); out.close(); sock.close(); input.close();
	}
}

Client02

 

 

 

 

 

 

 

 

 

 

객체를 직렬화하여 전송하기

직렬화 - 객체를 byte 형식으로 변환

객체는 byte 형식으로 직렬화하여 보내지 않으면 오류가 발생하기 때문에 꼭 직렬화 를 하여 전송해야 한다

직렬화하여 객체를 전송!!!! 직렬화 필수

 

package tcp;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Ex04_server {
	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(12345);
		System.out.println("접속 대기");
		Socket sock = server.accept();
		System.out.println("접속 되었음");
		
		InputStream in = sock.getInputStream();
		ObjectInputStream ois = new ObjectInputStream(in);
		
		Ex04_DTO dto = (Ex04_DTO)ois.readObject();
		System.out.println("수신 name : " + dto.getName());
		System.out.println("수신 addr : " + dto.getAddr());
		
		ois.close(); in.close(); sock.close();
		server.close();
	}
}

Server

 

package tcp;

import java.io.Serializable;

public class Ex04_DTO implements Serializable{
					// Serializable 상속하여 꼭 직렬화 해주기!
	private String name, addr;

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
}

DTO

 

package tcp;

import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Ex04_client {
	public static void main(String[] args) throws Exception {
		Socket sock = new Socket("127.0.0.1", 12345);
		
		Scanner sc = new Scanner(System.in);
		
		OutputStream out = sock.getOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(out);
		
		Ex04_DTO dto = new Ex04_DTO();
		System.out.print("이름 입력 : ");
		dto.setName(sc.next());
		System.out.print("주소 입력 : ");
		dto.setAddr(sc.next());
		
		oos.writeObject(dto);
		oos.close(); out.close(); sock.close();
	}
}

Client

 

 

 

 

 

 

 

 

 

 

쓰레드를 사용하여 다중 client 에게 데이터 전송받기

Thread 를 사용하지 않으면 클라이언트에게 응답을 받을때 하나씩 받거나 응답이 오지않으면 무한대기에 빠지기 때문에 쓰레드를 사용하여 다중의 데이터를 받아 처리한다

 

 

 

 

 

 

 

 

 

 

다자간 채팅 서버

다자간 채팅 서버 구현

 

기억할 것 : 소켓으로 클라이언트가 접속하면 서버는 ArrayList 를 사용하여 클라이언트의 Socket 정보를 배열로 저장한뒤 수신 받은 데이터를 변수로 다시 선언하여 OutputStream 을 사용하여 ArrayList 안에 담긴 Socket 정보로 다시 전송하는 형태

 

Server 의 Thread : 다중 클라이언트의 데이터를 전송받고 다시 연결된 클라이언트들에게 데이터를 전송하기 위해 사용

Client 의 Thread : 발신은 Thread 를 사용하지 않고 클라이언트에서 진행되며, Thread 를 사용하여 실시간으로 들어오는 데이터를 수신

 

package tcp;

import java.net.ServerSocket;
import java.net.Socket;

public class Ex06_server {
	public static void main(String[] args) throws Exception {
		
		ServerSocket server = new ServerSocket(12345);
		
		while(true) {
			System.out.println("접속을 기다립니다...");
			Socket s = server.accept();
			System.out.println(s.getInetAddress() + "님 접속");
			
			// 쓰레드 객체를 생성
			new Ex06_serverThread(s);
		}
	}
}

Server

 

package tcp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;

public class Ex06_serverThread extends Thread {
	// arr 변수를 static 으로 선언하여 모든 쓰레드가 공유하여 사용할 수
	// 있게끔 생성한다
	public static ArrayList<Socket> arr;
	static {
		arr = new ArrayList<>();
	}
	private Socket s;
	public Ex06_serverThread(Socket s) {
		// ArrayList 에 사용자들의 정보(소켓)를 저장
		arr.add(s);
		this.s = s;
		start(); // start 메소드 실행 시 run 메소드 자동 실행
	}
	@Override
	public void run() {
		try {
			// InputStream in = arr.get( arr.size()-1 ).getInputStream();
			
			// 현재 접속한 사용자로부터 데이터를 수신
			InputStream in = s.getInputStream();
			DataInputStream dis = new DataInputStream(in);
			while(true) {
				// 수신한 데이터를 변수에 저장
				// readUTF 메소드는 입력값이 들어올때까지 대기하다가 입력 값이
				// 들어오면 그때 메소드가 동작한다!!!!
				// 그러므로 빈 값을 클라이언트에게 무한으로 던지지 않는다
				String msg = dis.readUTF();
				for(Socket ss : arr) {
					// 배열로 저장된 현재 연결된 클라이언트들에게 수신 데이터를
					// 다시 전송
					OutputStream out = ss.getOutputStream();
					DataOutputStream dos = new DataOutputStream(out);
					dos.writeUTF(msg);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Server Thread

 

package tcp;

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Ex06_client01 {
	public static void main(String[] args) throws Exception {
		// 소켓 생성
		Socket sock = new Socket("127.0.0.1", 12345);
		OutputStream out = sock.getOutputStream();
		DataOutputStream dos = new DataOutputStream(out);
		
		Scanner sc = new Scanner(System.in);
		String msg = null;
		
		// 수신되는 데이터는 쓰레드 객체를 생성하여 수신
		Ex06_clientThread rcv = new Ex06_clientThread(sock);
		
		while(true) {
			// 클라이언트에서 전송하는 데이터는 while 문으로 계속 입력받음
			System.out.print("전송 데이터 입력 : ");
			msg = sc.nextLine();
			dos.writeUTF(msg);
		}
	}
}

Client01

 

package tcp;

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class Ex06_client02 {
	public static void main(String[] args) throws Exception {
		// 소켓 생성
		Socket sock = new Socket("127.0.0.1", 12345);
		OutputStream out = sock.getOutputStream();
		DataOutputStream dos = new DataOutputStream(out);
		
		Scanner sc = new Scanner(System.in);
		String msg = null;
		
		// 수신되는 데이터는 쓰레드 객체를 생성하여 수신
		Ex06_clientThread rcv = new Ex06_clientThread(sock);
		
		while(true) {
			// 클라이언트에서 전송하는 데이터는 while 문으로 계속 입력받음
			System.out.print("전송 데이터 입력 : ");
			msg = sc.nextLine();
			dos.writeUTF(msg);
		}
	}
}

Client02

 

package tcp;

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.Socket;

public class Ex06_clientThread extends Thread {
	Socket sock;
	public Ex06_clientThread(Socket sock) {
		// 클라이언트가 객체 생성할때 들고온 Socket 정보를 sock 으로 저장
		// 서로 다른 클라이언트가 접근하면 클라이언트 1개 당
		// 쓰레드 객체가 1개씩 신규로 생성된다
		this.sock = sock;
		start(); // 쓰레드에서 start 메소드가 실행되면 run 메소드도 자동으로 실행된다
	}
	@Override
	public void run() {
		try {
			// Socket 으로 연결된 서버에서 전달 받는 정보를 쓰레드를 사용하여
			// 메세지를 발신하면서도 독립적으로 계속 수신받게끔 설정
			InputStream in = sock.getInputStream();
			DataInputStream dis = new DataInputStream(in);
			while(true) {
				String data = dis.readUTF();
				System.out.println("수신 데이터 : " + data);
			}
		}catch (Exception e) {
		}
	}
}

Client Thread

 

 

- 프로그램 작동 순서 -

Server 에서 서버 소켓 생성 후 클라이언트가 접속하는 것을 대기

 

> 클라이언트 1 이 서버 소켓에 접속

> 서버쓰레드가 공유하는 arr 배열에 클라이언트 1의 소켓 정보를 저장

> 서버 쓰레드 1 과 클라이언트 1 쓰레드가 동시에 생성 및 작동

 

> 클라이언트 2 가 서버 소켓에 접속

> 서버쓰레드가 공유하는 arr 배열에 클라이언트 2의 소켓 정보를 저장

> 서버 쓰레드 2 와 클라이언트 2 쓰레드가 동시에 생성 및 작동

 

> 클라이언트 1에서 데이터를 전송

> 서버 쓰레드 1 에서 전송받은 데이터를 arr 배열에 존재하는 사용자정보(Socket)에 모두 전송

> 클라이언트 쓰레드 1, 2 는 서버쓰레드 1 에서 전송받은 데이터를 출력

 

> 클라이언트 2에서 데이터를 전송

> 서버 쓰레드 2 에서 전송받은 데이터를 arr 배열에 존재하는 사용자정보(Socket)에 모두 전송

> 클라이언트 쓰레드 1, 2 는 서버쓰레드 2 에서 전송받은 데이터를 출력

728x90

 

맥북을 구매하여 사용하는 김에 개발에 사용하는 IDE를 이클립스에서 인텔리제이로 변경해보려 한다.

 

 

⌥ : option

⌘ : command

⇧ : Shift

^ : control

 

 

맥북 자주 사용하는 단축키

⌘ + 방향키 한줄 이동
⌥ + 방향키 음절 별로 이동
fn + ⌫ delete
fn + ← Home 키
fn + → End 키
⌘ + ↑ Page Up 키
⌘ +  Page Down 키
⌘ + tab 윈도우의 Alt + Tab
⌘ + C 복사
⌘ + V 붙여넣기
⌘ + Z 되돌리기
   
   
   
   
   
⌥, ⌘, ⇧, ⇪, ⎋, ^  

 

 

 

인텔리제이 단축키

^ + Space Bar 자동 완성 ( 패키지 목록 띄워줌 )
⌘ + n 생성자, getter / setter 생성
⌘ + / 한 줄 주석
⌘ + Shift + / 여러 줄 주석
⌘ + Shift + ↑↓ 선택 코드 줄 위, 아래로 이동
⌘ + d 한 줄 복사
⌘ + 한 줄 삭제
Shift + ⌘ + Enter 구문 완성 ( ; 를 닫아준다 )
   
   
   
728x90

 

 

 

 

 

미니 프로젝트

- DB 를 연동하지 않아서 코드를 실행할때마다 데이터가 초기화 되는 문제를 파일로 객체 정보를 저장하여 해결해보자...!!!

 

 

 

회원 정보를 파일로 저장하고 등록, 확인, 탈퇴할 수 있는 프로그램

package file.main;

import java.util.Scanner;

import file.service.ServiceMember;
import file.service.ServiceMemberImpl;

public class MainClass {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int num;
		ServiceMember member = new ServiceMemberImpl();
		
		while(true) {
			System.out.println("1. 회원가입");
			System.out.println("2. 검 색");
			System.out.println("3. 회원 목록 보기");
			System.out.println("4. 탈 퇴");
			System.out.println("5. 종 료");
			System.out.print(">>>> : ");
			num = sc.nextInt();
			
			switch(num) {
			case 1 : 
				member.register();
				break;
			case 2 : 
				member.search();
				break;
			case 3 : 
				member.list();
				break;
			case 4 : 
				member.delete();
				break;
			case 5 : 
				System.out.println("프로그램을 종료합니다.");
				break;
			default : 
				System.out.println("잘못 입력하셨습니다.");
				break;
			}
		}
	}
}

MainClass

 

package file.service;

public interface ServiceMember {
	public void register();
	public void list();
	public void delete();
	public void search();
}

ServiceMember

 

package file.service;

import java.util.Scanner;

import file.dao.MemberDAO;
import file.dto.MemberDTO;

public class ServiceMemberImpl implements ServiceMember {
	private MemberDAO dao;
	public ServiceMemberImpl() {
		dao = new MemberDAO();
	}
	
	@Override
	public void register() {
		MemberDTO dto = new MemberDTO();
		Scanner sc = new Scanner(System.in);
		System.out.print("아이디 입력 : ");
		dto.setId(sc.next());
		System.out.print("이름 입력 : ");
		dto.setName(sc.next());
		
		dao.register(dto);
	}
	
	public void list() {
		String[] listFile = dao.getList();
		if(listFile.length == 0) {
			System.out.println("저장된 목록이 없습니다!!!");
		}else {
			for(int i=0; i<listFile.length; i++) {
				System.out.println(i + ". " + listFile[i]);
			}
		}
	}
	
	public void delete() {
		Scanner sc = new Scanner(System.in);
		String id;
		System.out.print("삭제할 id 입력 : ");
		id = sc.next();
		dao.delete(id);
	}
	
	public void search() {
		Scanner sc = new Scanner(System.in);
		String id;
		System.out.print("검색할 id 입력 : ");
		id = sc.next();
		MemberDTO d = dao.search(id);
		if(d != null) {
			System.out.println("id : " + d.getId());
			System.out.println("name : " + d.getName());
		}
	}
}

ServiceMemberImpl

 

package file.dto;

import java.io.Serializable;

import lombok.Data;

@Data
public class MemberDTO implements Serializable{
					// serializble 상속 받아 직렬화
	private String id, name;
}

MemberDTO

 

package file.dao;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import file.dto.MemberDTO;

public class MemberDAO {
	// 객체가 저장될 path 설정
	private String path = "E:\\0.핀테크\\members\\";
	
	// 파일 입출력에 관련된 객체들을 선언
	private FileInputStream fis;
	private FileOutputStream fos;
	private BufferedInputStream bis;
	private BufferedOutputStream bos;
	private ObjectInputStream ois;
	private ObjectOutputStream oos;
	
	// 객체를 외부로 전송....
	public void register(MemberDTO dto) {
		//  String p = path + dto.getId() + ".txt";
		
		// 파일 클래스의 기능들을 사용하기 위해 String 자료형이 아닌
		// File 클래스를 사용
		File p = new File(path + dto.getId() + ".txt");
		
		// 동일한 이름의 회원 파일이 있는지 확인
		if(p.exists()) {
			System.out.println("이미 존재하는 회원입니다.");
		}else {
			try {
				fos = new FileOutputStream(p);
				bos = new BufferedOutputStream(fos);
				oos = new ObjectOutputStream(bos);
				oos.writeObject(dto);
				
				oos.close(); bos.close(); fos.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println("회원가입 성공!!!!!");
		}
	}
	
	public String[] getList() {
		File file = new File(path);
		return file.list();
	}
	
	public void delete(String id) {
		File file = new File(path + id + ".txt");
		if(file.exists()) {
			file.delete();
			System.out.println(id + " 가 삭제되었습니다.");
		}else {
			System.out.println("존재하지 않는 회원입니다.");
		}
	}
	
	public MemberDTO search(String id) {
		File file = new File(path + id + ".txt");
		MemberDTO dto = null;
		if(file.exists()) {
			try {
				fis = new FileInputStream(file);
				bis = new BufferedInputStream(fis);
				ois = new ObjectInputStream(bis);
				dto = (MemberDTO)ois.readObject();
				ois.close();
				bis.close();
				fis.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}else {
			System.out.println("찾는 회원이 없습니다.");
		}
		return dto;
	}
}

MemberDAO

728x90

 

 

 

 

 

직렬화 ( Serializable )

직렬화 ( Serializable ) - 객체를 byte 로 형변환해서 저장하는 것

객체를 DB 에 저장할 때 객체 자체로는 저장이 불가능하기 때문에 byte 로 형태를 변환하여 DB 에 저장한다.

 

 

전송하려는 객체를 직렬화 ( serializable ) 하여 ObjectOutpuStream 을 사용하여 외부로 전송

 

 

외부로 전송하여 byte 형태 문자로 test.txt 에 저장되어 있는 Ex09DTO 자료형의 자료를 역으로 읽어오는 과정

ObjectInputStream 사용하여 객체를 읽어옴

728x90

 

 

 

 

 

 

오라클 DB 다운로드

 

Oracle Database 19c Download for Microsoft Windows x64 (64-bit)

Oracle Database 19c Grid Infrastructure (19.3) for Microsoft Windows x64 (64-bit) Contains the Grid Infrastructure Software including Oracle Clusterware, Automated Storage Management (ASM), and ASM Cluster File System. Download and install prior to install

www.oracle.com

Oracle DB 19c 버전을 사용해볼 것임

 

 

product 하단의 Oracle Database 클릭

 

 

오라클 데이터베이스 19c 다운로드 클릭

 

 

개별 구성요소 다운로드 클릭

 

 

클릭하여 다운로드

 

 

 

DB 를 피씨에 다운로드 받으면 피씨가 DB 가 된다.

만약 집에서 DB 작업을 하고 회사에서 DB 작업을 이어서 진행하고 싶은 경우에 DB 회사에서 제공하는 클라우드를 사용해서 연동하면 된다.

 

 

 

 

 

 

 

 

 

 

SQL Developer 다운로드

 

SQL Developer

Oracle SQL Developer는 무료 개발 환경으로 전통적인 배포 및 클라우드 배포 모두에서 Oracle Database의 관리를 간소화해 줍니다. 또한 PL/SQL 애플리케이션, 쿼리 도구, DBA 콘솔, 보고서 인터페이스 등의

www.oracle.com

 

 

Windows 64-bit with JDK 11 included 다운로드 버튼 눌러서 다운로드

 

728x90

 

 

 

 

 

파일 입, 출력 ( File I/O )

파일 입, 출력 ( File I/O )

 

 

 

 

 

FileOutputStream

 

새로 생성한 테스트 폴더에 파일이 존재하지 않음

 

package file;

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

public class Ex01 {
public static void main(String[] args) throws IOException {
	
	// 파일 경로 지정(E:\\0.핀테크\\test) 및 생성할 파일(\\test.txt) 설정
	File path = new File("E:\\0.핀테크\\test\\test.txt");
	
	// 내보내는 통로 OutputStream
	FileOutputStream fos = new FileOutputStream(path); // 위에서 설정한 경로 변수로 설정, 예외처리 throws 로 처리함
	fos.write( 97 ); // 예외처리 thorws 로 처리
	fos.write( 'a' ); // 예외처리 throws 로 처리
	// write() 메소드는 int 자료형과 byte 자료형만 입력할 수 있다
	fos.write("test".getBytes()); // 문자열을 처리하려면 byte 형으로 변환하여 사용해야 한다
	
	// 가져오는 통로 InputStream
	
}
}

파일 스트림 사용

 

위 코드 실행 후 파일이 생성된 모습

 

파일 내용 확인

 

package file;

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

public class Ex02 {
public static void main(String[] args) throws Exception {
	
	Scanner sc = new Scanner(System.in);
	// 경로 설정
	String path = "E:\\0.핀테크\\test\\test2.txt";
	// 파일 내보내는 통로인 FileOutputStream 생성
	FileOutputStream fos = new FileOutputStream(path);
	
	// 입력 내용 받기
	System.out.print("출력할 내용 입력 >> ");
	String  name = sc.next();
	
	// byte 형태로 문자열 전달하여 생성
	fos.write(name.getBytes());
	System.out.println("내용이 저장되었습니다!");
	
}
}

텍스트 입력받은 후 생성되는 파일 확인

 

파일이 정상적으로 생성된 모습

 

package file;

import java.io.File;

public class Ex03 {
public static void main(String[] args) {
	// 문자열로 경로를 생성하는 경우 문자열에 존재하는 메소드만 사용할 수 있다
	String sPath = "c:/test/";
	
	// 하지만 경로를 File 자료형으로 선언하면 File 클래스에 존재하는 메소드를 사용할 수 있다
	File fPath = new File("E:\\0.핀테크\\abcd");
	fPath.mkdir(); // abcd 디렉토리 생성
	fPath.delete(); // abcd 디렉토리 삭제
	
	fPath = new File("E:\\0.핀테크");
	// list() 메소드는 반환 형태가 String[] 배열
	String[] s = fPath.list();
	// 존재하는 파일 갯수
	System.out.println(s.length); // 7 출력
	for(String a : s) {
		System.out.println(a);
		// eclipse-java
		// eclipse-java-2023-03-R-win32-x86_64.zip
		// jdk-11.0.22_windows-x64_bin.exe
		// test
		// test-home
		// test_git
		// workspace-java
	}
	
	// 현재 생성된 경로가 존재하는지 확인하는 exists() 메소드
	// 존재하면 : true, 존재하지 않으면 : false
	System.out.println(fPath.exists()); // true 출력
}
}

경로를 파일 객체로 생성하여 사용하는 이유, 파일 자료형의 메소드 종류

 

package file;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

public class Ex04 {
public static void main(String[] args) throws IOException {
	Scanner sc = new Scanner(System.in);
	
	// 파일 경로는 입력받지 않고 미리 설정해두었음
	String path = "E:\\\\0.핀테크\\test";
	
	// 파일명 입력받는 부분
	System.out.print("생성할 파일명 입력 >>> ");
	String fileName = sc.nextLine();
	
	// File 자료형으로 경로를 설정 + 사용자가 입력한 파일명을 내용에 추가
	File filePath = new File(path + "\\" + fileName + ".txt");
	
	// 파일을 전송하기 위해 fileOutputStream 객체 생성
	// FileOutputStream fos = new FileOutputStream(filePath);
	// FileOutputStream 를 사용하여 파일을 생성 시 이미 해당 이름의 파일이 존재하면
	// 기존 파일을 덮어씌운다
	
	// 파일이 존재하는지 확인 후 없다면 파일 생성
	if(filePath.exists()) { 
		// 만약 같은 이름으로 파일이 존재한다면
		System.out.println("이미 존재하는 파일입니다.");
	}else {
		// 같은 이름으로 파일이 존재하지 않는다면
		FileOutputStream fos = new FileOutputStream(filePath);
		String msg;
		System.out.print("내용을 입력하세요 >>> ");
		msg = sc.nextLine();
		fos.write(msg.getBytes());
		System.out.println("저장 되었습니다.");
	}
}
}

FileOutputStream 의 경우 기존에 파일이 존재하는데 새로 생성하려고할 때 기존 파일을 파기해버린 후 새로 생성한다

그래서 파일을 생성할땐 해당 이름의 파일 또는 디렉토리가 이미 존재하는지 여부를 확인 후 진행해야 한다

 

 

 

 

 

FileInputStream

 

package file;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class Ex06 {
public static void main(String[] args) throws Exception {
	String path = "E:\\\\0.핀테크\\test\\test.txt";
	FileOutputStream fos = new FileOutputStream(path, true);
	// path 뒤에 true 값은 파일이 존재하면 기존 내용을 유지하면서 내용을 추가하겠다는 뜻
	// 만약 해당 파일이 없으면 파일을 새로 생성하는 것은 동일하다
	
	// true 가 들어갔으므로 기존에 test.txt 파일이 존재한다면
	// 해당 파일의 내용 뒤에 a 라는 내용을 추가하여 저장한다
	fos.write('a');
	
	fos.close(); // 열려있는 stream 을 닫아 메모리를 효율적으로 관리한다
	
	fos = new FileOutputStream(path, true);
	fos.write('c');
	fos.close();
	
	
	FileInputStream fis = new FileInputStream(path);
	int re = fis.read();
	System.out.println((char)re); // 문자를 숫자형식으로 가져와서 a 의 int 값인 97 출력되기 때문에 char 형으로 변경
	while(true) {
		re = fis.read();
		if(re<0) {
			System.out.println();
			System.out.println("내용이 없습니다 : " + re);
			break;
		}
		System.out.print((char)re);
	}
	fis.close();
}
}

파일의 내용을 읽어오는 방법

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

보조 스트림 ( BufferedOutputStream )

 

package file;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;

public class Ex07 {
public static void main(String[] args) throws Exception {
	String path = "E:\\\\0.핀테크\\test\\test.txt";
	FileOutputStream fos = new FileOutputStream(path);
	
	// 보조 스트림
	// 파일을 매번 접근하지 않고 한번에 파일 작업을 모아서 한번 접근하여 모두 처리하게끔 해줌
	BufferedOutputStream bos = new BufferedOutputStream(fos);
	
	for( char ch='0' ; ch<='9' ; ch++ ) {
		Thread.sleep(1000);
		
		// fos.write(ch);
		// 파일에 1초마다 1, 2, 3, 4, 5, 6, 7, 8, 9 내용이 순차적으로 저장됨
		// 문자 하나를 입력할때마다 파일에 한번씩 접근함 -> 처리 속도가 느리다
		
		bos.write(ch); // 반복문을 돌면서 저장된 123456789 데이터를 보조 스트림에 모아놓은 상태
	}
	bos.flush(); // 보조스트림에 저장된 내용을 파일로 보내주는 flush() 메소드
	bos.write("안녕하세요".getBytes());
	bos.flush();
	
	bos.close(); // 메모리를 효율적으로 사용하기 위해 스트림을 종료
	fos.close(); // 메모리를 효율적으로 사용하기 위해 스트림을 종료
}
}

보조 스트림 ( BufferedOutputStream ) 을 사용하는 이유

- 문자를 입력받을 때 한꺼번에 처리하기 위해

 

 

 

 

 

보조 스트림 ( DataInputStream )

DataInputStream 을 사용하는 이유는 보조스트림 중 하나인 BufferedOutputStream 이나 FileOutputStream 의 경우 값을 입력할 때 byte 자료형이나 int 자료형밖에 사용할 수 없지만 DataInputStream 은 문자열이나 double 자료형 등을 형변환 하지 않고 입력할 수 있다.

 

package file;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class Ex08 {
public static void main(String[] args) throws Exception {
	String path = "E:\\\\0.핀테크\\test\\test.txt";
	FileOutputStream fos = new FileOutputStream(path);
	BufferedOutputStream bos = new BufferedOutputStream(fos);
	DataOutputStream dos = new DataOutputStream(bos);
	
	// writeUTF - 문자열 한글 입력 가능
	dos.writeUTF("안녕하세요");
	dos.writeInt(123456);
	dos.writeDouble(0.12345);
	dos.close(); bos.close(); fos.close();
	
	FileInputStream fis = new FileInputStream(path);
	BufferedInputStream bis = new BufferedInputStream(fis);
	DataInputStream dis = new DataInputStream(bis);
	
	// 파일에 저장된 순서대로 값을 읽어와야 한다
	String msg = dis.readUTF();
	int num = dis.readInt();
	double dou = dis.readDouble();
	System.out.println(msg); // 안녕하세요
	System.out.println(num); // 123456
	System.out.println(dou); // 0.12345
	
}
}

보조 스트림 ( DataInputStream ) 을 사용하는 이유

728x90

 

 

 

 

 

롬복 적용 방법

 

JavaC

 

projectlombok.org

상단 탭에서 Download 를 눌러 lombok 을 다운로드 받아서 사용한다.

 

다운로드 받은 lombok.jar 파일을 잘라내서

 

이클립스가 존재하는 파일 경로에 붙여넣기 이후 이클립스를 닫는다

 

eclipse.ini 파일을 메모장으로 열어준 뒤

 

아래 두 줄 추가 후 저장후 종료 후 이클립스 실행

 

install - javac 클릭

 

해당 내용 프로젝트 안에 module-info.java 파일에 내용 추가

 

module-info.java 안에 내용 추가한 모습

 

롬복을 사용할 패키지에서 우클릭 - Properties 클릭

 

Java Build Path - Libraries - Modulepath 클릭 후 우측에 add External JARs... 박스 클릭

 

설치한 lombok.jar 선택 후 열기

 

정상적으로 올라갔으면 Apply and Close 선택 후 이클립스 재부팅

 

롬복을 설치하면 어노테이션 형태로 getter / setter 와 필드 값을 모두 포함한 생성자 선언, 기본 생성자 선언 등을 어노테이션으로 간단하게 선언할 수 있다.

@getter - getter 메소드 생성

@setter - setter 메소드 생성

@Data - getter / setter, toString(), equalsAndHashCode() 를 모두 생성

@NoArgsConstructor - 기본 생성자 생성

@AllArgsConstructor - 필드 값을 모두 포함한 생성자를 생성

 

어노테이션 선언 이후 정상적으로 생성자나 getter / setter 가 생성되는지 확인해야 한다.

 

 

추가적인 롬복의 어노테이션 종류는 " 롬복 어노테이션 종류 " 를 검색하여 찾아서 사용하면 된다.

728x90

 

 

 

 

 

회원 관리 프로젝트

현재 사용하는 DB 가 없으므로 DAO 를 생성하여 ArrayList 객체를 생성하여 DataBase 를 구현

회원관리 기능은 구현 완료, 로그인 기능은 미구현

 

DAO - 데이터베이스에서 가져온 데이터를 객체로 변환하여 비즈니스 로직에서 사용할 수 있도록 함

DTO - Service와 DB를 연결하는 역할

 

package collection.main;

import java.util.Scanner;

import collection.service.MemberService;
import collection.service.MemberServiceImpl;

public class MainClass {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int num;
		MemberService ms = new MemberServiceImpl();
		while(true) {
			System.out.println("1. 회원관리");
			System.out.println("2. 로그인기능");
			System.out.print(">>> : ");
			num = sc.nextInt();
			switch(num) {
			case 1 : 
				ms.display();
				break;
			case 2 : 
				// 미구현
				break;
			}
		}
	}
}

MainClass 클래스

 

package collection.service;

public interface MemberService {
	// 중간자 역할
	public void register();
	public void memberViews();
	public void display();
	public void search();
}

MemberService 인터페이스 ( 구현해야 하는 메소드를 정의 )

 

package collection.dto;

public class MemberDTO {
	private String name, addr;
	
	// getter/setter
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
}

MemberDTO 클래스 ( 데이터베이스에서 가져온 데이터를 객체로 변환하여 비즈니스 로직에서 사용할 수 있도록 함 )

 

package collection.dao;

import java.util.ArrayList;

import collection.dto.MemberDTO;

public class MemberDAO {
	// DAO = Data Access Object
	// DAO 는 특정 저장소에 연결하는 역할을 함
	
	// 현재 DB 가 존재하지 않기 때문에 데이터를 유지하기 위해
	// static 으로 생성
	public static ArrayList<MemberDTO> arr;
	
	// arr 초기화 - 	다음과 같이 static 으로 초기화 하는 이유는 초기화 하면서 코드를
	//				추가할 수 있기 때문
	static {
		arr = new ArrayList<>();
	}
	
	// 데이터를 ArrayList 에 저장하는 역할
	public void register(MemberDTO dto) {
		System.out.println("dao register 연동");
		// System.out.println( dto.getName() );
		// System.out.println( dto.getAddr() );
		arr.add(dto);
	}
	
	// 데이터를 반환하는 역할
	public ArrayList<MemberDTO> getData() {
		return arr;
	}
	
	public MemberDTO search(String name) {
		for(MemberDTO a : arr) {
			if(a.getName().equals(name)) {
				return a;
			}
		}
		return null;
	}
	
	public MemberDAO() {
		
	}	
}

MemberDAO 클래스 ( Service와 DB를 연결하는 역할 )

 

package collection.service;

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

import collection.dao.MemberDAO;
import collection.dto.MemberDTO;

public class MemberServiceImpl implements MemberService {
	// MemberService 를 상속 받아서 실제 기능을 구현
	MemberDAO dao;
	public MemberServiceImpl() {
		dao = new MemberDAO();
	}

	@Override
	public void register() {
		System.out.println("회원 가입 기능입니다!!!!");
		String name, addr;
		MemberDTO dto = new MemberDTO();
		Scanner sc = new Scanner(System.in);
		
		System.out.print("이름 입력 : ");
		name = sc.next();
		System.out.print("주소 입력 : ");
		dto.setAddr(sc.next());
		dto.setName(name);
		dao.register(dto);
	}

	@Override
	public void memberViews() {
		System.out.println("멤버 보기 기능입니다!!!!");
		ArrayList<MemberDTO> arr = dao.getData();
		for(MemberDTO a : arr) {
			System.out.println("이름 : " + a.getName());
			System.out.println("주소 : " + a.getAddr());
			System.out.println("-----------------");
		}
	}
	
	public void display() {
		Scanner sc = new Scanner(System.in);
		int num;
		
		while(true) {
			System.out.println("1. 저장");
			System.out.println("2. 목록확인");
			System.out.println("3. 종료");
			System.out.println("4. 검색");
			System.out.print(">>> : ");
			num = sc.nextInt();
			switch(num) {
			case 1 : 
				register();
				break;
			case 2 : 
				memberViews();
				break;
			case 3 : return;
			case 4 : 
				search();
				break;
			}
		}
	}
	
	public void search() {
		Scanner sc = new Scanner(System.in);
		String name;
		System.out.print("검색할 이름 입력 : ");
		name = sc.next();
		MemberDTO m = dao.search( name );
		if( m == null ) {
			System.out.println(name + " 사용자는 존재하지 않습니다.");
		}else {
			System.out.println("사용자 이름 : " + m.getName());
			System.out.println("사용자 주소 : " + m.getAddr());
		}
	}
}

MemberServiceImpl 클래스 ( 실제 기능 구현부 )

728x90

+ Recent posts