0111 - 0117
0111
새로운 프로젝트
오늘부터 인공지능 포털 사이트 개발 프로젝트에 참여하여 풀스택 영역을 다루기로 했다.
우선 백엔드 API개발부터 시작하였다.
- 기존에 개발하던 API를 인수인계 받고 설명을 들었다.
- 스토리 보드를 참조하여 내가 할 일을 정하고, 어떻게 구현할지 고민했다.
- 개발 환경을 구축하고, 서버를 올리는 데 성공하였다.
- 스프링 부트에 대한 정보를 찾아보며 기본적인 흐름에 대해 이해하였다.
0112
- 회원과 관련된 API 개발을 맡아서 하게 되었다.
- 회원가입과 회원탈퇴하는 API를 생성했다.
- 회원가입 시 비밀번호를 SHA-256을 이용하여 암호화 해서 DB에 저장하였다.
public class SHA256Util {
/**
* SHA-256 암호화 함
* @param source 원본
* @param salt(String) SALT 값
* @return
*/
public static String getEncrypt(String source, String salt) {
return getEncrypt(source, salt.getBytes());
}
/**
* SHA-256 암호화 함
* @param source 원본
* @param salt(byte[]) SALT 값
* @return
*/
public static String getEncrypt(String source, byte[] salt) {
String result = "";
byte[] a = source.getBytes();
byte[] bytes = new byte[a.length + salt.length];
System.arraycopy(a, 0, bytes, 0, a.length);
System.arraycopy(salt, 0, bytes, a.length, salt.length);
try {
// 암호화 방식 지정 메소드
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(bytes);
byte[] byteData = md.digest();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xFF) + 256, 16).substring(1));
}
result = sb.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return result;
}
}
//사용
String password = user.getPassword();
password = SHA256Util.getEncrypt(password, salt);
user.setPassword(password);
처음으로 실제 프로젝트에서 사용하는 API를 개발하다보니 생각보다 고민해야 할 부분도 많았고, 코딩을 하기 전에 설계 측면에서 더 깊게 생각해야 한다는 것을 느꼈다.
0113
- 비즈니스 형식으로 이메일을 작성해보고 이를 이용해 정보를 공유했다.
- 로그인 시 쿠키를 생성해서 필요한 정보들을 쿠키에 저장하였다.
- 그리고 쿠키를 이용해서 백엔드 로직을 구현하였다.
Cookie[] loginCookies = new Cookie[4]; // 쿠키 설정
loginCookies[0] = new Cookie("email", login.getEmail());
loginCookies[1] = new Cookie("userNo", login.getUserNo() + "");
loginCookies[2] = new Cookie("userGbCode", login.getUserGbCode());
loginCookies[3] = new Cookie("userName", login.getUserName());
for (Cookie c : loginCookies) {
c.setPath("/");
c.setMaxAge(-1);
response.addCookie(c);
}
//쿠키정보를 체크해서 회원인지를 확인한다. user.email과 쿠키에 있는 이메일이 같은지 확인하다.
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for(Cookie c : cookies){
if ("email".equals(c.getName())) {
cookieEmail = c.getValue();
}
}
}
int emailCnt = userService.dupEmail(user); //DB에 이메일이 존재하면 1, 없으면 0 반환
if (emailCnt > 0) {
if(user.getEmail() == cookieEmail) {
//회원탈퇴처리
userService.withdraw(user);
//회원탈퇴가 제대로 처리 되면 쿠키를 삭제한다.
if (cookies != null) { // 쿠키가 한개라도 있으면 실행
for (Cookie c : cookies) {
c.setMaxAge(0); // 유효시간을 0으로 설정
c.setPath("/");
response.addCookie(c); // 응답 헤더에 추가
}
}
}
}
쿠키는 이전에도 학습했던 적이 있는데, 직접 프로젝트에 사용해보니 조금 더 이해가 잘 되었다. 쿠키를 이용해서 API에 접근하는 권한을 확인하였다.
0114
- 오늘은 스스로 여러가지 상황을 생각해서 오류 코드를 작성하였다.
- API를 작성하는데 기본이 되는 연동규격 정의서를 작성하고, 그에 맞게 API를 개발하였다.
- 직접 돌아가는 코드를 확인하고, 테스트를 시도하여 회원의 기본적인 CRUD를 할 수 있도록 설계 및 개발하였다.
- 로그인 시 쿠키를 생성할 때, ‘UTF-8’형식으로 인코딩하여 디코딩 시 예상한 결과가 출력되도록 코딩하였다.
0115
java.math.BigInteger클래스
- 정수형으로 표현할 수 있는 값의 한계가 있으므로, 더 큰 값을 다뤄야할 때 사용하면 좋은것이 BigInteger이다.
- 내부적으로 int배열을 사용해서 값을 다뤄서 long타입보다 훨씬 큰 값을 다룰 수 있다. 대신 성능은 long타입보다 떨어진다.
BIgInteger생성
생성하는 방법은 여러 가지가 있는데, 문자열로 숫자를 표현하는 것이 일반적이다. 정수형 리터럴로는 표혈할 수 있는 값의 한계가 있기 때문이다.
BigInteger val = new BigInteger("12345678901234567890"); //문자열로 생성
BigInteger val = new BigInteger("FFFF", 16); //n진수 문자열로 생성
BigInteger val = BigInteger.valueOf(1234567890L); //숫자로 생성
다른 타입으로의 변환
String toString() // 문자열로 변환
String toString(int radix) // 지정된 진법의 문자열로 변환
byte[] toByteArray() // byte배열로 변환
BigInteger의 연산
BigInteger에는 정수형에 사용할 수 있는 모든 연산자와 수학적인 계산을 쉽게 해주는 메서드들이 정의되어 있다.
BigInteger add(BigInteger val) // 덧셈(this + val)
BigInteger subtract(BigInteger val) // 뺄셈(this - val)
BigInteger multiply(BigInteger val) // 곱셈(this * val)
BigInteger divide(BigInteger val) // 나눗셈(this / val)
BigInteger remainder(BigInteger val) // 나머지(this % val)
- BigInteger는 불변이므로, 반환타입이 BigInteger이란 얘기는 새로운 인스턴스가 반환된다는 뜻
비트 연산 메서드
- 워낙 큰 숫자를 다루기 위한 클래스이므로, 성능을 향상시키기 위해 비트단위로 연산을 수행하는 메서드들을 많이 가지고 있다.
- 예를 들어 짝수는 제일 오른쪽 비트가 0일 것이므로, testBit(0)으로 마지막 비트를 확인하는 것이 더 효율적이다.
0116
java.math.BigDecimal클래스
BigDecimal은 실수형과 달리 정수를 이용해서 실수를 표현한다. 실수의 오차는 10진 실수를 2진 실수로 정확히 변환할 수 없는 경우가 있기 때문에 발생하는 것이므로, 실수를 정수와 10의 제곱의 곱으로 표현한다.
BigDecimal의 생성
생성하는 방법은 여러 가지가 있는데, 문자열로 숫자를 표현하는 것이 일반적이다. 기본형 리터럴로는 표혈할 수 있는 값의 한계가 있기 때문이다.
BigDecimal val = new BigDecimal("123.4567890"); //문자열로 생성
BigDecimal val = new BigDecimal("123.456"); // double타입의 리터럴로 생성
BigDecimal val = new BigDecimal("123456"); // int, long타입의 리터럴로 생성가능
BigDecimal val = BigDecimal.valueOf(123.456); //생성자 대신 valueOf(double)사용
BigDecimal val = BigDecimal.valueOf(123456); //생성자 대신 valueOf(int)사용
- 주의할 점은, double타입의 값을 매개변수로 갖는 생성자를 사용하면 오차가 발생할 수 있다는 것
다른 타입으로의 변환
String toPlainString() //어떤 경우에도 다른 기호없이 숫자로만 표현
String toString() //필요하면 지수형태로 표현할 수도 있음
- 대부분 두 메서드 반환결과가 같지만, BigDecimal을 생성할 때 ‘1.0e-22’와 같은 지수형태의 리터럴을 사용했을 때 다른 결과를 얻는 경우가 있다.
0117
HTTP 메서드 활용
클라이언트에서 서버로 데이터 전송
데이터 전달 방식 2가지
- 쿼리 파라미터를 통한 데이터 전송
- 주로 정렬 필터(검색어)
- 메시지 바디를 통한 데이터 전송
- 회원 가입, 상품 주문, 리소스 등록, 리소스 변경
4가지 상황
- 정적 데이터 조회
- 동적 데이터 조회
- HTML Form을 통한 데이터 전송
- HTTP API를 통한 데이터 전송
정적 데이터 조회
- 이미지, 정적 텍스트 문서
- 조회는 GET 사용
- 정적 데이터는 일반적으로 쿼리 파라미터 없이 리소스 경로로 단순하게 조회 가능
동적 데이터 조회
- 주로 검색, 게시판 목록에서 정렬 필터(검색어)
- 조회 조건을 줄여주는 필터, 조회 결과를 정렬하는 정렬 조건에 주로 사용
- 조회는 GET 사용
- GET은 쿼리 파라미터 사용해서 데이터를 전달
HTML Form 데이터 전송
- 회원 가입, 상품 주문, 데이터 변경시에는 POST 전송
- Content-Type: application/x-www-form-urlencoded 사용
- form의 내용을 메시지 바디를 통해서 전송(key=value, 쿼리 파라미터 형식)
- 전송 데이터를 url encoding처리
- HTML Form은 GET 전송도 가능하지만 조회에만 사용하고 리소스 변경이 발생하는 곳에 사용하면 안된다.
- Content-Type: multipart/form-data
- 파일 업로드 같은 바이너리 데이터 전송시 사용
- 다른 종류의 여러 파일과 폼의 내용 함께 전송 가능
- GET, POST만 지원
HTTP API 데이터 전송
- 서버 to 서버
- 백엔스 시스템 통신
- 앱 클라이언트
- 아이폰, 안드로이드
- 웹 클라이언트
- HTML에서 Form 전송 대신 자바 스크립트를 통한 통신에 사용(AJAX)
- ex) React, VueJs같은 웹 클라이언트와 API 통신
- POST, PUT, PATCH: 메시지 바디를 통해 데이터 전송
- GET: 조회, 쿼리 파라미터로 데이터 전달
- Content-Type: application/json을 주로 사용
HTTP API 설계 예시
회원 관리 시스템 API 설계 - POST 기반 등록
- 회원 목록 /members -> GET
- 회원 등록 /members -> POST
- 회원 조회 /members/{id} -> GET
- 회원 수정 /members/{id} -> PATCH, PUT, POST
- 회원 삭제 /members/{id} -> DELETE
POST - 신규 자원 등록 특징
- 클라이언트는 등록될 리소스의 URI를 모른다.
- 서버가 새로 등록된 리소스 URI를 생성해준다.
- HTTP/1.1 201 Created Location: /members/100
- 컬렉션(Collection)
- 서버가 관리하는 리소스 디렉토리
- 서버가 리소스의 URI를 생성하고 관리
- 여기서 컬렉션은 /members
파일 관리 시스템 API 설계 - PUT 기반 등록
- 파일 목록 /files -> GET
- 파일 조회 /files/{filename} -> GET
- 파일 등록 /files/{filename} -> PUT
- 파일 삭제 /files/{filename} -> DELETE
- 파일 대량 등록 /files -> POST
PUT - 신규 자원 등록 특징
- 클라이언트가 리소스 URI를 알고 있어야 한다.
- 클라이언트가 리소스의 URI를 지정한다.
- 스토어(Store)
- 클라이언트가 관리하는 리소스 저장소
- 클라이언트가 리소스의 URI를 알고 관리
- 여기서 스토어는 /files
HTML FORM 사용
- 회원 목록 /members -> GET
- 회원 등록 폼 /members/new -> GET
- 회원 등록 /members/new, /members -> POST
- 회원 조회 /members/{id} -> GET
- 회원 수정 폼 /members/{id}/edit -> GET
- 회원 수정 /members/{id}/edit, /members/{id} -> POST
- 회원 삭제 /members/{id}/delete -> POST
HTML FORM 특징
- HTML FORM은 GET, POST만 지원
- AJAX 같은 기술을 사용하여 해결 가능
- 컨트롤 URI
- GET, POST만 지원하므로 제약이 있음
- 이런 제약을 해결하기 위해 동사로 된 리소스 경로 사용
- POST의 /new, /edit, /delete가 컨트롤 URI
- HTTP 메서드로 해결하기 애매한 경우 사용(HTTP API 포함)