인프런 커뮤니티 질문&답변

김성은님의 프로필 이미지

작성한 질문수

스프링부트 시큐리티 & JWT 강의

스프링부트 시큐리티 3강 - 시큐리티 회원가입

오류 문의 _ org.springframework.orm.jpa.JpaSystemException: could not deserialize

작성

·

198

·

수정됨

1

우선 도움 많이 받고 있습니다

 

1) 다름이 아니라 3강-시큐리티 회원 가입에서 동영상 강의 12분 10초까지는 제가 작성한 코드가 잘 실행 됩니다. 회원 가입한 데이터가 콘솔에 잘 출력 됩니다

 

2) 그리고 나서 데이터를 DB까지 잘 저장 하기 위해서 레지파토리를 작성 하여 회원 가입을 시도 했는데 아래와 같이 오류가 발생 합니다

 

3) 제 소견으로 저는 이미 마리아 DB랑 아래와 같이 설정 하여 사용 중에 있었습니다. 이게 문제인거 같기도 합니다

 spring.application.name=FirstProject

server.servlet.encoding.force-response=true

spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://localhost:3306/FirstProject?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=1234
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.show-sql=true
spring.jpa.open-in-view=true

 

User(id=0, username=6, password=6, email=6@naver.com, role=null, createDate=null)

Hibernate:

insert

into

user

(create_date, email, password, role, username)

values

(current_timestamp(6), ?, ?, ?, ?)

Hibernate:

select

u1_0.create_date

from

user u1_0

where

u1_0.id=?

2024-08-02T21:41:49.880+09:00 ERROR 19076 --- [FirstProject] [io-8080-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.orm.jpa.JpaSystemException: could not deserialize] with root cause

 

아래는 코드 내용 입니다 ~~~~~~~

 


package com.example.FirstProject.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;




@Configuration
@EnableWebSecurity // 스프링 시큐리티 필터가 스프링 필터체인에 등록
public class SecurityConfig {

    //
    @Bean
    public BCryptPasswordEncoder encodePwd() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf(csrf -> csrf.disable());
        http.authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/user/**").authenticated()
                        .requestMatchers("/manager/**").hasAnyRole("ADMIN", "MANAGER")
                        .requestMatchers("/admin/**").hasRole("ADMIN")
                        .anyRequest().permitAll()
        );

        http.formLogin(form -> form
                .loginPage("/loginForm"));
        return http.build();
    }


}

 

package com.example.FirstProject.controller;

import com.example.FirstProject.model.User;
import com.example.FirstProject.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class indexController {

@Autowired
private UserRepository userRepository;

@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;



    // 아래는 http://localhost:8080/ 로 들어 왔을 때의 겟 맵핑 임
    // http://localhost:8080/ 로 들어오면 index.mustache 페이지로 전환 됨
    @GetMapping({"","/"})
    public String index(){
        return "/index";
    }

    // href="/joinForm"가 들어오거나 URL 주소가 8080/joinForm로 들어오면 페이지는 return 값인 joinForm으로(mustache) 전환 해라
    @GetMapping("/joinForm")
    public String joinForm(){
        return "joinForm";
    }

    @GetMapping("/loginForm")
    public String loginForm(){
        return "loginForm";
    }

    // 아래는 href="/user"가  타고 들어 오면 URL 주소는 8080/user 이 되면서 페이지는 return 값인 user로(mustache) 페이지가 전환 됨
    @GetMapping("/user")
    public @ResponseBody String user(){
        return "user";
    }

    @GetMapping("/admin")
    public @ResponseBody String admin(){
        return "admin";
    }

    @PostMapping("/join")
    public @ResponseBody String join(User user){
        System.out.println(user);
        user.setRole("ROLE_USER");
        String rawPassword=user.getPassword();
        String encPassword=bCryptPasswordEncoder.encode(rawPassword);
        user.setPassword(encPassword);
        userRepository.save(user);
        return "redirect:/loginForm";
    }
}

 

package com.example.FirstProject.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import java.security.Timestamp;

@Entity
@Data
public class User {
    @Id // primary key
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String username;
    private String password;
    private String email;
    private String role; //ROLE_USER, ROLE_ADMIN
    @CreationTimestamp
    private Timestamp createDate;
}

 

package com.example.FirstProject.repository;

import com.example.FirstProject.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

// JpaRepository 를 상속하면 자동 컴포넌트 스캔됨.
public interface UserRepository extends JpaRepository<User, Integer> {

    // Jpa Naming 전략
    // SELECT * FROM user WHERE username = 1?
    // User findByUsername(String username);
    // SELECT * FROM user WHERE username = 1? AND password = 2?
    // User findByUsernameAndPassword(String username, String password);

    // @Query(value = "select * from user", nativeQuery = true)
    // User find마음대로();
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>회원가입 페이지</title>
</head>
<body>
<h1>회원가입 페이지</h1>
<hr/>
<form action="/join" method="post">
    <input type="text" name="username" placeholder="Username"/> <br/>
    <input type="password" name="password" placeholder="Password"/> <br/>
    <input type="email" name="email" placeholder="Email"/> <br/>
    <button>회원가입</button>
</form>
</body>
</html>

 

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>로그인 페이지</title>
</head>
<body>
<h1>로그인 페이지</h1>
<hr/>
<!-- 시큐리티는 x-www-form-url-encoded 타입만 인식 -->
<form action="/loginProc" method="post">
    <input type="text" name="username" placeholder="Username"/> <br/>
    <input type="password" name="password" placeholder="Password"/> <br/>
    <input type="email" name="email" placeholder="Email"/> <br/>
    <button>로그인</button>
</form>
<a href="/joinForm">회원 가입 페이지 이동</a>
</body>
</html>

 

 

답변 1

0

안녕하세요, 인프런 AI 인턴입니다.

김성은님, 제공해주신 정보를 바탕으로 문제를 검토한 결과 오류의 원인이 java.security.Timestamp 올바르지 않은 사용일 가능성이 높아 보입니다. User 모델에서 Timestamp를 사용할 때는 java.sql.Timestamp를 사용해야 합니다. 현재 java.security.Timestamp를 잘못 사용하고 있는 것으로 보입니다. 올바른 Timestamp 타입으로 변경해주세요.

User 모델 내의 Timestamp import를 다음과 같이 수정하세요.

import java.sql.Timestamp;

java.security.Timestamp는 보안 인증서의 타임스탬프 처리와 관련된 클래스입니다. 이 경우에는 데이터베이스에 시간 관련 정보를 저장하는 용도로 java.sql.Timestamp를 사용해야 합니다. 데이터 모델에서 시간 정보를 다룰 때는 SQL 패키지 내의 Timestamp 클래스를 사용하는 것이 적합합니다.

수정 후 코드를 다시 실행해보시고, 문제가 계속되면 추가로 확인해보겠습니다.