log

[Spring boot] (์—๋ธŒ๋ฆฌํƒ€์ž„ ํด๋ก ์ฝ”๋”ฉ) + MySQL, ํšŒ์› ๊ฐ€์ž… ๊ตฌํ˜„(1) ๋ณธ๋ฌธ

๐Ÿ“‹ Project

[Spring boot] (์—๋ธŒ๋ฆฌํƒ€์ž„ ํด๋ก ์ฝ”๋”ฉ) + MySQL, ํšŒ์› ๊ฐ€์ž… ๊ตฌํ˜„(1)

sun_young 2023. 7. 13. 23:14

[์ฐธ๊ณ ] '๋ฐฑ๊ฒฌ๋ถˆ์—ฌ์ผํƒ€ - ์Šคํ”„๋ง ๋ถ€ํŠธ ์‡ผํ•‘๋ชฐ ํ”„๋กœ์ ํŠธ with JPA' ์ฑ…์„ ์ฐธ๊ณ ํ•˜์—ฌ ์ž‘์„ฑ๋œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค!

https://product.kyobobook.co.kr/detail/S000001624717

 

๋ฐฑ๊ฒฌ๋ถˆ์—ฌ์ผํƒ€ ์Šคํ”„๋ง ๋ถ€ํŠธ ์‡ผํ•‘๋ชฐ ํ”„๋กœ์ ํŠธ with JPA | ๋ณ€๊ตฌํ›ˆ - ๊ต๋ณด๋ฌธ๊ณ 

๋ฐฑ๊ฒฌ๋ถˆ์—ฌ์ผํƒ€ ์Šคํ”„๋ง ๋ถ€ํŠธ ์‡ผํ•‘๋ชฐ ํ”„๋กœ์ ํŠธ with JPA | ์Šคํ”„๋ง ๋ถ€ํŠธ์™€ JPA๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์‹ค์ œ ์ด์ปค๋จธ์Šค ์—…๊ณ„์—์„œ ํ™œ์šฉ๋˜๋Š” ์‡ผํ•‘๋ชฐ ๊ธฐ์ˆ ๋“ค์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณผ ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌ์„ฑํ•˜์˜€๋‹ค. JPA์™€ Thymeleaf์— ๋Œ€ํ•œ

product.kyobobook.co.kr

 

1. ๋ฒ„์ „

spring boot 2.7.13

java 11

gradle

IntelliJ IDEA

 

2. ์˜์กด์„ฑ ์ถ”๊ฐ€

implementation 'org.springframework.boot:spring-boot-starter-security'
runtimeOnly 'com.mysql:mysql-connector-j'

 

3. ERD

์ž์œ  ๊ฒŒ์‹œํŒ๋งŒ ์ถ”๊ฐ€ํ–ˆ์ง€๋งŒ ๋‚˜๋จธ์ง€ ๊ฒŒ์‹œํŒ๋„ ํฌ๊ฒŒ ๋‹ค๋ฅธ ์ ์€ ์—†์Œ

(์ฃผ์ œ๋Š” ์—๋ธŒ๋ฆฌํƒ€์ž„ ํด๋ก ์ฝ”๋”ฉ์ด์ง€๋งŒ ์„ธ๋ถ€์ ์ธ ๋‚ด์šฉ์€ ๋Šฅ๋ ฅ ๋ถ€์กฑ์œผ๋กœใ…  ์•ฝ๊ฐ„ ์ˆ˜์ •๋  ๊ฒƒ ๊ฐ™๋‹ค)

 

4. MySQL ์—ฐ๋™

โ‘  ์Šคํ‚ค๋งˆ ์ƒ์„ฑ

 

โ‘ก application.properties - MySQL ์ •๋ณด ์ž…๋ ฅ

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/everytime?serverTimezone=UTC
spring.datasource.username=###
spring.datasource.password=###

spring.jpa.hibernate.ddl-auto=update

๋‘๋ฒˆ์งธ datasource.url ๋ถ€๋ถ„์— everytime์€ ๋ณธ์ธ์ด ์„ค์ •ํ•œ ์Šคํ‚ค๋งˆ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ๋˜๊ณ , username๊ณผ password๋„ ๋ณธ์ธ ์ •๋ณด์— ๋งž๊ฒŒ ์ˆ˜์ •ํ•˜๋ฉด ๋œ๋‹ค.

 

5. ์Šคํ”„๋ง ์‹œํ๋ฆฌํ‹ฐ ์„ค์ •

@Configuration 
@EnableWebSecurity // Spring Security ์„ค์ •
public class SecurityConfig {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

URL์— ๋”ฐ๋ฅธ ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ ์ถ”๊ฐ€๋Š” ์ถ”ํ›„ ์ง„ํ–‰ ์˜ˆ์ •

 

6. dto ์ƒ์„ฑ

package com.example.everytime.DTO;

import lombok.*;

@Getter @Setter
public class UserDto {
    private String userId;
    private String userPwd;
    private String userUniv;
    private String userEmail;
}

 

7. entity ์ƒ์„ฑ

package com.example.everytime.constant;

public enum Role {
    USER,ADMIN
}
package com.example.everytime.entity;

import com.example.everytime.DTO.UserDto;
import com.example.everytime.constant.Role;
import lombok.*;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.persistence.*;

@Getter @Setter
@Entity
@Table(name = "user")
@ToString
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false, length = 50, unique = true)
    private String userId;

    @Column(nullable = false, length = 50)
    private String userPwd;

    @Column(nullable = false)
    private String userUniv;

    @Column(nullable = false, length = 50, unique = true)
    private String userEmail;

    @Enumerated(EnumType.STRING)
    private Role role;

    public static User createUser(UserDto userDto, PasswordEncoder passwordEncoder) {
        User user = new User();
        user.setUserId(userDto.getUserId());
        user.setUserEmail(userDto.getUserEmail());
        user.setUserUniv(userDto.getUserUniv());
        String password = passwordEncoder.encode(userDto.getUserPwd());
        user.setUserPwd(password);
        user.setRole(Role.USER);
        return user;
    }
}

์ฒ˜์Œ์ด๋ผ ์ฑ…์˜ ์˜ˆ์ œ์™€ ์ตœ๋Œ€ํ•œ ์œ ์‚ฌํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜๋ ค๊ณ  id์™€ role์ด ์ถ”๊ฐ€๋˜์—ˆ๋Š”๋ฐ ์ถ”ํ›„ ์•ž์— ์„ค๊ณ„ํ•œ erd์— ๋งž์ถฐ ์ˆ˜์ •ํ•  ์˜ˆ์ • (๋ณธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๊ด€๋ฆฌ์ž ๋ฒ„์ „์„ ๋”ฐ๋กœ ๋งŒ๋“ค์ง€ ์•Š์„๊ฑฐ๋ผ role๋„ ํ•„์š”์—†์ง€ ์•Š์„๊นŒ ์‹ถ๋‹ค)

 

@Table(name = "") : "" ์•ˆ์— ์ ํžŒ ์ด๋ฆ„์œผ๋กœ MySQL table ์ƒ์„ฑ

@Id : ํ…Œ์ด๋ธ” ๊ธฐ๋ณธํ‚ค ์„ค์ •

@GeneratedValue : ์ž๋™์œผ๋กœ ๊ฐ’ ์ฆ๊ฐ€

@Column : ํ…Œ์ด๋ธ” ์—ด ์„ค์ • 

createUser ํ•จ์ˆ˜ : ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋„˜๊ฒจ๋ฐ›์€ dto๋ฅผ entity๋กœ ๋ณ€๊ฒฝ, ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ์•”ํ˜ธํ™”ํ•ด์„œ db์— ์ €์žฅ

 

8. repository ์ƒ์„ฑ

package com.example.everytime.repository;

import com.example.everytime.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
    User findByUserId(String userId);
}

๊ธฐ๋ณธ์ ์œผ๋กœ JpaRepository๋ฅผ ์ƒ์†๋ฐ›๊ณ , ์•„์ด๋””๊ฐ€ ์ค‘๋ณต๋˜๋ฉด ์•ˆ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ž…๋ ฅํ•œ ์•„์ด๋””๋กœ ์ด๋ฏธ ๊ฐ€์ž…ํ•œ ํšŒ์›์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด findByUserId๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค

 

9. service ์ƒ์„ฑ

package com.example.everytime.service;

import com.example.everytime.entity.User;
import com.example.everytime.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Service
@Transactional
public class UserService {
    private final UserRepository userRepository;

    public User saveUser(User user) {
        validateDuplicateUser(user);
        return userRepository.save(user);
    }

    private void validateDuplicateUser(User user) {
        User findUser = userRepository.findByUserId(user.getUserId());
        if(findUser != null) {
            throw new IllegalStateException("์ด๋ฏธ ๊ฐ€์ž…๋œ ํšŒ์›์ž…๋‹ˆ๋‹ค.");
        }
    }

}

@RequiredArgsConstructor : final์ด๋‚˜ @NonNull์ด ๋ถ™์€ ํ•„๋“œ์— ์ƒ์„ฑ์ž๋ฅผ ์ƒ์„ฑํ•ด์ค€๋‹ค. ๋นˆ์— ์ƒ์„ฑ์ž๊ฐ€ 1๊ฐœ์ด๊ณ  ์ƒ์„ฑ์ž์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์ด ๋นˆ์œผ๋กœ ๋“ฑ๋ก์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด @Autowired ์–ด๋…ธํ…Œ์ด์…˜ ์—†์ด ์˜์กด์„ฑ ์ฃผ์ž…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

 

10. test ์ž‘์„ฑ

package com.example.everytime.service;

import com.example.everytime.DTO.UserDto;
import com.example.everytime.entity.User;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.TestPropertySource;
import org.springframework.transaction.annotation.Transactional;

@SpringBootTest
@Transactional
@TestPropertySource(locations = "classpath:application-test.properties")
public class UserServiceTest {
    @Autowired
    UserService userService;

    @Autowired
    PasswordEncoder passwordEncoder;

    public User createUser() {
        UserDto userDto = new UserDto();
        userDto.setUserId("kim1111");
        userDto.setUserEmail("abcdefg@naver.com");
        userDto.setUserUniv("**๋Œ€ํ•™๊ต");
        userDto.setUserPwd("kim1111");
        return User.createUser(userDto, passwordEncoder);
    }

    @Test
    @DisplayName("ํšŒ์›๊ฐ€์ž… ํ…Œ์ŠคํŠธ")
    public void saveUserTest() {
        User user = createUser();
        User savedUser = userService.saveUser(user);

        Assertions.assertEquals(user.getId(), savedUser.getId());
    }
}

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋Š” ์„ฑ๊ณต!