Coding History/project

프로젝트 Mybatis 제거 JPA 도입

BlackBirdIT 2024. 9. 5. 11:47

OAuto2 인증을 도입하던 와중에 GPT를 고문하다가 좋을 걸 알아냈다.

내 프로젝트는 지금 Mybatis로 직접 내가 쿼리를 다 써서 날리고 있는데 세상에 JPA를 사용하면 쿼리를 알아서 자동으로 날려준다는게 아닌가?

바로 적용해봐야지 ㅋㅋ

일단은 의존성부터 다시 설정을 하는데, Mybatis 관련 의존성은 지우고, JPA를 도입해주면 된다. 검색하면 나오니까 자기 프로젝트에 맞게 알아서들 하십쇼. 그리고 어플리케이션.yml도 JPA를 사용할 수 있게 수정해줘야한다!

이후 난 VO 폴더에서 Member 클래스로 데이터를 전달했는데 이를 JPAentity패키지로 새로 만들어서 객체로 전달했다. 뭐 거의 비슷한데 어노테이션이 조금 추가 된 정도다.

@Entity
@Table(name = "users")  // DB의 테이블 이름과 매핑
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)  // Primary Key 자동 생성
    private int id;
    private String regDate;
    private String updateDate;
    private String loginId;
    private String loginPw;
    private String uName;
    private String nickname;
    private String cellphoneNum;
    private String email;
    private boolean delStatus;
    private String delDate;
    private int sellLevel;
    private int authLevel;
    private String spotifyLoginId;
    private String googleLoginId;
}

욜케.

그리고 기존 VO에 있던 member 클래스는 과감히 지워주고, 리포지토리와 서비스 계층을 수정해주자.

클래스를 옮겼기 때문에 해당 member 객체를 사용하는 곳 모두 다 찾아가서 임포트를 다시 다 직접 해줬다.

그렇게 기초 설정 후에 서버 키고 확인하려고 했는데 이게 웬걸

문제 발생@@@

OAuto2인증 관련 때문인 것 같은데 JSP로드를 못해서 이상한 페이지가 뜬다

???? 얘 진짜 뭐임 난 이런거 만든적이 없는데 그래서 왜 로드가 안되는지 찾아봤는데 아무리 찾아봐도 내 코드에 논리적 오류는 없었다.

그래서 OAuto2랑 서큐리티 콘피그 코드 주석처리한 후에 해보니까 구글창이뜨면서 엑세스 권한이 없다고 뜨더라.. 대체 저게 뭔데. JPA때문이 아니고 OAuto2 하던 와중에 내가 JPA 설정하고 확인해서 이렇게 된 것 같은데..

Custom Login 페이지 라고 하는건데 Spring Security가 기본적으로 제공하는 로그인 페이지라고 한다.

이게 내가 Security를 설정할 때 로그인 페이지를 제대로 명시하지 않아서 일어난 일이라고.. 하긴 코드 긁어와서 돌아가는지 아닌지만 확인하려고 설정 확인을 제대로 하지 않긴했다.

그래서 긁어온 것을 다시 읽기 시작했다.

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // CSRF 비활성화
                .csrf(AbstractHttpConfigurer::disable)
                // 로그인 폼 설정
                .formLogin(Customizer.withDefaults())
                // 권한 설정
                .authorizeHttpRequests(authorizeRequests ->
                        authorizeRequests
                                // /usr/member/login 및 /usr/member/join는 모두 접근 가능하게 설정
                                .requestMatchers("/usr/member/login", "/usr/member/join").permitAll()
                                // /home 및 루트 페이지는 인증 필요 없음
                                .requestMatchers("/", "/usr/home/").permitAll()
                                // 나머지 요청은 인증 필요
                                .anyRequest().authenticated()
                )
                // H2 콘솔을 위한 헤더 설정 (프레임을 허용)
                .headers(headersConfigurer ->
                        headersConfigurer.frameOptions(frameOptionsConfig -> frameOptionsConfig.sameOrigin())
                )
                // 로그아웃 설정
                .logout(logout ->
                        logout
                                .logoutUrl("/logout")
                                .logoutSuccessUrl("/login?logout")
                                .invalidateHttpSession(true)
                                .deleteCookies("JSESSIONID")
                );

        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring()
                .requestMatchers(
                        PathRequest.toStaticResources().atCommonLocations()
                );
    }
}

여기서 대충 경로같아 보이는 곳에 내 경로로 수정을 했었고, 쳐다도 안봤다. 왜? 설정이니까 알아서 되겠거니 했거든.

근데 문제가 생겨서 다시 보니까 로그인 폼 설정에 .formLogin(Customizer.withDefaults())이게 문제인 것 같았다. 디폴트 어쩌구 커스터마이저 어쩌구 돼있으니까 이게 내 로그인 페이지를 임의로 설정한거구나! 라는 결론에 도달.

그래서 해당 영역을

                 .formLogin(form -> form
                        .loginPage("/usr/member/login") // 커스텀 로그인 페이지 경로
                        .loginProcessingUrl("/usr/member/doLogin") // 로그인 처리 URL
                        .defaultSuccessUrl("/") // 로그인 성공 후 리디렉션될 기본 URL
                        .permitAll() // 로그인 페이지는 인증 없이 접근 가능하게 설정
                )

이렇게! 내 JSP 경로! 로! 고쳐봤다.

아 근데 또 무한 리디렉션하네.. 뭔가 막을만한게 필요하다.

블로그랑 GPT를 활용해서 일단 해결 했다.

이제 로그인 페이지 잘띄운다..

어떻게 해결했냐면

request.dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll()
이 코드가 핵심이라는 내용이였다. 그래서 이 코드를 내 코드에 어떻게 적용시킬까 여기저기 넣어보고

                // 포워딩 허용
                .authorizeHttpRequests(authorizeRequests ->
                        authorizeRequests
                                .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll() // 포워딩에 대해 인증을 허용
                                // 로그인 페이지와 회원가입 페이지에 대한 접근을 허용
                                .requestMatchers("/usr/member/login", "/usr/member/join", "/usr/member/doLogin").permitAll()
                                // 루트 페이지 및 /usr/home은 인증 필요 없음
                                .requestMatchers("/", "/usr/home/**").permitAll()
                                // 정적 리소스에 대한 접근 허용
                                .requestMatchers("/js/**", "/css/**", "/img/**", "/fontawesome-free-6.5.1-web/**").permitAll()
                                // 나머지 요청은 인증 필요
                                .anyRequest().authenticated()
                )

해당 블로그 코드랑 유사하게 짜보았다.

블로그 주소는 여기당 (정말 감사합니다 선생님 ㅠㅠㅠ)

이제 JPA 확인할 수 있따...


JPA 제대로 돌아가나 확인.

음 일단 창을 복구 해서 테스트 해봤는데, 전혀 제대로 작동하지 않는 것 같다.

일단 망가진 부분

  1. 빈칸이여도 조인을 했을 때, 경고 알람이 뜨지 않음.
  2. 다 채우고 전송해도 DB에 저장되지 않음.

제일 큰 문제는 이 두개고, 그러니까 JOIN기능이 그냥 아예 망가졌다.

그래서 일단은 프론트에 인자 전달을 정확히 하는가부터 체크해봤다

        // 폼 제출 시 호출될 함수
        function handleSubmit(event) {
            event.preventDefault(); // 폼이 자동으로 제출되지 않도록 방지

            const form = event.target; // form 요소를 가져옴
            const formData = new FormData(form); // form 데이터를 가져옴

            // formData의 모든 값을 콘솔에 출력
            formData.forEach((value, key) => {
                console.log(key + ": " + value);
            });

            // 필요 시 form을 여기서 제출
            form.submit();  // 이 부분에서 실제로 폼 제출할 수 있음
        }

이렇게 체크 해봤는데 콘솔에 입력한 값은 잘 찍힌다.

백엔드에 문제가 있다는건데.

그래서 이메일이 빈칸일 때 코드와 비번이 빈칸일 때 코드에 프린트를 찍어봤다.

        if (Ut.isEmptyOrNull(email)) {
            System.out.println("이메일이 비었습니다.");
            return Ut.jsHistoryBack("F-6", Ut.f("이메일을 입력해주세요."));
        }

        if (Ut.isEmptyOrNull(loginPw)) {
            System.out.println("비번이 비었습니다.");
            return Ut.jsHistoryBack("F-2", Ut.f("비밀번호를 입력해주세요."));
        }

이렇게 찍고 실행해보니까 콘솔에 찍히지 않았다. 컨트롤러까지 접근 자체를 못한다는거.

그래서 왜 접근을 못하는지까지는 모르겠어서 좀 알아보니까 서큐리티 설정을 잘못했다는 결론에 도달했다..

서큐리티가 날 너무 힘들게 해..

일단 해결은 했다. 쿼리는 날리도록.

                // 포워딩 허용
                .authorizeHttpRequests(authorizeRequests ->
                        authorizeRequests
                                .dispatcherTypeMatchers(DispatcherType.FORWARD).permitAll() // 포워딩에 대해 인증을 허용
                                // 로그인 페이지와 회원가입 페이지에 대한 접근을 허용
                                .requestMatchers("/usr/member/login", "/usr/member/join", "/usr/member/doLogin", "/usr/member/doJoin").permitAll()
                                // 루트 페이지 및 /usr/home은 인증 필요 없음
                                .requestMatchers("/", "/usr/home/**").permitAll()
                                // 정적 리소스에 대한 접근 허용
                                .requestMatchers("/js/**", "/css/**", "/img/**", "/fontawesome-free-6.5.1-web/**").permitAll()
                                // 나머지 요청은 인증 필요
                                .anyRequest().authenticated()
                )

서큐리티 클래스에서 .requestMatchers("/usr/member/login", "/usr/member/join", "/usr/member/doLogin", "/usr/member/doJoin").permitAll()이 부분이 문제였다.

여기서 doJoin이 빠져있어서 실행이 안됐던것. 내가 빼먹어놓고 왜 안되냐고 하면 안되지. 암튼 추가하니까 비어있는 칸 처리까지 하고 이제는 회원가입까지만 성공하면 된다.

그런데 쿼리에서 regDate가 계속 null값을 넣는대서 service에서 로컬데이트타임으로 넣어줬는데도 null값을 전달하네? 진짜 뭐지 싶다. 그래서 엔티티에서도 명시를 해줬다.

    @PrePersist
    protected void onCreate() {
        regDate = LocalDateTime.now();
        updateDate = LocalDateTime.now();
    }

    @PreUpdate
    protected void onUpdate() {
        updateDate = LocalDateTime.now();
    }

이렇게.

그래도 잘 안되더라. 보니까 JPA의 카멜 케이스, 스네이크 케이스라는 규칙이 있는데 이 규칙을 그냥 따라서 내 DB를 수정하기로 했다. (칼럼 어노테이션으로 직접 다 내 테이블에 맞게 명시를 해줬는데 어째선지 먹히지 않았고 그냥 쉬운 해결 방법으로 가기로 했다.)

결과.

그냥 규칙에 따라주니까 쿼리를 올바르게 보냈다.

4번 회원이 내가 회원가입 성공한 회원이다.

JPA 도입 성공!!!