어떤 자연수 N(1 ≤ N ≤ 10,000,000)에 대해서, 이 N을 몇 개의 연속된 자연수의 합으로 나타내는 가지수를 구하는 문제

 

연속된 수의 조합이고 N의 범위가 크기 때문에 투 포인터(lt, rt)를 사용해서 조합의 합이 N보다 작으면 rt를 증가, N보다 크면 lt를 증가 시키면서 이동한다.

 

곧바로 떠오르는 고려할 점은 어디까지 수를 체크 할 것이냐인데 최소한의 연속된 수로 나타낼 수 있는 경우는 N의 절반이 될 것이다.

 

연속된 숫자가 1개인 경우도 포함되기 때문에 자기 자신도 포함하면 기본값은 1이 될 것

 

int N = Integer.parseInt(br.readLine());
int end = N / 2;
int count = 1;
int lt = 1;
int rt = 2;
int sum = lt + rt;

while (lt <= end) {
    if (sum > N) {
        sum -= lt;
        ++lt;
    }
    if (sum == N && rt != N) {
        ++count;
    }
    if (sum <= N) {
        ++rt;
        sum += rt;
    }
}

 

OAuth(Open Authorization)란 표준 인증 프로토콜로 사용자들이 특정 플랫폼에 있는 자신의 정보에 대해 접근 권한을 부여하는 수단으로 사용이 된다.

 

사용자 인증(Authentication) 처리를 카카오, 네이버, 구글과 같이 OAuth 로그인 API를 제공하는 대형 서비스에게 맡기고 필요한 권한(Authorization)을 사용자 동의를 통해 받아서 필요한 Resource를 받아오는 것이다.

 

 

SecurityConfig

 

 

이전에는 스프링 시큐리티 설정을 WebSecurityConfigurerAdapter의 configure()로 했었지만 현재는 deprecated 되어서 SecurityFilterChain을 Bean으로 등록해야 한다.

 

oauth2Login() 밑에 부분을 보면 userService()에 CustomOAuth2UserService를 등록하는데 이는 함수형 인터페이스인 OAuth2UserService의 loadUser() 메서드를 구현한 것으로 로그인 성공 이후 Access Token을 이용해서 유저 정보(resource owner)를 받아서 OAuth2User(AuthenticatedPrincipal)를 반환한다.

 

 

CustomOAuth2UserService

 

 

사용자가 성공적으로 인증이 되면 OAuth2User에는 GrantedAutority Set이 포함되어 있는데 이 GrantedAuthority 컬렉션은 반환할 OAuth2AuthenticationToken에 매핑하는데 사용 될 수 있다.

 

매핑 옵션으로는 GrantedAuthoritiesMapper 또는 OAuth2UserService를 사용한 Delegation-based 전략이 있는데 후자의 경우 OAuth2UserRequest 및 OAuth2User에 대한 액세스를 제공하기 때문에 더 유연하고 향상된 방법이라고 한다. 나는 DefaultOAuth2UserService(표준 OAuth 2.0 공급자를 지원하는 OAuth2UserService의 구현)를 사용하였다.

 

DefaultOAuth2UserService 생성자를 통해 userRequest로 OAuth2User를 가져오고 Attributes 정보로 User Entity를 조회(기존 회원)하여 가져오거나 저장(새로운 회원)한다.

 

UserNameAttributeName()은 키 값으로 카카오의 경우 id가 된다

 

 

마지막으로 OAuth2User(AuthenticatedPrincipal)를 생성하여 반환한다.

 

 

아래는 전체적인 순서도와 내부적으로 어떻게 처리가 되는지 정리를 해봤다.

 

순서도

 

 

먼저 로그인을 누르면 프론트에서 "/oauth2/authorization/kakao"로 요청을 보내고 OAuth2AuthorizationRequestRedirectFilter는 기본 경로로 받아서 yml 파일에 정의해둔 authorization url로 요청을 보낸다. 

이때 앱의 Rest API 키 값인 client_id랑 Authorization Code를 받을 redirect_url, response_type을 같이 보내는데 이 정보는 yml 파일에 저장을 해놓는다.

 

참고로 스프링 시큐리티가 yml 파일을 읽어서 OAuth2ClientProperties를 생성하고 ClientRegistration 객체(kakao, google, naver ..)를 생성해서 InMemoryClientRegistrationRepository에 저장한다. 

 

 

위에서 말한 OAuth2AuthorizationRequestRedirectFilter는 OAuth2AUthorizationRequestResolver의 resolve()를 호출하는데 로그인 요청 URL에서 registrationId를 확인하고 InMemoryClientRegistrationRepository에서 ClientRegistration 객체를 꺼내 OAuth2AuthorizagtionRequest 객체를 만든다.

 

 

그리고 OAuth2AuthorizationRequest를 받아서 redirect를 보내면 카카오 로그인 창이 뜨게 되는 것이다.

 

 

 

사용자가 카카오 로그인 인증을 성공하면 카카오 서버에서는 위에서 요청시 보낸 redirect_url로 인가 코드(Authorization Code)를 보내기 때문에 OAuth2LoginAuthenticationFilter의 기본 경로에 맞춰서 redirect_url을 yml 파일에 정의해두었다.

 

 

 

OAuth2LoginAuthenticationFilter도 OAuth2AuthorizationRequestRedirectFilter처럼 registrationId를 통해 ClientRegistation을 가져오고 Authorization Code를 사용해서 Access Token을 가져온다.

 

OAuth2LoginAuthenticationProvider는 authenticate() 메서드를 실행하여 Access Token을 받고 loadUser 메서드를 통해 유저 정보를 가져오는 처리까지 하는데 이때 loadUser()를 실행하는 UserService가 처음에 SecuriryConfig에서 userService()에 주입해준  CustomUserService가 된다.

 

 

다음에는 JWT를 발급하는 부분을 처리해봐야겠다.

 

 

[참고]

 

OAuth2 :: Spring Security

Spring Security provides comprehensive OAuth 2 support. This section discusses how to integrate OAuth 2 into your servlet based application.

docs.spring.io

 

[OAuth + Spring Boot + JWT] 2. 스프링 시큐리티로 OAuth 구현해보기

이번에는 \[OAuth + Spring Boot + JWT] 1. OAuth란? 프론트엔드와 백엔드의 역할 마지막에 설명한 구조를 스프링 시큐리티 없이 구현하기 앞서 스프링 시큐리티를 사용해서 oauth를 구현해보려고 한다.👀

velog.io

 

[Spring Boot] OAuth2 + JWT + React 적용해보리기

오늘 팀원이랑 이야기를 해보다가 우려했던 일이 벌어졌다.. 우려했던 일이란?우려했던 일(현재 문제점)개선 방안OAuth2란?With Spring Boot구현현재까지 구현되었던 프로젝트의 로그인과정을 살펴보

velog.io

 

 이전에 Swagger로 API 문서를 만들어봤는데 UI도 예쁘게 만들어주고 API 테스트도 해볼 수 있어서 편리하게 사용했었다.

 

 

 

[SpringFox] Swagger3.0 사용하기 1 (Spring Security, JWT)

Swagger란 REST API를 문서화하여 보기 편하게 시각화하고, 테스트할 수 있는 라이브러리로 서버 가동시 @RestController를 읽어서 API 분석을 해서 HTML로 문서화를 하기 때문에 API 문서를 직접 만들어서

treecode.tistory.com

 

 

하지만 컨트롤러에 설정 코드가 많이 들어가고 동기화가 되지 않는 단점이 있어서 이번에는 Spring Rest Docs를 공부해서 적용을 해보았다.

 

Asciidoctor로 만든 문서와 Spring MVC Test로 생성된 AsciiDoc 스니펫을 결합하여 API 문서(HTML)를 만든다고 나와있는데 원하는 경우 Markdown을 사용하도록 Spring REST Docs를 구성할 수도 있다고 한다.

 

1. 설정


 

Asciidoctor Plugin

*.adoc으로 생성된 asciidoc 파일을 html로 변환해주는 플러그인, 처음에 "org.asciidoctor.convert" 를 사용했다가 오류가 떠서 확인해보니 Gradle 7 부터는 "org.asciidoctor.jvm.convert"를 사용한다고 한다.

그리고 asciidoctorExtensions 설정도 추가해준다.

 

 

snippetsDir에 테스트 빌드로 생성되는(outputs) 스니펫들이 저장될 위치를 지정해준다.

 

dependsOn은 해당 작업에 의존한다는 의미로 bootJar를 실행하면 asciidoctor가 먼저 실행이 된다. 그리고 finalizedBy는 후행 작업을 명시하는 것으로 마지막에 build/docs/asciidoc/ 에 생성된 html 파일을 static 경로에 복사한다.

 

블로그 보면서 해보다가 설정 안 맞아서 고생했는데 블로그 글을 쓰면서 공식 문서를 살펴보니 다시 한번 공식 문서의 중요성을 느끼게 된다.

 

 

 

 

2. 테스트 코드


 

@AutoConfigureRestDocs 애노테이션으로 Rest Docs 여러 설정을 간편하게 할 수 있다.

 

우선 순위에 따라 @AutoConfigureRestDocs(), OperationRequestPreprocessor로 url 설정을 할 수 있다.

 

MockMvc, Rest Assured 등으로 테스트를 작성하면 되는데 API 명세를 ResourceSnippetParameters builder()로 만든다,

 

 

3. 결과


 

퀄리티는 만들기 나름이라고 하는데.. Swagger를 썼을 때의 UI에 비하면 아주 심심한 화면이다. 그래서 더 괜찮은 방법이 없나 찾아보다가 Rest Docs랑 Swagger UI를 결합하는 방식을 소개하는 글을 발견해서 결국 해당 방식으로 변경을 했다!

이거에 대한 정리는 다음에 이어서 해야겠다.

 

 

 

[참고]

 

 

나의 첫 SpringRestDocs 적용기 part 1

※ 모든 코드는 저의 Github 에서 확인하실 수 있습니다. 0. 코드로 말합니다. 개발업무에 있어 형상관리업무만큼은 지극히 최소한으로 유지하는 게 좋다고 생각합니다. 과거엔 코드를 유지보수할

ahndy84.tistory.com

 

API 문서 자동화 - Spring REST Docs 팔아보겠습니다

프로덕션 코드와 분리하여 문서 자동화를 하고 싶다고요? 신뢰도 높은 API 문서를 만들고 싶다고요? 테스트가 성공해야 문서를 만들 수 있다!! Spring REST Docs가 있습니다. API 문서를 자동화 도구로

tecoble.techcourse.co.kr

 

betterfuture4 (헌치) - velog

🌱 함께 자라는 중입니다 🚀 rerub0831@gmail.com

velog.io

 

Spring Rest Docs 적용 | 우아한형제들 기술블로그

{{item.name}} 안녕하세요? 우아한형제들에서 정산시스템을 개발하고 있는 이호진입니다. 지금부터 정산시스템 API 문서를 wiki 에서 Spring Rest Docs 로 전환한 이야기를 해보려고 합니다. 1. 전환하는

techblog.woowahan.com

 

Spring REST Docs 적용 (Gradle 7)

Spring REST Docs를 통해 API를 문서화한다.

xlffm3.github.io

 

지도 API에 사용할 좌표 데이터를 DB에 관리하려고 하는 중 지원하는 기능이 없나 찾아보니 MySQL에서 Point 자료형과 JPA에서 Hibernate Spatial을 사용하여 좌표 데이터를 편리하게 다룰 수 있다.

 

 

Hibernate ORM 5.6.14.Final User Guide

Fetching, essentially, is the process of grabbing data from the database and making it available to the application. Tuning how an application does fetching is one of the biggest factors in determining how an application will perform. Fetching too much dat

docs.jboss.org

위에 문서를 보면 Hibernate Spatial은 지리 데이터 저장 및 쿼리 기능에 대한 표준화된 교차 데이터베이스 인터페이스를 제공하며 Oracle 10g/11g, PostgreSQL/PostGIS, MySQL 등의 데이터베이스에서 지원 가능하다고 한다. Hibernate Spatial은 JTS와 geolatte-geom이라는 두 라이브러리를 지원하는데 JTS는 사실상의 표준, Geolatte-geom은 JTS에서는 사용할 수 없는 많은 기능을 지원하는 최신 라이브러리다.

 

Jts, GeoLatte

 

JTS Topology Suite

The JTS Topology Suite is an API of spatial predicates and functions for processing geometry. It has the following design goals: JTS conforms to the Simple Features Specification for SQL published by the Open Geospatial Consortium JTS provides a complete,

www.tsusiatsoftware.net

 

GitHub - GeoLatte/geolatte-geom: A geometry model that conforms to the OGC Simple Features for SQL specification.

A geometry model that conforms to the OGC Simple Features for SQL specification. - GitHub - GeoLatte/geolatte-geom: A geometry model that conforms to the OGC Simple Features for SQL specification.

github.com

 

 

build.gradle

build.gradle 설정은 간단하다. (원래는 build.gradle에 hibernate 버전을 맞춰서 적어줘야 되는데 Hibernate 5.2.x 이후부터는 org.hibernate:hibernate-spatial만 추가하면 된다고 한다)

 

implementation group: 'org.hibernate', name: 'hibernate-spatial'

 

Hibernate Spatial은 데이터베이스의 공간 기능을 HQL 및 JPQL 내에서 사용할 수 있도록 Hibernate ORM 방언을 확장할 수 있는데 5.6.1 이전의 MySQL 버전은 공간 연산자에 대한 지원이 제한적이었지만 5.6.1 버전 이후 공간 연산자가 도입되면서 방언MySQLSpatial56Dialect를 통해 새롭고 정확한 연산자를 지원한다.

(MySQLSpatialDialect -> MySQL5SpatialDialect -> MySQLSpatial56Dialect)

그래서  applicaiton 설정에 MySQL56InnoDBSpatialDialect를 추가해주었다.

 

apllication yml

jpa:
    database-platform: org.hibernate.spatial.dialect.mysql.MySQL56InnoDBSpatialDialect

 

 

 

지도의 좌표 데이터 정도만 사용을 하려고 하기 때문에 사용하는 부분은 간단하다.

import org.locationtech.jts.geom.Point;

 

Point를 그대로 반환하면 Json이 변환을 못해서 추가 처리를 해야 되는데 간단하게 X, Y값을 빼내서 Dto로 만들었다.

 

마지막으로 MySQL에서 공간 자료형인 POINT 컬럼을 추가하면 깔끔하게 해결 된다.

 

 

java:hibernate:spatial [권남]

 

kwonnam.pe.kr

 

Hibernate Spatial을 이용한 좌표간 거리계산 (feat. PostGIS, H2GIS)

💽 Hibernate Spatial Hibernate Spatial은 지리 데이터를 계산하기 위해 만들어 졌고, Hibernate 5.0 버전 부터 Hibernate 라이브러리에 공식적으로 마이그레이션이 됐다. 현재 지원하는 데이터베이스는 , , , ,

seongsu.me

 

Spring JPA MySql 위치 정보(위도, 경도) 저장 및 Json으로 응답

의존성을 추가할 때, 반드시 hibernate 버전을 확인하고 그에 맞게 추가해야한다.build.gradle의 dependencies에 다음 한 줄을 추가한다.application.yml파일의 jpa database-platform을 다음과 같이 변경한다.위치정

velog.io

 

+ Recent posts