빅데이터 Java 개발자 교육 - 19일차 [Oracle 4번째 시간 (JUnit test, @Param @Results 어노테이션, Hash 알고리즘)]

Jun_Gyu·2023년 2월 26일
0
post-thumbnail

지난시간 SELECT의 구문순서와 eclipse 연동에 대해서 실습들을 진행하였다.

다시 한번 더 복습하고 넘어가도록 하자!

복습

SELECT 구문의 순서

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT

  • FROM : 어느 테이블을 대상으로 할 것인지를 먼저 결정 (어디서 데이터를 가져올것인지)

  • WHERE : 해당 테이블에서 특정 조건(들)을 만족하는 ROW들만 선별 (어떤 데이터만 선별할것인지)

  • GROUP BY : row 들을 그루핑 기준대로 그루핑, 하나의 그룹은 하나의 row로 표현됨 (어떤 기준으로 분류할건지)

  • HAVING : 그루핑 작업 후 생성된 여러 그룹들 중에서 특정 조건(들)을 만족하는 그룹들만 선별 (분류가 끝난 데이터를 어떻게 다시 분류할건지)

  • SELECT : 모든 컬럼 또는 특정 컬럼들을 조회. SELECT절에서 컬럼 이름에 alias(AS)를 붙인게 있다면 이 이후 단계(ORDER BY, LIMIT)부터는 해당 alias 사용 가능 (어떤 데이터를 표시할건지)

  • ORDER BY : 각 row를 특정 기준에 따라서 정렬 (어떻게 보기좋게 나열할건지)

  • LIMIT : 이전 단계까지 조회된 row들 중 일부 row들만들 추림 (어디까지만 조회할건지)

-- 1. 먼저 "어디서" 데이터를 가져올건지 정한다.
SELECT * FROM "purchaseview" ;  // *은 전체를 뜻함. 세부사항은 아직 설정하지 않음.

-- 2. 다음으로 어떤 데이터만 "선별" 할건지 정한다.
SELECT * FROM purchaseview WHERE " usergender = 'M' "; 

-- 3. 그다음으로, "기준"을 정한다.
SELECT * FROM purchaseview WHERE usergender = 'M' GROUP BY "TO_CHAR (regdate, 'MM')";

-- 4. 그리고 "표시할 데이터"를 입력해준다.
SELECT "TO_CHAR (regdate, 'MM') 월별, SUM(cnt),  구매수량" 
FROM purchaseview WHERE usergender = 'M' GROUP BY TO_CHAR (regdate, 'MM');

-- 5.그리고 "나열할 방법"을 입력해준다.
SELECT TO_CHAR (regdate, 'MM') 월별, SUM(cnt) 구매수량 
FROM purchaseview WHERE usergender = 'M' GROUP BY TO_CHAR (regdate, 'MM') "ORDER BY SUM(cnt) ASC";

-- 6. 최종코드
SELECT TO_CHAR (regdate, 'MM') 월별, SUM(cnt) 구매수량 
FROM purchaseview WHERE usergender = 'M' GROUP BY TO_CHAR (regdate, 'MM') ORDER BY SUM(cnt) ASC;

오늘은 지난번 배달의 민족을 구현하기 위해서 만든 설계도를 바탕으로 실습을 진행하는 시간을 가질 것이다.

먼저 식당테이블이다.

// 식당 조회
SELECT * FROM restaurant ORDER BY phone ASC;

// 식당 등록
INSERT INTO restaurant (phone, name, address, password)
    VALUES('051-524-1002', '한식', '부산 서구', 'd');
    COMMIT;

Oracle에서의 문법.



하지만 우리는 지난시간 eclipse에 식당에 대해서 구현을 해둔상태이다.

구현되어있는 기능들을 사용해서

이번에는 메인에서 실행하는것이 아니라,

따로 테스트를 해보는 기능을 구현해보도록 하겠다.

JUnit Test 사용하기

  • 기초설정법

테스트 기능을 사용하기 위해서 버전을 맞춰 줄 필요가 있겠다.

먼저 'oracle'에서 우클릭을 후

맨 아래의 Properties를 클릭한다.

사진에는 JUnit5가 있는데, 추가를 하지 않았다면 원래 없는것이 맞다!

이후 Java Build Path의 Libraries 항목에서

Classpath를 선택한 이후

Add Library를 선택,

JUnit을 누른뒤 NEXT,

제일 높은버전인 5버전으로 추가해주도록 한다.

추가가 완료되었다면

이제 테스트 기능을 사용할 패키지와 클래스를 만들어주도록 하자.

먼저 패키지를 생성해주었다.

이후 패키지를 눌러 새로운 클래스를 생성하는데,

일반 클래스를 생성하는것이 아니라

Java 항목의 맨 아래에 있는

JUnit 폴더의 JUnit Test Case를 눌러서 클래스를 생성해주도록 하자.

(그래야 온전히 기능을 사용할 수 있다!)

완성하게 되면 이러한 모습의 클래스가 생성된다.

이제 여기에 메인문에서 작성해주었던 코드들을 옮겨 하나씩 한번 작성해보도록 하자.​

먼저 식당추가 기능을 시험해보겠다.

식당Mapper에서 기능을 가져오고, 항목을 추가하는 코드는 메인에서 작성한것과 동일하다.

실행을 시키는 방법도 어렵지 않다.

- test 실행시키기

test패키지에 방금 만들었던 클래스를 하위목록으로 열어,

실행하고자 하는 메소드를 우클릭하여 Run As의 'JUnit Test'를 눌러준다.

이렇게 하는 이유는

테스트 하고자 하는 메소드만 골라서 기능을 실행해볼 수 있기 때문이다.

실행을 하게되면..

정상적으로 코드가 동작할 시 초록불,

오류가 발생한다면 이렇게 오류문과 함께 빨간불이 들어오게 된다.

그렇다면 이제 주석처리를 할 필요가 없어진 새로운 테스트 클래스로 기능을 하나씩 시험해보도록 하겠다.

package mapper;

import java.util.List;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import dto.Restaurant;

@Mapper
public interface RestaurantMapper {

	// String[] str ={"a","b","c"}
	@Insert({
		" INSERT INTO restaurant( phone, name, address, password  ) " ,
		" VALUES( #{phone}, #{name}, #{address}, #{password} ) "
	})
	public int insertRestaurant( Restaurant obj );

	
	@Select({
		" SELECT r.* FROM restaurant r " 
	})
	public List<Restaurant> selectRestaurantList();
	


	//------------------------------------------- 0223 실습 추가---------------------------------------------------
	
	@Update({ // 식당 정보변경 (식당이름, 주소) + 기본키정보
		" UPDATE restaurant SET name =#{name}, address =#{address}",
		" WHERE phone =#{phone} " 
	})
	public int updateRestaurant( Restaurant obj );
	
	
	@Update({ // 식당 비밀번호 변경 {(변경할 비밀번호) + 조건 = (기본키) AND (현재암호)}
		" UPDATE restaurant  SET password =#{newPassword} ",
		" WHERE phone =#{phone} AND password=#{password} "
	})
	public int updateRestaurantPassword( Restaurant obj );

}

이번엔 테스트 클래스의 코드를 구성해보겠다.​

package test;

import java.util.List;

import org.junit.jupiter.api.Test;

import connection.MyBatisContext;
import dto.Restaurant;
import mapper.RestaurantMapper;

class RestaurantMapperTest {
	
	// 테스트 Mapper 객체 생성
	RestaurantMapper rmapper = MyBatisContext.getSqlSession().getMapper(RestaurantMapper.class);
	
	// 식당정보 변경(이름, 주소)
	@Test
	void updateRestaurant() {
		Restaurant obj = new Restaurant();
		obj.setPhone("080-123-4567");
		obj.setName("끝내주는 돼지국밥");
		obj.setAddress("부산시 동래구 온천동");;
		
		int ret = rmapper.updateRestaurant(obj);
		System.out.println(ret);
	}
	
	// 식당 비번 변경
	@Test
	void updateRestaurantPassword() {
		Restaurant obj = new Restaurant();
		obj.setPassword("1q2w3e4r!");
		obj.setPhone("051-000-1005");
		obj.setNewPassword("12341234");
		
		int ret = rmapper.updateRestaurantPassword(obj);
		System.out.println(ret);
	        }
     }
}

위를 실행시키고 DB를 확인해보면


잘 적용이 된 모습이다.


Java에서 코드를 작성하기 이전에 반드시 Oracle에서 쿼리문을 작성한 이후에 Java에서 실행시키도록 하자.


다른 예제 문제들도 한번 풀어보도록 하자.

package mapper;

import java.util.List;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import dto.Restaurant;

@Mapper
public interface RestaurantMapper {

	// String[] str ={"a","b","c"}
	@Insert({ " INSERT INTO restaurant( phone, name, address, password  ) ",
			" VALUES( #{phone}, #{name}, #{address}, #{password} ) " })
	public int insertRestaurant(Restaurant obj);

	@Select({ " SELECT r.* FROM restaurant r " })
	public List<Restaurant> selectRestaurantList();

	// --------------------02월23일 실습 추가------------------------------

	@Update({ // 식당 정보변경 (식당이름, 주소) + 기본키정보
			" UPDATE restaurant SET name =#{name}, address =#{address}", " WHERE phone =#{phone} " })
	public int updateRestaurant(Restaurant obj);

	@Update({ // 식당 정보변경 @Param (식당이름, 주소) + 기본키정보
			" UPDATE restaurant SET name =#{obj.name}, address =#{obj.address}", " WHERE phone =#{obj.phone} " })
	public int updateRestaurantParam(@Param("obj") Restaurant obj);

	@Update({ // 식당 비밀번호 변경 {(변경할 비밀번호) + 조건 = (기본키) AND (현재암호)}
			" UPDATE restaurant  SET password =#{newPassword} ", " WHERE phone =#{phone} AND password =#{password} " })
	public int updateRestaurantPassword(Restaurant obj);

	@Select({ // 식당 로그인
			" SELECT * FROM restaurant WHERE phone =#{phone} AND password =#{password} " })
	public List<Restaurant> loginRestaurant(Restaurant obj);

	@Select({ // 식당 로그인 @Param
			// 명칭 부여 (@Param("obj") Restaurat obj);
			" SELECT * FROM restaurant WHERE phone =#{ph} AND password =#{pw} " })
	public Restaurant loginRestaurantParam(@Param("ph") String phone,@Param("pw") String password);

	@Select({ // 식당 1개조희 (조회니까 비밀번호는 노출되면 안됨!!)
			" SELECT phone, name, address FROM restaurant WHERE phone =#{phone} " })
	public List<Restaurant> selectOneRestaurant(Restaurant phone);

}

Mybatis의 SQL 문장에 다수의 파라미터를 전달할 때는 전달되는 변수들에 꼭

"@Param 어노테이션"

을 써주도록 한다.

오늘 진행하는 실습에는 위의 어노테이션을 자주 사용하고 있으니 참고하도록 하자.​

package test;

import java.util.List;

import org.junit.jupiter.api.Test;

import connection.MyBatisContext;
import dto.Restaurant;
import mapper.RestaurantMapper;

class RestaurantMapperTest {
	
	// 테스트 Mapper 객체 생성
	RestaurantMapper rmapper = MyBatisContext.getSqlSession().getMapper(RestaurantMapper.class);
	

	// 식당추가 테스트
	@Test
	void insertRestaurant() {
		Restaurant obj = new Restaurant();
		obj.setPhone("051-000-1005");
		obj.setName("부산돼지국밥");
		obj.setPassword("1q2w3e4r!");
		obj.setAddress("부산 동래구");;

		int ret = rmapper.insertRestaurant(obj);
		System.out.println(ret);
	}

	// 식당목록조회 테스트
	@Test
	void selectRestaurantList() {
		List<Restaurant> list = rmapper.selectRestaurantList();
		for(Restaurant obj : list) {
			System.out.println(obj.toString());
		}
		
	}
	
	// 식당정보 변경(이름, 주소)
	@Test
	void updateRestaurant() {
		Restaurant obj = new Restaurant();
		obj.setPhone("080-123-4567");
		obj.setName("끝내주는 돼지국밥");
		obj.setAddress("부산시 동래구 온천동");;
		
		int ret = rmapper.updateRestaurant(obj);
		System.out.println(ret);
	}
	
	// 식당 비번 변경
	@Test
	void updateRestaurantPassword() {
		Restaurant obj = new Restaurant();
		obj.setPassword("1q2w3e4r!");
		obj.setPhone("051-000-1005");
		obj.setNewPassword("12341234");
		
		int ret = rmapper.updateRestaurantPassword(obj);
		System.out.println(ret);
	}
	
	// 식당로그인
	@Test
	void loginRestaurant() {
		Restaurant obj = new Restaurant();
		obj.setPhone("051-000-1005");
		obj.setPassword("12341234");
		List<Restaurant> list = rmapper.loginRestaurant(obj);
		for(Restaurant ret : list) {
		System.out.println(ret.toString());
		}
	}
	
	// 식당 로그인 @Param
	@Test
	void loginRestaurantParam() {
		String ph = "051-000-1005";
		String pw = "12341234";
		Restaurant obj = new Restaurant();
		obj = rmapper.loginRestaurantParam(ph, pw);
		System.out.println(obj);
		}
	
	

	// 식당 한개만 조회하기 
	@Test
	void selectOneRestaurant() {
		Restaurant obj = new Restaurant();
		obj.setPhone("051-000-1005");
		List<Restaurant> list = rmapper.selectOneRestaurant(obj);
		for(Restaurant ret : list) {
			System.out.println(ret.toString());
		}
		
	}
	
	
}

위의 방법으로 Test클래스를 만들어 각각의 기능들을 수행하도록 구성하였다.

이번에는 메뉴 테이블 구현 실습이다.

package dto;

import java.util.Date;

import lombok.Data;

@Data
public class Menu {
	// 메뉴테이블

	// 메뉴번호(시퀀스)
	private Long no;
	// 메뉴명
	private String name;
	// 가격
	private Long price;
	// 메뉴설명
	private String content;
	// 등록일자
	private Date regdate;
	// 전화번호
	private String phone;
	
	
	// 임시변수
	private String strPrice;
	private String strRegdate;
	private long discountPrice; 
}

'임시변수'를 지정해준 이유는

쿼리문에서 'SET'으로 새롭게 지정해주는 값들에 대해서

입출력이 가능하도록 하기 위해서 지정해주는 것이다.

package mapper;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.type.JdbcType;

import dto.Menu;

public interface MenuMapper {

	@Insert({ " INSERT INTO menu ( no, name, price, content, phone ) ",
			" VALUES( seq_menu_no.NEXTVAL, #{name}, #{price}, #{content}, #{phone} ) " })
	public int insertMenu(Menu menu);

	@Select({ " SELECT m.* FROM menu m ORDER BY name ASC " })
	public List<Menu> selectMenuList();

	@Update({ " UPDATE menu SET name =#{name}, price =#{price}, content=#{content} ",
			" WHERE no=#{no} AND  phone =#{phone} " })
	public int updateMenu(Menu menu);

	@Delete({ " DELETE FROM menu WHERE no=#{no} AND phone=#{phone}" })
	public int deleteMenu(Menu menu);

	// ------02/23 실습진행---------------------------------------------------
	// 메뉴등록
	@Insert({ " INSERT INTO menu (no ,name, price, content, regdate, phone) ",
			" VALUES(seq_menu_no.NEXTVAL, #{N}, #{Pr}, #{C}, CURRENT_DATE, #{Ph}) " })
	public int newInsertMenu(@Param("N") String name, @Param("Pr") long price, @Param("C") String content,
			@Param("Ph") String phone);

	// 메뉴변경 (이름, 가격, 내용)
	@Update({ " UPDATE menu SET name =#{N}, price =#{N}, content =#{N} WHERE phone =#{N} AND no =#{N} " })
	public int newUpdateMenu();

	// 메뉴삭제
	@Delete({ " DELETE FROM menu WHERE no=#{N} AND phone=#{P} " })
	public int newdeleteMenu(@Param("N") int no, @Param("P") String phone);

	// 해당 식당의 전체메뉴조회(가격에 3자리 콤마 추가, 등록일은 년월일만 표시)
	@Select({ " SELECT name, TO_CHAR(price, '999,999,999')strPrice, ",
			" TO_CHAR(regdate, 'YYYY-MM-DD')strRegdate, content FROM menu WHERE phone =#{Ph} " })
	public List<Menu> selectMenuAll(@Param("Ph") String phone);

	// 할인률0.3을 전달하면 discountPrice컬럼이 추가된 해당 식당의 전체메뉴 조회
	@Select({ " SELECT name, TO_CHAR(price, 'FM999,999')strPrice, TO_CHAR(regdate, 'YYYY:MM:DD')strRegdate, content, ",
			" FLOOR(price * (1 - #{D}))discountPrice FROM menu WHERE phone =#{Ph} "
	})
	public List<Map<String, Object>> selectMenuDiscountPrice(@Param("D") float discount, @Param("Ph") String phone);


	// ------------------------아래가 사실 생략되어있는것임.--------------------------------
	// CLOB = > byte
	@Results({
		@Result(column = "CONTENT", property = "컨텐츠내용",              // column에 해당하는항목을 property로 바꾼다.
				javaType = String.class, jdbcType = JdbcType.CLOB) // javaType은 바꾸려는 항목의 형태를 지정해준다.
	})
	// ------------------------ 여기까지 ---------------------------------------------------
	@Select({
		" SELECT name, TO_CHAR(price, 'FM999,999')strPrice, TO_CHAR(regdate, 'YYYY:MM:DD')strRegdate, content, ",
		" FLOOR(price * (1 - #{D}))discountPrice FROM menu WHERE phone =#{Ph} "
})
	public List<Map<String, Object>> selectMenuDiscountPriceMap(@Param("D") float discount, @Param("Ph") String phone);

}

이번에도 똑같이 @Param 어노테이션을 사용해준 모습이다.

중간에 주석 처리문 사이의 코드를 참고하면,

@Results

라고 어노테이션이 지정되있는모습을 볼 수 있는데,

이는 쿼리문을 통해서 최종적으로 나오는 값의 '필드명'을 원하는대로 바꿔주는 역활을 한다.

(위의 사진처럼!)

@Results는 여러 갯수의 @Result 어노테이션들을 가질 수 있기 때문에,

결과적으로는 데이터들을 구분하기 쉽도록 상황에 따라서 사용할 수 있겠다.


다음으로는 테스트 클래스이다

package test;

import java.util.List;
import java.util.Map;

import org.junit.jupiter.api.Test;

import connection.MyBatisContext;
import dto.Menu;
import dto.Restaurant;
import mapper.MenuMapper;

class MenuMapperTest {
	// Mapper 객체 생성
	MenuMapper mapper = MyBatisContext.getSqlSession().getMapper(MenuMapper.class);

	// 메뉴등록
	@Test
	void newInsertMenu() {
		String name = "테스트메뉴";
		long price = 1000000;
		String content = "메뉴등록 테스트";
		String phone = "051-234-4123";
		int ret = mapper.newInsertMenu(name, price, content, phone);
		System.out.println(ret);
	}

	// 해당 식당의 전체메뉴조회(가격에 3자리 콤마 추가, 등록일은 년월일만 표시)
	@Test
	void selectMenuAll() { // Map을 쓰는 이유는 'Menu'클래스에는 
		List<Menu> list = mapper.selectMenuAll("051-224-5752");
		for(Menu obj : list) {
			System.out.println(obj.toString());
		}
	}
	
	// 할인률0.3을 전달하면 discountPrice컬럼이 추가된 해당 식당의 전체메뉴 조회
		@Test
		void selectMenuDiscountPrice() {
			List<Map<String, Object>> list = mapper.selectMenuDiscountPrice(0.3f, "051-224-5752");
			for(Map<String, Object> obj : list) {
				System.out.println(obj.toString());
			}
			
		}
		
		@Test
		void selectMenuDiscountPriceMap() {
			List<Map<String, Object>> list = mapper.selectMenuDiscountPriceMap(0.3f, "051-224-5752");
			for(Map<String, Object> obj : list) {
				System.out.println(obj.toString());
			}
		}
}

앞선 문제 1, 2 ,3번은 간단한 문제이기에 조금 더 심화과정인 4, 5번을 위주로 실행코드를 구성해보았다.

할인률이 0.3 (30%)이기 때문에 float 함수를 이용해서 값을 받아온 모습이다.



마지막으로 고객 테이블 실습이다.

package dto;

import java.util.Date;

import lombok.Data;

//고객테이블
@Data
public class Customer {
// 이메일
	private String email;
// 암호
	private String password;
// 연락처
	private String phone;
// 차단기능
	private int chk;
// 주소
	private String address;
// 등록일자
	private Date regdate;
}
package mapper;

import java.util.List;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import dto.Customer;

public interface CustomerMapper {
	// 고객 회원가입
	@Insert({ " INSERT INTO customer (email, password, phone, address, regdate) ",
			" VALUES( #{email}, #{password}, #{phone}, #{address}, CURRENT_DATE) " })
	public int insertCustomer(Customer obj);

	// 고객 로그인
	@Select({ " SELECT * FROM customer WHERE email =#{id} AND password =#{pw} " })
	public Customer selectCustomer(@Param("id") String id, @Param("pw") String pw);

	// 고객 회원정보 수정
	@Update({ " UPDATE customer SET phone = #{phone}, address = #{address} WHERE email =#{email} " })
	public int updateCustomer(Customer obj);

	// 고객 암호변경
	@Update({ " UPDATE customer SET password =#{newpw} WHERE email =#{id} "
	})
	public int updateCustomerPw(@Param("id") String id, @Param("newpw") String pw);

}

고객 테이블도 위와같이 코드 설정을 마무리해주었다.

그리고 고객 테이블 같은 경우에는

Mybatis에 추가해주지 않았기때문에 꼭 추가해주도록 하자..!

그래놓고 사진은 PurchaseMapper인건 비밀



Hash 암호화

여기서 한가지 새로운 알고리즘을 사용하여 암호를 집어넣으려고 한다.

기존의 암호는 DB에 저장될때 '123','abc'와 같이 간단한 값들을 입출력 시켰기때문에

보안에 매우 취약하였다.

하지만 이번에는 입력받을 암호를

암호화 알고리즘 과정을 거친 값으로

데이터베이스에 집어넣도록 하겠다.

위와 같은 과정을 거치는 이유는

DB의 데이터들이 유출되거나 도난당했을때를 대비하여

비밀번호가 유출되는것을 막기 위함이라고 볼 수 있다.

// 암호와 아이디를 전달하면 64자의 암호로 변환하는 메소드
	public String hashPW(String id, String pw) {
		try {
			// 1. Hash알고리즘 SHA-256, 단방향 aa => 3asdfjkikewjwkj21k2km...
			MessageDigest md = MessageDigest.getInstance("SHA-256");
			// ex)A라는 사용자 1234(암호) + salt (사용자id)
			// ex)B라는 사용자 1234(암호) + salt (사용자id) (같은 암호를 치더라도 다른 암호키가 발생한다!)
			md.update((id + pw).getBytes());

			// byte to string으로 변경
			byte[] pwdSalt = md.digest();

			StringBuffer sb = new StringBuffer();
			for (byte b : pwdSalt) {
				sb.append(String.format("%02x", b));
			}
			String result = sb.toString();
			return result;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

먼저 오류를 잡기 위해서 try catch문으로 잡아주었다.

MessageDigest 이라는 클래스의 알고리즘("SHA-256") 를 이용하여

사용자의 암호값을 받아온 이후

"salt 값" (암호화 과정을 더 복잡하게 하기 위해 첨가하는 값) 을

입력받은 id값으로 지정하고

update()메소드를 이용하여 암호와 salt값을 각각을 더해준 뒤

지정된 바이트 데이터를 사용하여 digest를 갱신하고,

digest()메소드를 이용하여 해쉬값을 pwdSalt 라는 바이트 배열로 반환하게 된다.

이후 이 배열을 String으로 변환하는 과정을 거치게 되면

위와 같은 복잡한 암호화 키가 구현이 되게 되는 것이다.


이를 이용해서 한번 테스트 클래스를 구현해보았다.

package test;

import java.security.MessageDigest;
import java.util.List;

import org.junit.jupiter.api.Test;

import connection.MyBatisContext;
import dto.Customer;
import mapper.CustomerMapper;

class CustomerTest {
	CustomerMapper mapper = MyBatisContext.getSqlSession().getMapper(CustomerMapper.class);

	// 암호와 아이디를 전달하면 64자의 암호로 변환하는 메소드
	public String hashPW(String id, String pw) {
		try {
			// 1. Hash알고리즘 SHA-256, 단방향 aa => 3asdfjkikewjwkj21k2km...
			MessageDigest md = MessageDigest.getInstance("SHA-256");
			// ex)A라는 사용자 1234(암호) + salt (사용자id)
			// ex)B라는 사용자 1234(암호) + salt (사용자id) (같은 암호를 치더라도 다른 암호키가 발생한다!)
			md.update((id + pw).getBytes());

			// byte to string으로 변경
			byte[] pwdSalt = md.digest();

			StringBuffer sb = new StringBuffer();
			for (byte b : pwdSalt) {
				sb.append(String.format("%02x", b));
			}
			String result = sb.toString();
			return result;

		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}

	// 회원가입
	@Test
	void insertCustomer() {
		// 해쉬 비밀번호만 나오는 값.
		Customer obj = new Customer();
		obj.setEmail("junkue20@naver.com");
		obj.setPassword("123");
		obj.setPhone("010-0000-0003");
		obj.setChk(1);
		obj.setAddress("부산 서구");
		String hash = this.hashPW(obj.getEmail(), obj.getPassword());
		obj.setPassword(hash);
		int ret = mapper.insertCustomer(obj);
		System.out.println(ret);
	}

	// 고객 로그인
	@Test
	void selectCustomer() {
		String id = "junkue20@naver.com";
		String pw = "123";
		String hash = this.hashPW(id, pw);
		pw = hash;
		Customer list = mapper.selectCustomer(id, pw);
		System.out.println(list.toString());

	}

	// 고객 회원정보 수정
	@Test
	void updateCustomer() {
		Customer obj = new Customer();
		obj.setEmail("junkue20@naver.com");
		obj.setPassword("001001001");
		obj.setPhone("010-0000-0010");
		obj.setAddress("부산 서구");
		String hash = this.hashPW(obj.getEmail(), obj.getPassword());
		obj.setPassword(hash);
		int ret = mapper.updateCustomer(obj);
		System.out.println(ret);

	}

	// 고객 암호변경
	@Test
	void updateCustomerPw() {
		String id = "abcde";
		String pw = "77771";
		String hash = this.hashPW(id, pw);
		pw = hash;
		int ret = mapper.updateCustomerPw(id, pw);
		System.out.println(ret);
	}
}

모든 코드들이

정상 작동됨을 확인하였다.


profile
시작은 미약하지만, 그 끝은 창대하리라

0개의 댓글