본문 바로가기

웹_프론트_백엔드/JAVA

2020.09.18(JAVA_심화반)

1. 로그인, 회원가입, 암호화, 복호화

** com.lec.java.user > User.java

package com.lec.java.user;

public class User {
	private String id;
	private String pw;
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPw() {
		return pw;
	}
	public void setPw(String pw) {
		this.pw = pw;
	}
}

 

** com.lec.java.user > Field.java

package com.lec.java.user;

import java.util.ArrayList;

public class Field {
	// 내부 DB
	ArrayList<User> users = new ArrayList<>();
	
	// 대칭키
	private final int KEY = 3;
	
	// 중복체크
	// 외부에서 전달받은 id와 저장소 users에 있는 각 회원별 아이디를
	// 반복해서 검사한다.
	public User checkId(String id) {
		User user = null;
		// 등록된 회원수만큼 반복한다.
		for (int i = 0; i < users.size(); i++) {
			// 각 회원별로 아이디를 가지고 온 후 전달 받은 id와 비교한다.
			if(users.get(i).getId().equals(id)) {
				// 만약 같은 아이디가 있다면 해당 객체를 user에 담아준다.
				user = users.get(i);
			}
		}
		// null 리턴시 중복 없음, null이 아닐 시 중복 있음.
		return user;
	}
	
	// 회원가입
	// 외부에서 회원가입시 작성한 정보들을 User 타입의 객체로 전달받는다.
	public void join(User user) {
		/*
		 * 여기서 아이디 중복 검사를 하게되면 사용자가 매우 불편해진다.
		 * 
		 * 왜냐하면...! 
		 * 정보 입력 후 아이디 중복 검사가 진행되고,
		 * 만약 아이디가 중복됬다면 다시 입력해야하는데 
		 * 이미 입력한 정보를 다시 입력해야 하는 것은 사용자 입장에서 매우 번거로운 일이다.
		 * 
		 * 이러한 번거로움을 해소하기 위해서는 main에서 아이디 입력할 때마다 아이디 중복 체크하고
		 * 중복이 없을때 join()을 통해 회원가입될 수 있도록 처리하면 된다.
		 */
		// 입력한 아이디가 중복이 없을 때 null
		//if(checkId(user.getId()) == null) {
		//	user.setPw(encrypt(user.getPw()));
		//	users.add(user);
		//}
		user.setPw(encrypt(user.getPw()));
		users.add(user);
	}
	
	// 로그인
	// 외부에서 사용자가 입력한 아이디와 비밀번호를 전달받는다.
	public boolean login(String id, String pw) {
		// 입력한 id가 저장소에 있는지 검사한다.
		User user = checkId(id);
		
		// user가 null이 아니라면 존재하는 아이디이다.
		if(user != null) {
			// 그 아이디를 갖고 잇는 회원과 비밀번호와 사용자가 입력한 비밀번호가 같으면 true
			if(decrypt(user.getPw()).equals(pw)) {
				return true;
			}
		}
		// 아이디 또는 비밀번호 오류시 false 리턴
		return false;
	}
	
	// 비밀번호는 대칭키 암호로 보안
	// 암호화
	public String encrypt(String pw) {
		String en_pw = "";
		
		for (int i = 0; i < pw.length(); i++) {
			en_pw += (char)(pw.charAt(i) * KEY);
		}
		return en_pw;
	}
	
	// 복호화
	public String decrypt(String en_pw) {
		String de_pw = "";
		
		for (int i = 0; i < en_pw.length(); i++) {
			de_pw += (char)(en_pw.charAt(i) / KEY);
		}
		return de_pw;
	}
}

 

** com.lec.java.user > Form.java

package com.lec.java.user;

import java.util.Scanner;

public class Form {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		Field user_field = new Field();
		
		User user = null;
		
		int choice = 0;
		
		String id = null;
		String pw = null;
		
		while(true) {
			System.out.println("1.회원가입\n2.로그인\n3.종료");
			choice = sc.nextInt();
			
			if(choice == 3) {break;}
			
			switch(choice) {
			// 회원가입
			case 1:
				user = new User();
				
				// 사용자의 번거로움을 줄이기 위해 main에서 아이디 중복 검사를 한다.
				// 중복된 아이디가 없을때만 해당 반복문을 벗어 날 수 있다.
				while(true) {
					System.out.print("아이디 : ");
					id = sc.next();
					if(user_field.checkId(id) == null) {break;}
					else {System.out.println("중복된 아이디입니다.");}
				}
				user.setId(id);
				System.out.print("비밀번호 : ");
				user.setPw(sc.next());
				
				user_field.join(user);
				break;
			// 로그인
			case 2:
				System.out.print("아이디 : ");
				id = sc.next();
				System.out.print("비밀번호 : ");
				pw = sc.next();
				
				if(user_field.login(id, pw)) {System.out.println("로그인 성공!");}
				else {System.out.println("로그인 실패");}
				break;
			// 그 외
			default:
				System.out.println("다시");
			}
		}
	}
}

 

 

2. Set

 : Set은 집합이다,
   요소가 중복되지 않도록 관리한다.
   

   public interface Set<E> extends Collection<E>

   
   저장된 값들은 인덱스가 없기 때문에 저장 순서가 고정되어 있지 않다.
   값이 있는지 없는지 검사하기 위한 목적이다.
   
   HashSet은 검색의 목적이 있기 때문에 순서 정보를 관리할 필요가 없어서
   데이터 크기에 상관없이 검색에 걸리는 시간이 매우 짧다.
   반면 ArrayList는 index를 관리해야 하기 때문에 상대적으로 시간이 오래 걸린다.
   
   "그러므로 기능적 차이가 없다면 HashSet을 사용해야 한다."



3. Set 예제

** com.lec.java.set > SetTest.java

package com.lec.java.set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SetTest {
	public static void main(String[] args) {
		// public interface Set<E> extends Collection<E>
		
		// 왜 Set으로 선언하고 생성은 HashSet으로 생성했을까?
		// Up Casting 이용, HashSet 말고도 다른 Set을 이용할 수 있기 때문에...!
		Set<String> bloodTypeSet = new HashSet<>();
		
		bloodTypeSet.add("A");
		bloodTypeSet.add("B");
		bloodTypeSet.add("O");
		bloodTypeSet.add("AB");
		bloodTypeSet.add("AB");
		bloodTypeSet.add("AB");
		bloodTypeSet.add("AB");
		bloodTypeSet.add("AB");
		bloodTypeSet.add("AB");
		bloodTypeSet.add("AB");
		bloodTypeSet.add("AB");
		bloodTypeSet.add("AB");
		
		System.out.println(bloodTypeSet);
		System.out.println(bloodTypeSet.size());
		bloodTypeSet.remove("AB");
		System.out.println(bloodTypeSet);
		
		System.out.println(bloodTypeSet.contains("A"));
		
		// set에 순서를 부여해야 꺼내올 수 있음, 순서를 부여하는 순간 더이상 set이 아니다!
		// set이 아니면 뭔데? Iterator<String>임.
		Iterator<String> iter = bloodTypeSet.iterator();
		
		System.out.println(bloodTypeSet.size() + "\n");
		//System.out.println(iter.next());
		//System.out.println(iter.next());
		//System.out.println(iter.next());
		//System.out.println(iter.next());	// 에러 : NoSuchElementException
		
		// 안에 얼마나 들어있는지 파악하기 어렵기 때문에 
		// 위의 코드 에러(NoSuchElementException)가 발생 가능성이 높음
		// 즉, 몇 번을 반복해야할지 모를때 아래의 코드를 이용하여 출력하면 
		// NoSuchElementException 에러를 예방 가능
		while(iter.hasNext()) {
			System.out.println(iter.next());
		}
	}
}

 

 

4. 위의 예제를 통해 Set은 왜 get이 없을까란 궁금증이 생길 수 있다.
   하지만 값을 가져오고 싶다면 순서가 있어야 하는데 Set은 순서가 없기 때문에 값을 가져올 수 없다.

   [그럼 Set은 어디서 사용할까?]
   검색 속도가 빠르다는 점을 이용하여 contains()를 통해 검사하는 용도로 많이 사용한다.
   사용 예) 컬쳐랜드 상품권, 쿠폰

 

 

5. ArrayList와 HashSet 속도 비교

 : 해당 예제를 통해 동일한 조건이라면 hashSet이 매우 빠르다는 것을 알 수 있다!

package com.lec.java.set;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.IntStream;

public class SpeedTest {
	public static void main(String[] args) {
		final int SIZE = 10_000_000;
		final List<Integer> arrayList = new ArrayList<Integer>(SIZE);
		final Set<Integer> hashSet = new HashSet<>(SIZE);
		final int data = 9_000_000;
		
		// 순차 병렬 집계연산
		IntStream.range(0, SIZE).forEach(value ->{
			arrayList.add(value);
			hashSet.add(value);
		});
		
		Instant start = Instant.now();
		arrayList.contains(data);
		Instant end = Instant.now();
		
		long elapsedTime = Duration.between(start, end).toMillis();
		System.out.println("arrayList : " + elapsedTime * 0.001 + "초");
		
		start = Instant.now();
		hashSet.contains(data);
		end = Instant.now();
		
		elapsedTime = Duration.between(start, end).toMillis();
		System.out.println("hashSet : " + elapsedTime * 0.001 + "초");
	}
}

 


6. Map
 : Key와 Value 한 쌍으로 저장하고 관리한다,
   그러므로 검색에 용이하다,
   [Key : Value] 한 쌍을 Entry라고 한다.
   
   구현 클래스 - HashMap
   Key는 중복이 없고, Value는 중복이 가능하다.

 

 

7. Map 예제

** com.lec.java.hashMap > HaspMapTest.java

package com.lec.java.hashMap;

import java.util.HashMap;
import java.util.Iterator;

public class HashMapTest {
	public static void main(String[] args) {
		HashMap<String, Integer> fruitMap = new HashMap<>();
		
		fruitMap.put("사과", 2000); 
		fruitMap.put("배", 2500); 
		fruitMap.put("자두", 1500); 
		fruitMap.put("수박", 8000); 
		System.out.println(fruitMap.get("사과"));
		System.out.println(fruitMap.get("사과") + 9);
		System.out.println(fruitMap);	// 전체적으로 리스트를 출력해보면 
						// HashMap도 순서가 없다는 것을 알 수 있다.
						// 순서가 있다고 오해할 수 있으나 입력한 순서로 출력이 되지 않았다.
		
		// Key만 필요할때 : keySet().iterator();
		//       리턴값 : Set<String>.Iterator<String> 
		Iterator<String> iter = fruitMap.keySet().iterator();
		while(iter.hasNext()) {
			System.out.println("과일 이름 : " + iter.next());
		}
		
		int total = 0;
		double avg = 0.0;
		// Value만 필요할때 : values();
		//         리턴값 : Collection<Integer>
		for(int price : fruitMap.values()) {
			System.out.println("과일 가격 : " + price + "원");
			total += price;
		}
		avg = Double.parseDouble(String.format("%.2f", (double)total / fruitMap.size()));
		System.out.println("과일 총 가격 : " + total + "원");
		System.out.println("과일 평균 가격 : " + avg + "원");
	}
}

 

 

8. HashMap 문제

 : 중국집에는 메뉴가 5개 있다.
   메뉴판 출력은 keySet(), values() 사용하고 총 가격, 평균 가격을 출력해보자!

 

1) 내 코드

** com.lec.java.hashMap > HashMapTaskMe.java

package com.lec.java.hashMap;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;

public class HashMapTaskMe {
	public static void main(String[] args) {
		// HashMap 사용
		// 중국집
		// 메뉴 5개
		// 메뉴판 출력(keySet(), values() 사용)
		// 총 가격, 평균 가격
		HashMap<String, Integer> menuMap = new HashMap<>();
		int choice = 0;
		
		while(true) {
			System.out.println("1.메뉴추가\n2.메뉴출력\n3.나가기");
			choice = new Scanner(System.in).nextInt();
			
			if(choice == 3) {break;}
			
			switch(choice) {
			// 메뉴 추가
			case 1:
				if(menuMap.size() < 5) {
					System.out.print("메뉴를 입력해주세요 : ");
					String menu = new Scanner(System.in).next();
					System.out.print("가격을 입력해주세요 : ");
					int price = new Scanner(System.in).nextInt();
					menuMap.put(menu, price);
				} else {
					System.out.println("메뉴가 꽉 차 있어서 더 추가 못합니다.");
				}
				break;
			// 메뉴판 출력
			case 2:
				Iterator<String> iter = menuMap.keySet().iterator();
				String[] menu = new String[menuMap.size()];
				int num = 0;
				while(iter.hasNext()) {
					menu[num] = iter.next();
					num++;
				}
				
				int total = 0;
				double avg = 0.0;
				int[] priceList = new int[menuMap.size()];
				num = 0;
				for(int price : menuMap.values()) {
					priceList[num] = price;
					total += price;
					num++;
				}
				
				avg = Double.parseDouble(String.format("%.2f", (double)total / menuMap.size()));
				
				// 메뉴판 출력
				for (int i = 0; i < menuMap.size(); i++) {
					System.out.println(menu[i] + " - " + priceList[i]);
				}
				// 총 가격, 평균 가격 출력
				System.out.println("메뉴 총 가격 : " + total + "원");
				System.out.println("메뉴 평균 가격 : " + avg + "원");
				break;
			default:
				System.out.println("잘못 입력하셨습니다~!");
			}
		}
	}
}

 

2) 강사님 코드

** com.lec.java.hashMap > HashMapTaskTeacher.java

package com.lec.java.hashMap;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

public class HashMapTaskTeacher {
	public static void main(String[] args) {
		// HashMap 사용
		// 중국집
		// 메뉴 5개
		// 메뉴판 출력(keySet(), values()사용)
		// 총 가격, 평균 가격
		ArrayList<Integer> prices = new ArrayList<>();
		HashMap<String, Integer> chinaFoodMap = new HashMap<>();
		
		chinaFoodMap.put("짜장면", 3500);
		chinaFoodMap.put("짬뽕", 4000);
		chinaFoodMap.put("탕수육", 8500);
		chinaFoodMap.put("양장피", 8500);
		chinaFoodMap.put("볶음밥", 4500);
		
		Iterator<String> iter1 = chinaFoodMap.keySet().iterator();
		Collection<Integer> col = chinaFoodMap.values();
		
		col.forEach(value -> prices.add(value));
		int cnt = 0;
		while(iter1.hasNext()) {
			String menu = iter1.next();
			System.out.print(menu + " - " + chinaFoodMap.get(menu) + "원" + "\t/\t");
			System.out.println(menu + " - " + prices.get(cnt++) + "원");
		}

		
		System.out.println("=====================================");
		// 한 쌍씩 모두 가져올 때에는 Entry타입으로 사용하고,
		// entrySet()을 사용해준다.
		Iterator<Entry<String, Integer>> iter2 = chinaFoodMap.entrySet().iterator();
		
		while(iter2.hasNext()) {
			// 각각의 next()는 Entry 타입이므로 Key, Value 모두 타입을 지정해주어야 한다.
			// Entry<K, V>
			Entry<String, Integer> entry = iter2.next();
			// getKey() : Key
			// getValue() : Value
			System.out.println(entry.getKey() + " - " + entry .getValue());
		}
	}
}



9. 다음 수업 내용 : 쓰레드

'웹_프론트_백엔드 > JAVA' 카테고리의 다른 글

2020.09.24(JAVA_심화반)  (0) 2020.09.26
2020.09.22(JAVA_심화반)  (0) 2020.09.25
2020.09.17(JAVA_심화반)  (0) 2020.09.18
2020.08.27(JAVA_심화반)  (0) 2020.08.28
2020.08.25(JAVA_심화반)  (0) 2020.08.25