728x90

스프링 시큐리티 사용자 인증

스프링 시큐리티는 인증에 대한 정보들을 제공한다.

Servlet Authentication Architecture

인증에 대한 아키텍처는 아래와 같다.

  • SpringSecurityContextHolder
    • 인증된 사용자의 세부 정보를 저장하는 곳
  • SecurityContext
    • SpringSecurityContextHolder에서 가져온 현재 인증된 사용자 인증을 가지고 있다.
  • Authentication
    • 사용자가 인증을 위해 제공한 자격증명이나 현재 사용자를 제공하기 위한 AuthenticationManager의 입력이 될 수 있음
  • GrantedAuthority
    • 인증에 대한 권한 정보
  • AuthenticationManager
    • 스프링 시큐리티 필터가 인증을 수행하는 방법을 정의
  • ProviderManager
    • AuthenticationManager의 기본 구현체
  • AuthenticationProvider
    • ProviderManager에서 특정 유형의 인증을 진행하는 Provider
  • Request Credentials with AuthenticationEntryPoint
  • AbstractAuthenticationProcessingFilter
    • 인증에 사용되는 기본 필터

SecurityContextHolder

구조

일반적인 구조는 위와같이 생겼다.

설명

스프링 시큐리티가 인증된 사용자의 정보를 저장하는 곳이다.

값이 포함되어 있으면 현재 인증된 사용자로 사용된다.

Authentication

사용자가 인증을 위해 제공한 자격 증명 AuthenticationManager 입력값.

이 상태에서 isAuthenticated()false를 반환

현재 인증된 사용자를 반환 현재 인증은 SecurityContext에서 얻을 수 있다.

Authentication이 포함하고 있는 값들

  • principal
    • 사용자를 식별한다.
    • username, password로 인증할 때 UserDetails가 값들을 포함한다.
  • credentials
    • 비밀번호
    • 이 비밀번호는 유출되지 않게 사용자를 인증 후 지워진다.
  • authorities
    • GrantAuthority 권한을 포함한다.

GrantAuthority

사용자에게 부여된 상위 수준의 권한

이 객체는 Authentication.getAuthorities() 에서 얻을 수 있다.

이 권한은 인증받으려는 주체에게 부여된 권한이다.

이 권한은 흔히 말하는 사용자, 관리자 등등 해당 권한을 나타낸다.

이 역할로 특정 URI에 대한 권한이나 접근 권한을 제어할 수 있게 된다.

username, password 기반 인증을 사용할 시에 권한은 UserDetailService가 가지고 있다.

UserDetailService

이 클래스는 AuthenticationProvider에서 username, password로 인증하기 위해

해당 사용자 이름, 비밀번호, 기타 속성들을 검색하는데에 사용된다.

UserDetailService를 커스텀 Bean으로 정의할 수 있다.

AuthenticationManager

이 클래스는 스프링 시큐리티 필터가 인증을 수행하는 방법을 명시한 API이다.

반환되는 인증은 AuthenticationManager를 호출한 컨트롤러에 의해

SpringSecurityHolder에 설정된다.

스프링 시큐리티의 필터와 통합하지 않는 경우에는 SecurityContextHolder를 직접

설정 할 수 있고, AuthenticationManager를 사용할 필요가 없어진다.

AuthenticationManager의 구현은 어떤것이든 가능하지만, 기본 구현은 ProviderManager

ProviderManager

위에서 말했듯, 이 클래스는 AuthenticationManager의 구현체이다.

ProviderManagerAuthenticationProviders의 리스트에 위임한다.

AuthenticationProvider는 성공, 실패를 나타내거라 결정할 수 없고

다운스트림 AuthenticationProvider가 결정하도록 허용할 수 없다.

AuthenticationProvider중 어느 것도 인증을 할 수 없는 경우에는

인증 예외인 ProviderNotFoundException이 발생하여 인증이 실패하게 된다.

구조

설명했듯 각 provider들이 특정 유형의 인증을 수행한다.

ProviderManagerAuthenticationProvider가 인증을 수행할 수 없는 경우

상위의 AuthenticationProvider를 설정하여 구성이 가능하다.

상위 AuthenticationProviderProviderManager의 인스턴스이다.

스크린샷 2021-12-03 오후 10 44 17

AuthenticationProvider

ProviderManager에 여러 AuthenticationProvider를 주입할 수 있다.

AuthenticationProvider들은 저마다의 특정 유형 인증을 수행하게 되어있다.

예를 들어, DaoAuthenticationProvider는 이름/암호 기반의 인증을 사용하고,

JwtAuthenticationProvider는 Jwt 토큰 인증을 사용한다.

AbstractAuthenticationProcessingFilter

이 클래스는 사용자의 자격 증명을 인증하기 위한 기본 필터이다.

이 인증이 되기전에 AuthenticationEntryPoint를 사용하여 HTTP 요청을 한다.

Authentication으로 인증에 대한 정보들을 쭉 가져온다.

AuthenticationManager가 그 인증 정보들을 받아 여러 검증들을 수행한다.

성공하면 Success 기본 호출은 AuthenticationSuccessHandler, 실패하면 Failure로 가서 AuthenticationFailureHandler호출됨

728x90

'Spring > Security' 카테고리의 다른 글

로그인 동작 순서  (0) 2022.08.09
개요  (0) 2022.08.09
728x90

📌 Spring Security

Spring SecurityServlet Filters를 기반으로 동작한다.

Spring Security는 인증, 권한 부여 및 보호를 제공하는 프레임워크이다.

스크린샷 2021-12-03 오후 10 38 42

전체적인 구조는 위와 같다.

Gradle 설정

plugins {
      id 'io.spring.dependency-management' version "1.0.10.RELEASE"
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-security'
}

📌 Filter

그래서 필터의 역할을 먼저 아는것이 중요한데,

Filter 영어 단어만 봐도 뭔가를 필터로 걸러주는 느낌이 난다.

업무중에 통신 하나하나의 로그를 다 찍는 과정을 Filter를 통해서 구현했던 경험이 있다.

이 필터를 줄줄이 연결하면 FilterChain이 되는 것이다.

다음은 스프링 공식문서에서 FilterChain의 구조를 가져왔다.

구조

스크린샷 2021-12-01 오후 9 19 39

클라이언트는 서버에 요청을 보내고 컨테이너는 요청 URI를 기반으로 HttpServletRequest를 처리하는 필터와

필터체인을 생성한다. Spring MVC에서의 ServletDispatcherServlet이 된다.

Filter 인터페이스를 구현하면 doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

메소드를 구현해주어야 한다.

chain.doFilter()를 호출하면 다음 필터를 차례대로 수행하는 것이다.

이렇게 필터들이 쭉 연결되어 기능을 수행한다고 생각하면 된다.

📌 DelegatingFilterProxy

구조

스크린샷 2021-12-01 오후 9 30 41

설명

SpringServlet 컨테이너의 라이프사이클과

SpringApplicationContext 사이의 연결을 허용하는

DelegatingFilterProxy라는 필터를 제공한다.

이 필터는 Servlet Filter로 애플리케이션 컨텍스트에서 요청한 것을 스프링 컨테이너에 생성된

Bean Filter를 찾고 그 필터를 호출한다.

DelegatingFilterProxy는 컨테이너가 시작되기 전에 필터를 등록해야 하기 때문에 중요하다.

📌 FilterChainProxy

Spring Security의 서블릿 지원은 FilterChainProxy에 포함되어 있다.

FilterChainProxySecurityFilterChain을 통해 여러 필터 인스턴스에 위임할 수 있도록

시큐리티에서 제공하는 특수 필터이다.

FilterChainProxyBean이라서 DelegatingFilterProxy안에 포함된다.

구조

스크린샷 2021-12-01 오후 9 45 51

이제보니 구조가 좀 잡혀가는것 같다.

클린코드와 자바의 정석을 읽었더니 시큐리티 아키텍처가 이해되는건 무엇일까.... 🤔🤔🤔

📌 SecurityFilterChain

SecurityFilterChain은 클라이언트에서 필터를 돌다가 DelegatingFilterProxy에 들어온 요청을

받아서 이 요청에 대해 처리해야 하는 Security Filter를 찾아 수행한다.

구조

스크린샷 2021-12-01 오후 9 57 39

📌 Security Filter

핵심인 시큐리티 필터이다. 이 필터는 SecurityFilterChain API를 사용해

FilterChainProxy에 삽입된다. 이 필터들은 순서가 중요하다.

필터의 순서를 알 필요는 없다.

근데 알아두면 유용하게 사용할 수는 있다.

필터에는 다음과 같은 필터들이 존재하고 위에서 아래로 순서가 매겨져 있다.

  • ChannelProcessingFilter
  • WebAsyncManagerIntegrationFilter
  • SecurityContextPersistenceFilter
  • HeaderWriterFilter
  • CorsFilter
  • CsrfFilter
  • LogoutFilter
  • OAuth2AuthorizationRequestRedirectFilter
  • Saml2WebSsoAuthenticationRequestFilter
  • X509AuthenticationFilter
  • AbstractPreAuthenticatedProcessingFilter
  • CasAuthenticationFilter
  • OAuth2LoginAuthenticationFilter
  • Saml2WebSsoAuthenticationFilter
  • UsernamePasswordAuthenticationFilter
  • OpenIDAuthenticationFilter
  • DefaultLoginPageGeneratingFilter
  • DefaultLogoutPageGeneratingFilter
  • ConcurrentSessionFilter
  • DigestAuthenticationFilter
  • BearerTokenAuthenticationFilter
  • BasicAuthenticationFilter
  • RequestCacheAwareFilter
  • SecurityContextHolderAwareRequestFilter
  • JaasApiIntegrationFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • OAuth2AuthorizationCodeGrantFilter
  • SessionManagementFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor
  • SwitchUserFilter

블럭이 쳐져있는 필터들을 유의해서 더욱 살펴봐야 하겠다.

📌 Handling Security Exceptions

위에서 ExceptionTranslationFilter를 사용하면 AccessDeniedException이나,

AuthenticationException을 HTTP Response로 변환할 수 있다.

스크린샷 2021-12-01 오후 11 16 45
  1. 일단 들어온 요청에서 FilterChain.doFilter()로 나머지 애플리케이션을 호출한다.
  2. 사용자가 인증이 되지 않았거나, AuthenticationException이 발생한 경우에 인증을 진행한다.

    이 경우 사용자가 성공적으로 인증되면 RequestCache에 사용자를 저장하고 이 캐시를 사용하여 원래 요청을 쭉 진행한다.
  3. 여기서 AccessDeniedException이 발생하게 되면 액세스는 거부되고, AccessDeniedHandler는 이 예외를 처리하기 위해 호출된다.

이 설정이 AccessDeniedExceptionAuthenticationException에 대한 예외처리가 없다면

ExceptionTranslationFilter는 아무것도 수행하지 않는다.

정리

여기까지가 일단 스프링 시큐리티의 기본적인 흐름이다.

다음 포스팅에서는 인증(Authentication) 에 대해서만 쭉 다뤄보는것으로 하겠다.

어렴풋이 알고 있는 기본값들에 대해서만 사용할게 아니라 입맛에 따라 커스텀하며 필터를 작업해주는 것이

개발자의 역량이라고 생각한다. 이게 뒷받침되려면 당연히 이런 공식문서를 읽어보는게 답이다.

전체적인 아키텍처의 흐름을 알아야 잘 설계할 수 있다.

아무튼 이 아키텍처를 공부함으로써 어제의 나보다는 오늘이 더 성장했다.

업무나 프로젝트에 들어간 시큐리티에 대한 코드를 보면 지금보다 더 이해할거라고 자신한다 🔥🔥🔥🔥

728x90

'Spring > Security' 카테고리의 다른 글

로그인 동작 순서  (0) 2022.08.09
Authentication 인증  (0) 2022.08.09
728x90

전역 값

회사 프로젝트에서 resources 디렉토리에 있는 설정파일은 application.properties를 사용한다.

그래서 여기에 값을 할당해주고 @Value를 가져다가 사용한다.

properties의 값을 가져올때는 @Value("${properties키 값}")으로 불러오기 때문에

이번에 내가 진행하게된 프로젝트 설정파일 application.yaml에도 똑같이 @Value가 적용될줄 알았다.

근데 적용하려고 보니까 에러가 나는것이다.

에러메세지부터 바로 보자.

에러메세지

Could not resolve placeholder 'application.open-api.adminKey' in value "${application.open-api.adminKey}"

라는 에러가 발생했다.

설정을 전부 그대로 두고 다시 구현해보니까 그냥 성공하게 되는 이유는 무엇일까 🤔

추후에 다시 알아봐야 할 것 같다.

멍청하기는 아래의 해결법에서 yaml의 키를 보면 admin-key인데

위에 오류메세지에서는 adminKey로 매핑을 시켰었다.

정말 한심하기 짝이없다. 👿👿👿👿👿👿

아무튼 이런 설정 방법도 있구나 라는것을 알아두면 되겠다.

해결법

Baeldung 설정

벨덩 문서에 가보면 yaml파일 설정에 대한 것을 설명해주었다.

이걸보고 나는 키값을 할당해주려고 아래와 같이 구현하였다.

application.yaml

open-api:
  admin-key: 키값
  authorization: 인증코드

YamlConfiguration.java

@Configuration
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "open-api") // 기본이 되는 뿌리 키값 여기서는 open-api이다.
@Getter
@Setter //setter가 없으면 Setter가 없다고 에러를 뱉어준다.
public class YamlConfiguration {
    private String adminKey;
    private String authorization;
}

여기서 @ConfigurationProperties 라는 어노테이션을 사용하려면 gradle에서

annotationProcessor에 다음을 추가해주어야한다.

annotationProcessor (
    // ...
            'org.springframework.boot:spring-boot-configuration-processor'
    )

그리고 사용하는 객체에서는 의존성 주입을 받아서 사용하면 되겠다.

public class Foo {

    private final YamlConfiguration yamlConfiguration;

    public Foo(YamlConfiguration yamlConfiguration) {
        this.yamlConfiguration = yamlConfiguration;
    }

    public void test() {
        yamlConfiguration.getAdminKey();
        yamlConfiguration.getAuthorization();
    }

}

@ValueConfiguration을 설정하는방법으로 어떤게 더 편한지 가독성이 좋은지 잘 모르겠다.

상황에 따라 편한걸 사용하는게 맞는지 이거는 조금 더 협업을 해보면 답이 찾아지지 않을까 싶다.

728x90

'디버깅' 카테고리의 다른 글

Jenkins 에러  (0) 2022.08.11
AWS SNS 토큰 에러  (0) 2022.08.10
AbstractMessageConverter  (0) 2022.08.09
RequestParamMethodArgumentResolver  (0) 2022.08.09
728x90

필터와 인터셉터

사이드 프로젝트를 하면서, 그리고 최근 회사의 프로젝트를 진행하면서

로깅처리와 더불어 어떠한 인증에 관한 것을 처리할 때 항상 필터를 구현했다.

이 필터가 뭔가 했더니 내가 옛날에도 들었었던 지식이지만 그냥 넘어가는 경우였고,

하다못해 스프링 동작과정에 정리해도

필터와 인터셉터에 관한 내용은 빼먹고 업로드를 한 것같다.

image

스프링 mvc의 기본 흐름에 대한 조금 더 구체적인 그림을 가져왔다.

다른 플로우차트를 찾아보려고 했지만 없더라.

실행

일단 서블릿 Request요청이 오게되면 바로 Filter로 가게된다.

여기서 무조건 동작을 받아서 처리를 해주고 이 필터들이 쭉 이어진것이 바로 필터체인이다.

image

필터 내부의 설명에서 보는것과 같이 doFilter 이 메소드에서 필터링을 수행하기 때문에

필터를 하나하나 등록해주게 되면 스프링은 요청을 받을때 저 필터들을 쭉쭉 통과해 나간다.

그다음에 DispatcherServlet으로 가게 되는 것이다.

서버를 실행시키면 Servlet이 올라오는 동안 init이 실행될 것이고

그 후에 doFilter가 수행될 것이다.

필터

이 필터는 아까도 말했듯, DispatcherServlet 이전에 실행되기 때문에 뭔가를 걸러주거나, 요청내용을 변경, 그리고 말했던 로깅처리 등을 진행할 수도있다.

public interface filter {
    public default void init(FilterConfig filterConfig) throws ServletException{}// - 필터 인스턴스 초기화

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;// - 전/후 처리

    public default void destroy() {}// - 필터 인스턴스 종료
}

이런식으로 세가지의 구성으로 되어있다.

image

doFilter에 있는 ServletRequest 객체는 매개변수 이름, 값 속성 등을

포함하는 데이터를 제공해준다.

web.xml에서 정리할 수도 있고, 나는 스프링 부트를 쓰기 때문에

javax.servlet.Filter를 구현해 주었다.

인터셉터

인터셉터는 말 그대로 가로채기이다.

필터는 스프링 외적으로 존재해서 스프링과는 상관없는 자원에 동작한다.

인터셉터는 DispatcherServlet 이 컨트롤러를 호출하기 전,후에 가로채려고 하기 때문에

스프링 컨텍스트 내부에서 Controller에 관한 요청, 응답에 대해 관여할 수 있다.

인터셉터는 여러 개를 사용할 수 있고 로그인 체크, 권한체크, 프로그램 실행시간 계산작업 로그확인 등의 처리가 가능하다.

  • preHandler()
    • 컨트롤러 메서드가 실행되기 전
  • postHanler()
    • 컨트롤러 메서드 실행직 후 view페이지 렌더링 되기 전
  • afterCompletion()
    • view페이지가 렌더링 되고 난 후

image

동작과정을 보면 이해가 될 수 있다.

지금 내 사이드 프로젝트에서 로그인 세션 null체크 기능이 잡다하게 중복이 되어있다.

도대체 학원에선 왜 이렇게 해도 뭐라안했을까 싶은 그런 로직들..

이 개념을 좀 도입해서 로깅처리와 로그인 기능을 좀 더 단순하게 구성을 해야겠다.

조바심 느끼지말고 남하고 비교하지말고 어제의 나보다만 성장해있으면 되는것 같다.

728x90

'Spring' 카테고리의 다른 글

Service Layer에 대한 생각  (0) 2022.08.10
Validaion  (0) 2022.08.09
Jasypt  (0) 2022.08.07
Spring -> Spring Boot 마이그레이션 2  (0) 2022.08.06
728x90

삽질기

모든 코드는 깃허브에 있다.

일단 저번에 마이그레이션 1탄을 했었는데 의존성이 겹쳐서 다시 리팩토링 하려고 보니까 에러가 많았다.

의존성 겹침 에러

일단 의존성이 겹쳐서 생긴 에러가 조금 있다.

부분만 적은 gradle 일부이다.

plugins {
    id 'org.springframework.boot' version '2.5.3'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
}

dependencies {
    implementation (
            'org.springframework.boot:spring-boot-starter-web', //이부분
            'org.springframework.boot:spring-boot-starter-test', //이부분
            'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0',
            'org.mariadb.jdbc:mariadb-java-client', //이부분
            'commons-io:commons-io:2.6',
            'commons-fileupload:commons-fileupload:1.3.3',
            'javax.servlet:jstl',
            'org.projectlombok:lombok',
    )
}

이렇게 주석처리한 부분들이 에러를 띄웠다.

각자의 버전마다 호응(?)이 되는 버전들이 맞아야 세팅이 완료가 되는데 서로 충돌해서 발생하는 에러였다.

그레이들에서

id 'org.springframework.boot' version '2.5.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'

이 두가지의 부분이 중요한데,

org.springframework.boot는 부트 버전을 명시하여 boot starter 관련 된것들을 통일 시켜주고

dependency-management는 다른 라이브러리들의 의존성을 관리해주는 것인데 최적화된 버전들을 맞춰주는 역할을 한다.

그러면서 버전이 맞지않는게 생기면 에러를 띄워준다.

톰캣 오류

그리고 tomcat 오류였다.

부트와 jsp는 잘 맞지않는다.

그럼에도 일단 jsp가 너무 많아서 일단 jsp를 사용하려고 했기 때문에

의존성에는

implementation (
    'javax.servlet:jstl',
    'org.apache.tomcat.embed:tomcat-embed-jasper'
)

두가지를 일단 추가 해줬다. JSP를 사용하려면 embed-jasper가 존재해야 하는데

이건 기본으로 작성해줘서 문제가 아니었다. 😰

application.properties

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

여기는 둘다 잘 해주었는데.. 왜문제일까 약 2시간 고민했다 😡

근데 여기가 문제였다...

스크린샷 2021-08-21 오후 5 45 32

Working Directory에 저 설정을 안해주면 jsp 파일을 안찾는다. 그냥 반응이 없음..

@Controller @RequestMapping 이런건 문제가 아니었다.

Bean 주입

Bean을 예를 들어

public interface TestInter {
    void hello();
}

@Repository
public class TestImpl implements TestInter {
    @Override
    public void hello() {
        System.out.println("hello");
    }
}

@RequiredArgsConstructor
public class TestService {
    private final TestInter testInter;
}

스프링5 프로그래밍 입문

여기서 봤던건데 스터디원 한분이 알려줬다. 그러면서 책에있는게 기억이 나더라...

결론은 빈을 뭘 주입해야할지 모르는것이다.
@Qualifier를 통해 명시해줘서 하거나 이전 회사에서 하던 방식으로 어노테이션 뒤에 (빈 이름) 해서 매칭해주는 식으로 해야한다. 이게 좋지 않아서 다 삭제했다.

스크린샷 2021-08-21 오후 5 54 26

이랬던 구조들을

스크린샷 2021-08-21 오후 5 54 42

이렇게 바꾸었다. 클래스 이름들은 추후 안정화가 되면 바꿀 계획이다.

학원에서부터 벗어난지 꽤됐고, 그러면서 TDD강의까지 듣고있고 그동안 공부했던거를 생각하면서 코드를 보니까
더러운 부분이 참많다.

이제 시작이고 끝을 보겠다. 계속 리팩토링 하는 과정을 블로그 + 깃허브 에 업데이트 할 것이다.

728x90

'Spring' 카테고리의 다른 글

Filter, Interceptor 정리  (0) 2022.08.07
Jasypt  (0) 2022.08.07
Spring Data JPA  (0) 2022.08.06
Spring -> Spring Boot 마이그레이션  (0) 2022.08.05
728x90

내 팀 프로젝트를 예전에 Spring으로 구현을 했었는데 이것을 스프링부트로 마이그레이션 해보았다. 더불어 Maven 의존성을 Gradle로 바꾸면서 마이그레이션을 한 것이다.

오류들이 상당히 많았지만 남들과 같은 오류인지는 잘 모르겠다.🤣

어떤 오류들이 있었는지 알아보자

Lombok

일단 Jar로 빌드하게되면 SpringBoot는 WEB-INF안의 jsp파일을 읽을수가 없다. 그래서 war로 빌드를 해주어야한다.

추후에 Mybatis로 db연결을 하는 방식을 JPA로 변경할 예정이다.

우선 제일 먼저 gradle 을 의존성 관리 툴로 추가하기 위해서

pom.xml 이 있는 경로로 가서 gradle init을 시켜주었다.

gradle init --type pom

이것으로 pom.xml의 내용이 Gradle로 변환이된다.

그다음 war파일이 있어야 실행할 수 있는 환경이 되기 때문에

apply plugin: 'war'

를 해준다.
이왕이면 최신버전으로 마이그레이션 하자 생각해서 다 최신버전으로 엮어주었다.

여기서 에러가 발생했던건 lombok이었는데
implementaion만으로 lombok을 추가하는 것이 아니라
annotationProcessor로도 lombok을 추가해줘야 했었다.

간략하게 gradle 지시어를 정리하자면

  • compileOnly: 해당 의존성을 컴파일시에만 포함한다.

  • runtimeOnly: 해당 의존성을 런타임시에만 포함한다.

  • compile: 해당 의존성을 직/간접적으로 의존하고 있는 모든 의존성을 재빌드한다.

  • implementation: 해당 의존성을 직접 의존하고 있는 의존성만 재빌드 한다.

기본적으로 포함이 되어있지 않은 어노테이션이 바로 lombok이기 때문에
annotationProcessor로 명시적 추가를 해줘야한다.

Mybatis

탈 xml을 하기 위해서 이것도 다 Java의 @Bean으로 설정을 해주었다.
여기서도 에러가 조금 많이 발생했다.

@Configuration
@MapperScan(
        sqlSessionFactoryRef="dataSource",
        sqlSessionTemplateRef="sqlSessionFactoryBean")
public class MapperConfig {
    @Value("${spring.datasource.driver-class-name}")
    String driverClassName;

    @Value("${spring.datasource.url}")
    String url;

    @Value("${spring.datasource.username}")
    String userName;

    @Value("${spring.datasource.password}")
    String password;

    @Bean(name="dataSource")
    public DataSource dataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(userName);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean
    public DataSourceTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }

    @Bean(name="sqlSessionFactory")
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setVfs(SpringBootVFS.class);

        sessionFactoryBean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/Configuration.xml"));
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return sessionFactoryBean;
    }
    @Bean(name="sqlSessionTemplate")
    public SqlSessionTemplate sqlSession(SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

application.properties

여기에는 web.xml을 제거하고 application.properties에

server.port=8080
server.servlet.context-path=/

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.mvc.static-path-pattern=/resources/static/**

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/테이블명
spring.datasource.username=계정명
spring.datasource.password=비밀번호

이렇게 진행했다. 그래서 파일 구조도 resources의 static 안으로 js, css 등 여러 정적 파일들을 넣어주고 불러오는 것으로 경로를 잡았다.

그러면서 동시에 WEB-INF폴더는 src/main/webapp 하위에 넣어주고 밖으로 빠져있던 jsp파일도 안으로 넣어주었다.

Tomcat

org.apache.catalina.webresources.Cache.getResource []에 위치한 리소스를 웹 애플리케이션 []을(를) 위한 캐시에 추가할 수 없습니다.
이런 에러도 Tomcat 구동시에 에러를 뱉었는데
이것은
tomcat경로중 apache-tomcat/conf/context.xml
아래와 같은 문구를 넣어준다.

<Resources cachingAllowed="true" cacheMaxSize="100000" />

이렇게 보면 단순한 에러들이었는데 Mybatis가 얽히고 조금만 건드리면 바로 에러가 나고 마이그레이션 경험이 생겨서 좋은것 같다. 앞으로도 레거시를 업데이트 해야할 경우에 오류들을 상기시키면서 잘 진행해보면 한번 더 성장할 수 있을것 같다.

728x90

'Spring' 카테고리의 다른 글

Spring -> Spring Boot 마이그레이션 2  (0) 2022.08.06
Spring Data JPA  (0) 2022.08.06
[Spring] MockMvc Bean 주입 에러  (0) 2022.08.04
[Spring] Spring Security  (0) 2022.08.03

+ Recent posts