본문 바로가기
개인 공부용 프로젝트/schedule.jdbc.api

Lv1, Lv2

by pon9 2024. 12. 4.

api 프로젝트때 썼던거 복붙해서 날먹하려고 했는데 jpa가 아니라 jdbc로 해야해서 처음부터 만들어야한다.(..)

일단 entity와 @id, @generatedvalue를 못 쓴다.

repository 또한 jdbc에서는 Dao가 그 역할을 하고, 직접 쿼리문을 작성해줘야 한다.

@Getter
@Setter
@ToString
@AllArgsConstructor
@EqualsAndHashCode(of = "id")	
//id필드를 비교대상으로 둠.(고유성을 id로 판단, PK라는뜻)
public class Schedule {

    public Schedule(){
        this.id = UUID.randomUUID();
        this.created = LocalDateTime.now();
        this.updated = LocalDateTime.now();
    }

    public void updateTimestamp() {
        this.updated = LocalDateTime.now();
    }

    public Schedule(String name, String content, String password) {
        this();
        this.name = name;
        this.content = content;
        this.password = password;
    }

    private UUID id;
    private String name;
    private String content;
    private String password;
    private LocalDateTime created;
    private LocalDateTime updated;
}

우선 entity계층을 작성했다. @Id역할을 @EqualsAndHashCode(of = "id")가 대신한다.

UUID.randomUUID()로 객체마다 고유한 id를 생성한다.

schedule 객체가 생성될 때 id와 created, updated가 자동으로 생성되고, 클라이언트에게 값을 전달받아 name, content, password를 채운다.

    @PostMapping("/{id}")
    public void updateSchedule(@PathVariable UUID id, @RequestParam String password, @RequestBody ScheduleDto dto) {
        scheduleService.updateSchedule(id, password, dto);
    }
    
	public ScheduleDto updateSchedule(UUID id, String password, ScheduleDto dto){
        Schedule schedule = scheduleDao.findById(id);
        if(schedule == null){
            throw new BadInputException("오류요");
        }

        if (!passwordEncoder.matches(password, schedule.getPassword())) {
            throw new BadInputException("오류요");
        }

        schedule.setName(dto.getName());
        schedule.setContent(dto.getContent());
        schedule.updateTimestamp();
        scheduleDao.update(schedule);

        return ScheduleMapper.toDto(schedule);
    }
    
    public void update(Schedule schedule){
        String sql = "UPDATE Schedule SET name = ?, content = ?, password = ?, updated = ? WHERE id = ?";

        try(Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
             PreparedStatement pstmt = conn.prepareStatement(sql)){

            pstmt.setString(1, schedule.getName());
            pstmt.setString(2, schedule.getContent());
            pstmt.setString(3, schedule.getPassword());
            pstmt.setTimestamp(4, Timestamp.valueOf(schedule.getUpdated()));
            pstmt.setString(5, schedule.getId().toString());

            int rowsUpdated = pstmt.executeUpdate();
            if(rowsUpdated == 0){
                throw new BadInputException("오류요");
            }

        }catch(SQLException e){
            throw new BadInputException("오류요" + e.getMessage());
        }
    }
    
    public static Schedule toEntity(ScheduleDto dto, String password, UUID id) {
        return new Schedule(
                id != null ? id : UUID.randomUUID(),
                dto.getName(),
                dto.getContent(),
                password,
                LocalDateTime.now(),
                LocalDateTime.now()
        );
    }

update를 할 때의 전체적인 흐름이다. jpa 그립다

쿼리 update 과정에 비밀번호가 들어가는 게 상당히 마음에 안 드는데 방법을 좀 찾아봐야할것같다..

dao 클래스도 하나로 쓰고 있어서 코드 길이가 상당히 길다. 분리하는 편이 더 깔끔할듯하다

 

그리고 putmapping 이나 deletemapping 에선 프론트단에서 requestbody를 못 쓴대서 delete, update 모두 post로 구현해봤다.

dto에 password까지 넣어서 requestbody로 보내는 것이 좀 더 안전할거같아서 수정 예정이다.

 

비밀번호는 bcrypt 알고리즘을 쓰기때문에 검증과정을 넣어줬다.

swagger에서 테스트 해보려는데 뭐야 누구세요? 난 이런페이지 만든적없어요

spring security 그냥 집어넣어서 이러는거같다;; 

@Configuration
public class SecurityConfig {

    @Bean
    public InMemoryUserDetailsManager userDetailsService(){
        UserDetails user = User.builder()
                .username("cy")
                .password(passwordEncoder().encode("jane"))
                .roles("ROLE_ADMIN")
                .build();
        return new InMemoryUserDetailsManager(user);
    }

    //비번 bcrypt 암호화 적용
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
}

bcrypt때문에 아래거만 그냥 넣었는데 위의 사용자 인증도 넣어줬다.

버그 테스트는 내일 해야겠다. 많을 것 같다. 너무 힘들다..

일단 1일차 이렇게 마무리.. 근데 커밋메세지를 그냥 lv1 lv2로 해버려서 좀 걱정이다. 어차피 도전레벨에서 구현하다보면 컨벤션 지킨 커밋이 많이 나오긴 하겠지만..