[1부 계정 관리] 프로젝트 만들기, 계정 도메인, 회원 가입 컨트롤러

Yuri Lee·2020년 10월 8일
0

프로젝트 만들기

(1)sts, java version 8, maven, jar을 사용 (추후에 java 11을 사용하지 않으면 에러가 발생하는 것을 발견함)

(2)인텔리제이, java version 11, maven, jar 사용

Spring Configuration Processor: application.properties 파일에다가 에다가 원하는 커스터마이징, 추출해서 사용할 수 있음

  • id: user
  • Using generated security password: 396b78b5-65a9-4a0d-8a17-4a1f95020b53

app을 실행시켰을 때 기본적으로 스프링 시큐리티가 작동하므로다음과 같은 페이지가 나온다.

Account 도메인 클래스

  • 로그인
  • 프로필
  • 알림설정

팀이 커지면 모듈화 해도 되지만, 지금은 혼자 개발하는 것이므로 패스 😀

package com.goodmoim.domain;

import lombok.*;

import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Getter @Setter @EqualsAndHashCode(of = "id") //id만 사용하도록 함 
public class Account {

    @Id @GeneratedValue
    private Long id;

    @Column(unique = true)
    private String email;

    @Column(unique = true)
    private String nickname;

    private String password;

    private boolean emailVerified;

    private String emailCheckToken; //이메일을 검색할 때 사용할 토큰값을 db에 저장해놓고 매치하는지 확인하기 위해 

    private LocalDateTime joinedAt; //인증이 된 사용자를 그제야 가입될 수 있도록!

    private String bio; //짧은 자기소개

    private String url;

    private String occupation; //직업

    private String location;

    @Lob @Basic(fetch = FetchType.EAGER)
    private String profileImage;

    private boolean meetCreatedByEmail;

    private boolean meetCreatedByWeb;

    private boolean meetEnrollmentResultByEmail;

    private boolean meetEnrollmentResultByWeb;

    private boolean meetUpdatedByEmail;

    private boolean meetUpdatedByWeb;
}

Id만 사용하는 이유는?

연관관계가 복잡해질 때 @EqualsAndHashCode 에서 서로 다른 연관관계를 순환참조 하느라 무한루프가 발생하고, 결국에는 stackoverflow 가 발생할 수 있다. 그래서 id 를 주로 사용한다.

생성자 자동 생성이란?

Lombok을 사용하면 생성자도 자동으로 생성할 수 있다. @NoArgsConstructor 어노테이션은 파라미터가 없는 기본 생성자를 생성해주고, @AllArgsConstructor 어노테이션은 모든 필드 값을 파라미터로 받는 생성자를 만들어준다. 마지막으로 @RequiredArgsConstructor 어노테이션은 final이나 @NonNull인 필드 값만 파라미터로 받는 생성자를 만들어준다.

  • 이메일, 닉네임으로도 로그인을 할 수 있도록 지원함. 값은 유니크 해야 한다. 중복되어서는 안된다.
  • 일반적으로 스트링은 varchar(255) 타입으로 맵핑으로 되어있다. 하지만 프로필 이미지와 같은 경우는 더 커질 수 있으므로 lob로 맵핑한다. 그럼 텍스트 타입에 맵핑된다. 현재 기본 패치 타입은 lazy이지만 일단 명시적으로 eager로 주자. profileImage는 분명 유저를 로딩할 때 같이 쓰일 것
  • Tip: 시크릿 모드로 들어가야 캐시가 없어져서 더 수월하다!!!!

회원 가입: 컨트롤러

  • account 관련된 것들을 모아놓기 위해 account 패키지를 만든다.

  • 스프링 시큐리티 설정하기 위해 config 패키지를 만든다.

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .mvcMatchers("/", "/login", "/sign-up", "/check-email", "/check-email-token",
                        "/email-login", "/check-email-login", "/login-link").permitAll()
                .mvcMatchers(HttpMethod.GET, "/profile/*").permitAll()
                .anyRequest().authenticated();
    }
}
  • @ EnableWebSecurity 커스텀할 수 있도록 함
  • HttpSecurity 를 오버라이딩 해서 원하는 특정한 요청들은 스프링 시큐리티 인증 체크를 하지 않도록 걸러낼 수 있다.
  • profile 은 그냥 허용하면 안된다. httpmethod 중 get만 허용하도록! 나머지 요청은 로그인 해야만 사용할 수 있도록 한다.
MockHttpServletResponse:
           Status = 403
    Error message = Access Denied
          Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
  • AccountControllerTest 단위테스트 실행!
    (// .mvcMatchers("/", "/login", "/sign-up", "/check-email", "/check-email-token",
    // "/email-login", "/check-email-login", "/login-link").permitAll() 주석처리를 하고 unit test를 돌려봄)

에러반환! 그럼 다시 주석을 해지하고 돌려보면?

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Language:"en", Content-Type:"text/html;charset=UTF-8", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
     Content type = text/html;charset=UTF-8
             Body = <!DOCTYPE html>

200이 나온다. 즉 실제 뷰가 제공 된다는 것을 알 수 있음 😀 여기서 잠깐..! Mock 이 무엇일까?

Mock

  • Mock이라는 단어를 사전에서 찾아보면 '테스트를 위해 만든 모형'을 의미한다.

  • 테스트를 위해 실제 객체와 비슷한 모의 객체를 만드는 것을 모킹(Mocking)이라고 하며, 모킹한 객체를 메모리에서 얻어내는 과정을 목업(Mock-up)이라고 한다.

  • 객체를 테스트하기 위해서는 당연히 테스트 대상 객체가 메모리에 있어야 한다. 하지만 생성하는 데 복잡한 절차가 필요하거나 많은 시간이 소요되는 객체는 자주 테스트하기 어렵다. 또는 웹 애플리케이션의 컨트롤러처럼 WAS나 다른 소프트웨어의 도움이 반드시 필요한 객체도 있을 수 있다. 이런 복잡한 객체는 당연히 테스트 과정도 복잡하고 어려울 수 밖에 없다.

  • 따라서 테스트 하려는 실제 객체와 비슷한 가짜 객체를 만들어서 테스트에 필요한 기능만 가지도록 모킹을 하면 테스트가 쉬워진다.

  • 테스트하려는 객체가 복잡한 의존성을 가지고 있을 때, 모킹한 객체를 이용하면, 의존성을 단절시킬 수 있어서 쉽게 테스트할 수 있다.

  • 웹 애플리케이션에서 컨트롤러를 테스트할 때, 서블릿 컨테이너를 모킹하기 위해서는 @WebMvcTest를 사용하거나 @AutoConfigureMockMvc를 사용하면 된다.

  • 웹 환경에서 컨트롤러를 테스트하려면 반드시 서블릿 컨테이너가 구동되고 DispatcherServlet 객체가 메모리에 올라가야 하지만, 서블릿 컨테이너를 모킹하면 실제 서블릿 컨테이너가 아닌 테스트용 모형 컨테이너를 사용하기 때문에 간단하게 컨트롤러를 테스트할 수 있다.

출처 : 인프런 백기선님의 스프링과 JPA 기반 웹 애플리케이션 개발
https://elevatingcodingclub.tistory.com/61
https://www.daleseo.com/lombok-popular-annotations/

profile
Step by step goes a long way ✨

0개의 댓글