14일 한일

  • EC2 인스턴스에서 쉘스크립트를 통한 배포 자동화

  • EC2 인스턴스에 접근을 용이하게 하기 위해 password로 접속 허용

  • /etcs/hosts 에 엘라스틱IP에 대한 도메인 등록

  • 트렐로 테스트 코드 일부 수정

  • jQuery로 AJAX를 이용하는법 포스팅


15일 한일

트렐로 Boards 페이지(User, Member, Board) 구현 중 문제점 파악

  • 문제의 핵심은 DB/JPA

  • 객체가 테이블들에서 키값을 통해 연결되고, 키로 데이터들을 뽑아다가 쓰는 것에 익숙지 않다. 그러다 보니 모델 설계에 대한 진행이 안됨.

  • 차선책으로 과감하게 모델들은 고려 안 하고 구현해야 할 기능을 먼저 생각하고 그에 따라 필요한 모델의 형태를 정하기로 했다.

  • JPA에서 난항. ManyToOne, OneToMany, ManyToMany를 어떻게 설정해야 할지…


14~15일 느낀점

  • 쉘 스크립트를 통한 배포 자동화를 하다 보니까 EC2에 접속하는 게 상당히 번거롭게 느껴졌다. 그래서 패스워드를 통한 접속을 열고, hosts에 내 EC2 인스턴스에 대한 IP를 외우기 쉬운 이름으로 등록을 해두니까 한층 수월해졌다. 대신 그만큼 보완에 구멍이 생겼을 수도 있겠지만…

  • 확실히 자주 사용 안 하면 까먹는다. 그래서 jQuery로 AJAX를 이용하는 법에 대해 진짜 아주 간단히 포스팅 해뒀는데 나중에 필요할 때 요긴하게 쓰일 것 같다.

  • 테이블을 이용하는 게 익숙지 않다는 것을 깨달았다. 단순히 테이블들이 이미 만들어져 있어 crud를 이용하는 것이었다면 무난하게 진행했을 것 같다. 그러나 서로 관계가 엮인 테이블들은 어떻게 만들어야 할지 머릿속에 쉽게 안 들어 온다. 예를 들어 작성자, 게시글이 있으면 게시글이 작성자의 ID를 가지게 하는 것이 일반적인 것 같은데 왠지 작성자게시글을 가지게 하는 것이 자연스럽다고 느꼈다. 확실히 개념적인 글들만 머릿속에 들어 있었지 키값을 이용하여 db를 사용하는 것에 익숙지 않은 것 같다.

  • 정보처리기사나 생활코딩의 mysql 강의를 보고서 기초는 다졌다고 생각했는데 단순히 쿼리문을 읽고 간단한 쿼리에 대한 작성만 가능한 수준이지 데이터베이스를 다루는 것 자체는 안된다는 걸 깨달았다.

  • 확실히 모델을 먼저 고려 안 하니까 테이블들을 어떻게 짜야 할지 생각을 안 하고서 작업을 진행하게 되니까 멈춰있던 작업이 다시 시작됐다. 현재 Acceptance Test 코드부터 작성해 나가면서 어떤 형태로 모델이 있어야 할지 생각하면서 진행 중이다. 어느 정도 성공했다 생각했는데 역시나 ManyToOne, OneToMany, ManyToMany 관계에서 설정을 어떻게 줘야 할지 문제에 부딪치고, 기본적으로 관계 자체가 꼬여버려서 반쯤 멈춘 상태다…

    그래서 모델들 간의 관계를 조금 바꾸고 있는데 실마리가 조금씩 보이는 것 같다. 운이 좋다면 내일 중으로 끝날 것 같고, 아니라면 화요일까지 진행이 될 것 같은데 이번 고비만 잘 넘기고 나면 db를 다루는 일에 있어 한 단계 성장, 혹은 첫걸음을 떼게 될 것 같다. 게다가 보안을 제외한 다음 작업들에 속도가 붙을 것 같다.

    아! 한가지 더 고려해야 할 것은 프론트 단에서 데이터를 잘 받아 처리하는 것인데 이건 위의 문제가 해결된 다음 고민해 보자.

  • 잘하는 부분에 대해서도 좋지만, 못하는 부분일수록 TDD가 더욱 중요하다는 걸 느꼈다. 잘하는 부분에 대해서는 내가 구현한 코드가 잘 작동할 것이라는 확신을 느낀다.(거기에 제대로 된 테스트 코드까지 있다면 느낌이 아닌 사실이 되며, 테스트를 통해 검증을 한다) 하지만 못하는 부분에 대해서는 구현을 하고 나서도 잘 된 건지 아닌지 알 수가 없다. 그렇게 계속 구현하다가 운이 좋다면 아무 문제없이 완성이 되겠지만 어느 순간 문제가 생겼을 때 무엇이 문제인지 알 수 없는 총체적 난국인 상황이 온다. 게다가 작업이 진행될수록 잘 진행이 되고 있는 것인가에 대한 불안감이 점점 커진다.

    하지만 TDD로 구현을 하게 되면 내가 못하는 부분이라도 초록불이 뜨는 걸 보는 것으로 한고비를 넘겼다는 확신을 가질 수 있다. 그렇게 다음 작업으로 넘어가서 현재 진행해야 할 작업에만 집중을 할 수 있게 된다. 다만, TDD에 익숙해지는 것이 쉽지 않은 게 사실이다. 게다가 좋은(혹은 제대로 된) 테스트 코드를 짠 게 맞나 의문이 들 때가 있긴 하다. 잘못된 테스트 코드는 구현한 기능에 구멍을 만들 테니 말이다. ‘좋은 테스트 코드 짜기’ 이건 앞으로도 내 스스로 성장해 나가야 할 과제인 것 같다.


내일 할일

  • trello 구현하기

    • DB와 JPA에 대한 이해 및 사용
Elastic IP를 사용하여 EC2 인스턴스에 고정 아이피를 부여하는 방법

Elastic IP

EC2 인스턴스를 껐다 켤 때마다 아이피가 변경되는 경우를 많이 보셨을 겁니다. 이에 따른 불편을 느끼는 경우들이 있는데 이를 해결하기 위해 자신의 EC2 인스턴스에 고정 아이피를 연결하는 방법을 알아봅시다.

주의하실 점은 Elastic IP를 생성하고 EC2 인스턴스를 연결하여 사용하는 것은 무료지만 생성만 하고 인스턴스를 연결하지 않으면 비용이 발생합니다!! (저처럼 필요 없는 비용 내지 마세요….ㅜㅜ)


(한글 버전을 기준으로 설명 합니다.)

1. 일단 EC2 대시보드에서 엘라스틱 IP를 선택합니다.

엘라스틱Ip


2. 새 주소 할당 클릭

엘라스틱_새주소


3. 할당된 다음에 주소 연결 클릭

엘라스틱_주소연결


4. 자신의 인스턴스를 선택하고 연결 버튼을 클릭

엘라스틱_주소연결2


5. EC2 대시보드에서 인스턴스 항목을 가서 보면

엘라스틱_인스턴스

탄력적 IP라 해서 Elastic IP가 설정된 것을 볼 수 있습니다.

이제부터 해당 아이피를 이용해서 접근이 가능합니다.


주의사항

위에도 언급했지만 Elastic IP를 생성하고 EC2 인스턴스를 연결해서 사용을 안 하면 비용이 발생합니다.

연결해서 사용하던 인스턴스를 삭제할 경우 Elastic IP 쪽에선 연결된 인스턴스가 없는 상태가 됩니다. 그렇기 때문에 그렇게 놔두면 비용이 발생합니다!!(제 경우.. ㅜㅜ)

큰 비용은 아니지만 불필요한 지출을 늘릴 필요는 없기 때문에 Elastic IP을 생성 후 사용을 안 하면 비용이 발생한다! 이것만 까먹지 않으면 해당 기능을 정말 편하게 사용할 수 있습니다.

한두 번씩 프론트 작업을 할 때 어려운 것이 아니고, 이전에 적용해 본 것도 아직 익숙지 않다 보니 시간을 많이 쏟을 때가 있다. 그러한 시간을 줄이기 위해서 기록을 해둔다.

jQuery의 Ajax

일단 간단하게 jQuery의 ajax에 설정하는 값에 대해 보자.

$.ajax({
  type : `http method type`,
  url : `url`,
  data : `서버에 전송할 데이터`,
  contentType : "전송할 데이터 타입",
  //기본 값 : "application / x-www-form-urlencoded; charset = UTF-8"  
  dataType : '서버로 부터 수신할 데이터 타입',
  //아무것도 지정하지 않으면 jQuery는 응답의 MIME 유형을 기반으로 해석을 시도
  error : `에러 발생시 수행할 함수`,
  success : `성공시 수행할 함수`
});

좀 더 상세한 설명은 여기서 볼 수 있다.

(추가로 jQuery에서 .은 클래스, #은 아이디)


@RequestBody 사용시 적용법

현재 만들고 있는 트렐로 프로젝트에서 사용하고 있는 코드다.

@PostMapping("")
public ResponseEntity<Void> login(@RequestBody UserDto userDto, HttpSession session) {
  session.setAttribute("loginedUser", userService.login(userDto.toUser()));
  HttpHeaders headers = new HttpHeaders();
  return new ResponseEntity<Void>(headers, HttpStatus.OK);
}

@RequestBody를 사용하여 JSON 타입의 데이터로 값을 받아온다. (참고로 RestController다)

그렇기 때문에 클라이언트에서 JSON 타입으로 데이터를 보내주어야 한다.

$(".login-form button[type=submit]").click(login);

function login(e) {
  //원래 동작해야 할 이벤트를 중지 시킨다.  
	e.preventDefault();

  //유저가 입력한 정보를 js 오브젝트로 만든다.  
	var data = {
		'email' : $('#email').val(),
		'password' : $('#password').val()
	};

  //위에서 만든 오브젝트를 json 타입으로 바꾼다.
	var json = JSON.stringify(data);
	var url = $(".login-form").attr("action");

	$.ajax({
		type : 'post',
		url : url,
		data : json,
		contentType : "application/json; charset=utf-8",
		error : onError,
		success : onSuccess
	});
}

서버에서 JSON 데이터를 받기 때문에 JSON으로 데이터를 변환하였고, contentType을 JSON 설정하였다.(서버 기준으로 작업)


@RequestBody 사용을 안 할때

아주 간단하게 데이터 타입들만 맞추면 된다.

@PostMapping("")
public ResponseEntity<Void> login( UserDto userDto, HttpSession session) {
  session.setAttribute("loginedUser", userService.login(userDto.toUser()));
  HttpHeaders headers = new HttpHeaders();
  return new ResponseEntity<Void>(headers, HttpStatus.OK);
}
function login(e) {
	e.preventDefault();

	var data = $(".login-form").serialize();
	var url = $(".login-form").attr("action");

	$.ajax({
		type : 'post',
		url : url,
		data : data,
		error : onError,
		success : onSuccess
	});
}

11~12일 한일

- trello 프로젝트

  • 기존에 직접 프로젝트를 생성하여 작업 하던 것들을 포비의 github 레파지토리를 fork하여 재진행

  • RestController를 사용 하여 회원가입/로그인 구현

  • 회원가입/로그인 폼에서 AJAX로 데이터를 보내게 구현


11~12일 느낀점

  • 어떻게 진행하면 되겠다는 느낌이 왔다. 오늘 오전까지는 Restful API 설계 원칙에 따라서 작업을 한다는 게 어떻게 해야 할지 몰라서 고생을 했다. 특히 JSON으로 데이터를 받고 보내거나 HTTP 상태 값만 보내는 방식으로 서버와 클라이언트 간에 통신을 해 보라 했는데, Controller를 그렇게 구현하는 것 자체는 어렵게 느껴지지 않았는데 문제는 일부가 아닌 페이지가 바뀌어야 하는 상황에서 상태 값이나 JSON 데이터만 가지고 어떻게 다음 페이지로 이동을 하는가였다.

    그래서 생각한 방법은 ‘JSON으로 어떻게든 뷰단을 전송 시키는 것’, ‘모든 페이지를 프론트에서 가지고 있게 하고 상태 값에 따라 변경한다’ 후자야 사이트 종류에 따라 가능하지만 현재 프로젝트에선 저런 형태가 아니었던지라 서버에서 어떤 데이터를 어떻게 전송해야 할지 알 수가 없어 제대로 된 작업 시작을 못 했었다.

    오늘 오전 포비한테 의문 사항을 질문 후 자바스크립트를 통해 클라이언트가 자신이 이동하고 싶은 페이지를 요청할 수 있다는 사실을 알게 되니….. 순식간에 끝났다. 덕분에 프론트 쪽에 대한 지식도 좀 쌓아야겠다는 생각이 들었다.

  • 순식간에 끝났다고 했지만 그건 어디까지나 서버 쪽 얘기고(그래서 거꾸로 잘못 만들었나 싶었다. 심지어 테스트 코드를 잘못 만들었나도 고민했다) 프론트 작업은 반나절이나 한 것 같다. 진짜 간단한 작업이었는데 생각보다 빡셌다. 아예 잘 못 했다기보다는 신경 써야 할 것들을 놓쳐서 계속 실패를 했다. 특히 코드 자체의 문제가 아니라 서버와 클라이언트 간의 무언가(?)가 안 맞아 에러가 있을 때 무엇이 문제인지 찾는 게 늦었다.

    트렐로를 만들면서 서버도 서버지만 간단한 프론트 작업에도 익숙 해지도록 노력해야겠다. 다행인 게 옆에 프론트 분들도 계시고 해서 많은 도움을 받고 있다.
    그래도 문제가 있다고 무조건 찾아가진 않고 일단은 가능하면 직접 해결책을 찾는다. 그래도 안된다면 문제가 되고 있는 부분을 파악해서 방법을 묻거나, 어떤 기능을 구현해야 하는데 그때 어떤 함수를 써야 하는지 같은 형태로 물어 보고 있다.

  • 확실히 어제까지는 어떻게 구현해야 할지 이해 자체를 못하고 있어서 구현을 하나도 못하다시피하고, 앞으로 어떻게 해야 할지도 몰랐는데 오늘 해답을 찾고 나서 확실히 어떻게 구현해 나가야 할지는 알게 된 것 같다. 확실히 무엇을 해야 할지 알고서 코딩을 하니까 오랜만에 즐겁게 작업 한 것 같다.(요 며칠 트렐로 초기 작업 동안 내가 뭘 하고 있는 건가 싶었다) 아! Resful API 설계 원칙 자체는 아직 크게 신경 못 쓰고 단순히 RestController로 구현만 하다시피했는데 그 부분을 좀 더 신경 써봐야겠다.


내일 할일

  • trello 구현하기

    • Board쪽 구현 시작 혹은 개발 서버 환경 구축

    • 경우에 따라 로그인 부분에 구현 한 jQuery를 순수 자바스크립트로 변경

SpringBoot에서 애노테이션을 활용한 예외 처리

스프링 부트에서 예외 처리 하는 세가지 방법 (출처)

  • Global Level using - @ControllerAdvice

  • Controller Level using - @ExceptionHandler

  • Method Level using - try/catch


Controller

@Controller
public class UserController {
  @ExceptionHandler(UnAuthenticationException.class)
  @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
  public void unAuthentication() {
    log.debug("UnAuthenticationException is happened!");
  }
}
  • 위의 방법은 Controller 내부에서 예외가 발생하면 처리한다.

  • @ExceptionHandler를 통해 UnAuthenticationException에 대한 예외 처리를 한다.

  • @ResponseStatus를 통해 UNAUTHORIZED(401) 상태 값을 응답 한다.


ControllerAdvice

@ControllerAdvice
public class SecurityControllerAdvice {
  @ExceptionHandler(UnAuthenticationException.class)
  @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
  public void unAuthentication() {
    log.debug("UnAuthenticationException is happened!");
  }
}

  • 위의 방법은 모든 컨트롤러에 적용 된다.