공부 이야기/책

[자기계발] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 - 1편

한희성 2020. 7. 10.

목차

    반응형

    안녕하세요 쌍둥이 애비 깐지꾼지빠 입니다.

     

    한동안 메모성 블로그만 작성하다가 오늘은 최근에 전반부 학습을 마친 스프링 부트와 AWS로 혼자 구현하는 웹 서비스(이동욱 지음) 의 내용을 작성 하려고 합니다.

     

    소스로 직접 구현하기 전에 오며가며 책을 싹 읽어봤는데요 이 책의 정말 큰 장점은 스프링부트, JPA, 시큐리티 부터 시작하여

     

    테스트환경 구성, 아마존 배포, 무중단 배포, 배포 자동화까지 개발에 필요한 전반적인 사이클이 모두 포함되어 있습니다.

     

    정말 평소에 해보고 싶었던 기술들이 알차게 꽉꽉 잘 들어있어서 더더욱 재미 있었던 책 인듯하네요 ㅎㅎ

     

    개발환경

    1. Intellij 2020

    2. JPA

    3. JUnit5

    4. Gradle 6.3

    5. spring boot 2.3

     

    책의 예제코드 : http://bit.ly/fr-springboot

    글쓴이 git : https://github.com/hhsung0120/book

    - 아직은 뭐 몇개 없습니다... private 도 있고..

     

    [1장] 인텔리제이로 스프링 부트 시작하기

     

    - 사실 뭐 크게 별거 없는 챕터죠 ~ IDE 소개 및 설치 개발 환경 구성 등이 주 내용입니다.

     

    [2장] 스프링 부트에서 테스트 코드를 작성하자

     

    - 2장 또한 특별한 것? 없이 지나왔던 챕터이며, 한 가지 알게 된 사실은 

      JUnit4를 기준으로 작성 된 책인데, JUnit5가 디폴트로 변경되면서 어노테이션 찾는데 좀 해맸습니다 .

     

    Junit4 -> Junit5 달라진 점 보러가기!!!

     

    [3장] 스프링 부트에서 JPA로 데이터베이스 다뤄보자

     

    - 언젠가 한번 JPA를 써보고 싶다는 생각이 강하였는데, 아직까지 회사에서 적용하지 못했습니다. ㅠㅠ

     

    - 이번 책 공부로 인하여 느낌점은.. 아직까진 러닝커브... 기존의 습관이 아직은 몸에 익숙하여

      책에서 요구하는 requestDto, responseDto, update, save 와 같이 비슷한 종류의 객체와 DTO 를 여러번

      생성하는 것이 아직은 몸에 익숙치 않아서 많이 더딘 챕터였습니다. ㅋㅋ 또 한 builder 패턴 역시..

      쉽지 않았던 녀석이죠 ..하하

     

    - JPA 를 사용함으로 써 가장 좋았던 점은 패러다임 일치 와 같은 이런 논리 적인 요소 외에 해당 테이블에 객체만 넘기

      면 자동저장, setter에서 객체 값만 변경해준다면 자동으로(영속성 컨텍스트) 반영해준다는 장점이었습니다.

      관련 키워드 : 더티체킹, 영속성 컨텍스트(엔티티를 영구 저장하는 환경)

     

    -@EntityListeners(AuditingEntityListener.class) 기능으로 BaseTimeEntity 상속!(P121)

        매번 new LocalDate().now() 를 하지말자!

     

    자바8 부터 지원하는 날짜&시간 클래스 보러가기!!

     

    [4장] 머스테치로 화면 구성

     

    - 템플릿 엔진

     

    - 142p js 참고

     

    var main = {
        init : function () {
            var _this = this;
            $('#btn-save').on('click', function () {
                _this.save();
            });
    
            $('#btn-update').on('click', function () {
                _this.update();
            });
    
            $('#btn-delete').on('click', function () {
                _this.delete();
            });
        },
        save : function () {
            var data = {
                title: $('#title').val(),
                author: $('#author').val(),
                content: $('#content').val()
            };
    
            $.ajax({
                type: 'POST',
                url: '/api/v1/posts',
                dataType: 'json',
                contentType:'application/json; charset=utf-8',
                data: JSON.stringify(data)
            }).done(function() {
                alert('글이 등록되었습니다.');
                window.location.href = '/';
            }).fail(function (error) {
                alert(JSON.stringify(error));
            });
        },
        update : function () {
            var data = {
                title: $('#title').val(),
                content: $('#content').val()
            };
    
            var id = $('#id').val();
    
            $.ajax({
                type: 'PUT',
                url: '/api/v1/posts/'+id,
                dataType: 'json',
                contentType:'application/json; charset=utf-8',
                data: JSON.stringify(data)
            }).done(function() {
                alert('글이 수정되었습니다.');
                window.location.href = '/';
            }).fail(function (error) {
                alert(JSON.stringify(error));
            });
        },
        delete : function () {
            var id = $('#id').val();
    
            $.ajax({
                type: 'DELETE',
                url: '/api/v1/posts/'+id,
                dataType: 'json',
                contentType:'application/json; charset=utf-8'
            }).done(function() {
                alert('글이 삭제되었습니다.');
                window.location.href = '/';
            }).fail(function (error) {
                alert(JSON.stringify(error));
            });
        }
    
    }; 
    main.init();

     

     

     

     

     

     

     

     

     

     

     

     

     

    [5장] 스프링 시큐리티와 OAuth 2.0 으로 고르인 기능 구현하기

     

    - 인터셉터, 필터, 기반의 보안 기능을 구현하는 것보다 스프링 시큐리티를 통해 구현하는 것을 적극 권장

     

    - P164 ~ Google 을 이용한 로그인 구현

     

    - @EnableWebSecuriry : 시큐리티 설정을 활성화

      @csrf().disable().headers().frameOptions().disable() : h2-console 화면을 사용하기 위해 해당 옵션 disable

      @authorizeRequests : URL별 권한 관리를 설정하는 옵션의 시작점, 선어되어있어만 antMatchers 옵션 사용

      @antMatchers : 권한 관리 대상을 지정, URL, HTTP 메소드 별로 관리 가능 

                            / 등 지정된 URL들은 permiAll()옵션으로 전체 열람 권한

                            /api/v1/** 주소를 가진 API 는 USER 권한을 가진 사람만 접근 가능

      @anyRequest : 설정된 값들 이외 나머지 URL 들 통제/ anyRequest .authenticated() 나머지  URL 들은 모두 인증된

                           사용자들만 허용/ (인증 = 로그인)

      @logout().logoutSuccerssUrl(/) : 로그아웃 기능 진입점, 성공시 / 리다이렉트

      @oauth2Login : Oauth2로그인 기능의 설정 진입점

      @userInfoEndPoint : OAuth2 로그인 성공 이후 사용자 정보를 가져올 때 설정 담당

      @userService : 소설 로그인 성공 시 후속 조치 진행할 서비스 인터페이스 구현체 등록

     

    - 스프링 부트 2 버전의 시큐리티에서는 기본적으로 도메인/login/oauth2/code/소설코드 로 리다이렉트 되기 때문에

      컨트롤러를 따로 구현 하지 않아도 된다.

     

    @RequiredArgsConstructor
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        private final CustomOAuth2UserService customOAuth2UserService;
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .csrf().disable()
                .headers().frameOptions().disable()
                .and()
                .authorizeRequests()
                .antMatchers("/", "/css/**", "/images/**", "/js/**", "/h2-console/**", "/profile").permitAll()
                .antMatchers("/api/v1/**").hasRole(Role.USER.name())
                .anyRequest().authenticated()
                .and()
                .logout()
                .logoutSuccessUrl("/")
                .and()
                .oauth2Login()
                .userInfoEndpoint()
                .userService(customOAuth2UserService);
        } }

     

       

     

     

     

        

      

     

     

    반응형

    댓글