๐Ÿ“š TIL 22์ผ์ฐจ

temprmnยท2023๋…„ 6์›” 15์ผ
0
post-thumbnail

์˜ค๋Š˜์˜ ์ฃผ์š”์‚ฌํ•ญ (6/15, ๋ชฉ์š”์ผ)

  1. ๋๋‚˜์ง€ ์•Š๋Š” Spring์˜ ๊ตด๋ ˆ...
  2. ๊ฐœ์ธ๊ณผ์ œ ์ง„ํ–‰ (JPA ํ•™์Šต ์ „)

๋ฐค ๋Šฆ๊ฒŒ๊นŒ์ง€ ๋ณด์ถฉํ•™์Šต โ†’ ์ˆ˜๋ฉด๋ถ€์กฑ์œผ๋กœ ์•„์นจ์šด๋™์„ ๋ชปํ•จ
์ผ์ฐ ์ž  โ†’ ์ง„๋„๊ฐ€ ์‚ด์ง ๋Šฆ์–ด์ง

๋”œ๋ ˆ๋งˆ์ธ ๋“ฏ!!

๐ŸŒฑ Spring Bean

[Spring] Spring Bean ๋“ฑ๋ก๊ณผ ์‚ฌ์šฉ

Spring ๊ฐœ์ธ ๊ณผ์ œ

API ๋ช…์„ธ

๋งˆํฌ๋‹ค์šด์œผ๋กœ๋Š” ํ‘œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†์–ด์„œ ์Šคํ”„๋ ˆ๋“œ ์‹œํŠธ๋ฅผ ์ผ๋‹ค๋Š” ์Šฌํ”ˆ ์ด์•ผ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค... API ๋ช…์„ธ

DB ํ‘œ์ค€ ์‹œ ์„ค์ •

application.properties

mysql ์ฃผ์†Œ๊ฐ€ ์ž˜ ์„ค์ • ๋˜์–ด์žˆ๋Š”์ง€ ํ™•์ธํ•  ๊ฒƒ. ์ฃผ์†Œ๊ฐ€ ์ž˜๋ชป ์ž…๋ ฅ๋˜์–ด์žˆ์œผ๋ฉด DB์— ์ ‘์†๋„ ์•ˆ ๋  ๋ฟ๋”๋Ÿฌ ์—๋Ÿฌ๊ฐ€ ๋œจ๊ธฐ ๋•Œ๋ฌธ์— sql ์ฃผ์†Œ๊ฐ€ ์ œ๋Œ€๋กœ ์ž…๋ ฅ๋˜์–ด์žˆ๋Š”์ง€ ์œ ์˜ํ•ด์„œ ์‚ดํŽด์•ผํ•œ๋‹ค.

spring.datasource.url=jdbc:mysql://localhost:3306/{DB๋ช…}?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Seoul

์‹œ๊ฐ„ ์„ค์ •: setTimestamp

์ฐธ๊ณ : [JDBC] PrepareStatement์—์„œ TimeStamp, LocalDateTime ์‚ฌ์šฉํ•˜๊ธฐ

์‹œ๊ฐ„์„ ์ง์ ‘ ์ž…๋ ฅํ•ด์„œ ๋„ฃ์„ ์ˆ˜๋Š” ์—†์œผ๋ฏ€๋กœ, id์ฒ˜๋Ÿผ ์‹œ๊ฐ„์ด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋„๋ก ํ•ด์ค˜์•ผํ•œ๋‹ค.

๋”ฐ๋กœ ์ƒ์„ฑํ•˜๋‹ค๋ณด๋ฉด ์˜ค์ฐจ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ค์ฐจ๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋„๋ก setCreatedAt์™€ setModifiedAt์„ ํ†ตํ•ด ํ˜„์žฌ ์‹œ๊ฐ„์„ ๋จผ์ € ์„ค์ •ํ•ด์ฃผ๊ณ , ๊ฐ’์„ updateํ•  ๋•Œ๋Š” getCreatedAt์™€ getModifiedAt์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ค์ •๋œ ๊ฐ’์„ ํ˜ธ์ถœํ•˜๋„๋ก ํ–ˆ๋‹ค.

Timestamp๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ LocalDateTime ๊ฐ’์„ ๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— .toLocalDateTime()์„ ์‚ฌ์šฉํ•ด ๊ฐ’์„ ๋ณ€ํ™˜ ํ›„ ์ „๋‹ฌํ•ด์ฃผ์—ˆ๋‹ค.

BlogRepository.java
public Blog save(Blog blog) {

    // DB ์ €์žฅ
    // ๊ธฐ๋ณธ ํ‚ค๋ฅผ ๋ฐ˜ํ™˜๋ฐ›๊ธฐ ์œ„ํ•œ ๊ฐ์ฒด
    KeyHolder keyHolder = new GeneratedKeyHolder();
    
    // ์‹œ๊ฐ„ ์„ค์ •
    blog.setCreatedAt(ZonedDateTime.now());
    blog.setModifiedAt(ZonedDateTime.now());
    
    String sql = "INSERT INTO post (createdAt, modifiedAt, title, content, author, password) VALUES (?,?,?,?,?,?)";
    
    jdbcTemplate.update(con -> {
    
        PreparedStatement preparedStatement = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        preparedStatement.setTimestamp(1, java.sql.Timestamp.valueOf(blog.getCreatedAt().toLocalDateTime()));
        preparedStatement.setTimestamp(2, java.sql.Timestamp.valueOf(blog.getModifiedAt().toLocalDateTime()));
        preparedStatement.setString(3, blog.getTitle());
        preparedStatement.setString(4, blog.getContent());
        preparedStatement.setString(5, blog.getAuthor());
        preparedStatement.setString(6, blog.getPassword());
        
        return preparedStatement;
        
    }, keyHolder);

postmandb

์ €์žฅ๋„ ์ž˜ ๋œ ๊ฒƒ์„ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค!
์ˆ˜์ •ํ–ˆ๋‹ค!! (์•„๋ž˜์— ์ด์–ด์„œ)

๋‚ ์งœ ํƒ€์ž…์— ๋Œ€ํ•œ ๊ณ ์ฐฐ

์ฒ˜์Œ Table์„ ์ƒ์„ฑํ•  ๋•Œ, ์‹œ๊ฐ„์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋“ค(createdAt๊ณผ modifiedAt)์˜ ํƒ€์ž…์€ DATETIME์œผ๋กœ ์ง€์ •ํ–ˆ์—ˆ๋‹ค.

create table post (
        ...
		createdAt DATETIME not null,
		modifiedAt DATETIME not null,
		...
);

post ์ƒ์„ฑ ์งํ›„ Response๋กœ๋ถ€ํ„ฐ๋Š” ๋‚ ์งœ์™€ ์‹œ๊ฐ„์ด ๋ฐ€๋ฆฌ์ดˆ๋‹จ์œ„๊นŒ์ง€ ์ถœ๋ ฅ๋์ง€๋งŒ, ๋ฐ”๋กœ ์œ„์˜ ์ด๋ฏธ์ง€์ฒ˜๋Ÿผ yy-mm-dd HH-mm-ss ํ˜•์‹์œผ๋กœ ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์—, Table ์ƒ์œผ๋กœ๋Š” ์ž์„ธํ•œ ํ™•์ธ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ๋˜, ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ๊ณ„์† ํ˜•๋ณ€ํ™˜์„ ํ•ด์ค˜์•ผํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์ด ์žˆ๋‹ค.

๊ทธ๋ž˜์„œ varchar ํƒ€์ž…์œผ๋กœ ์ €์žฅํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค.

create table post (
        ...
		createdAt varchar(100) not null,
		modifiedAt varchar(100) not null,
		...
);

varchar ํƒ€์ž…์œผ๋กœ ๋ฐ”๋€œ์— ๋”ฐ๋ผ ์ž‘์„ฑํ–ˆ๋˜ ์ฝ”๋“œ์—๋„ ๋ณ€ํ™”๊ฐ€ ์กฐ๊ธˆ ์ƒ๊ธด๋‹ค. ๋‹จ์ˆœํ•˜๊ฒŒ LocalDateTime์„ ๋ฐ›์•„์™€ String ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ค€๋‹ค. (๊ธฐ์กด์— ZonedDateTime์„ ์‚ฌ์šฉํ–ˆ์—ˆ์ง€๋งŒ, ํƒ€์ž„์กด์ด ํ‘œ์‹œ๋  ํ•„์š”๊นŒ์ง„ ์—†์–ด์„œ LocalDateTime์„ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.)

BlogRepository.java
public Blog save(Blog blog) {

    // ...
    
    // ์‹œ๊ฐ„ ์„ค์ •
    // ํ˜„์žฌ ์‹œ๊ฐ„์„ ๋ฐ›์•„์„œ String ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜
    blog.setCreatedAt(LocalDateTime.now().toString());
    blog.setModifiedAt(LocalDateTime.now().toString());
    
   
   	// ...
   
    jdbcTemplate.update(con -> {
        PreparedStatement preparedStatement = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
        
        // ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋“ค์ฒ˜๋Ÿผ getter๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
        preparedStatement.setString(1, blog.getCreatedAt());
        preparedStatement.setString(2, blog.getModifiedAt());
        
        //...
        
        return preparedStatement;
        
    }, keyHolder);

์ž‘์„ฑ ์‹œ๊ฐ„ ๊ธฐ์ค€ ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ

๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌ์„ ํ•ด์•ผํ•œ๋‹ค๋Š” ์กฐ๊ฑด์ด ์žˆ์–ด์„œ ์ •๋ ฌํ•ด์ฃผ์—ˆ๋‹ค. ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์ด์–ด์„œ ๋ถ™์—ฌ์ฃผ๊ธฐ๋งŒ ํ•˜๋ฉด ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค.

## ๋‚ด๋ฆผ์ฐจ์ˆœ ์ •๋ ฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ช…๋ น์–ด
ORDER BY {์ •๋ ฌ ๊ธฐ์ค€ ๋ฐ์ดํ„ฐ ๋ช…} DESC
BlogRepository.java
public List<BlogResponseDto> findAll() {

	// DB ์กฐํšŒ
    String sql = "SELECT * FROM post ORDER BY createdAt DESC";
    
    ...

๋น„๋ฐ€๋ฒˆํ˜ธ ๋ฐ›์•„์„œ ํŒ๋ณ„ํ•˜๊ธฐ

๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฐ›์•„์™€์•ผํ•˜๋Š”๋ฐ? ์–ด๋–ป๊ฒŒ ๋ฐ›์•„์˜ค๋ผ๊ณ  ์ œ์‹œ๋˜์–ด์žˆ์ง„ ์•Š์•˜์œผ๋‚˜... ์‹คํ–‰ ํ…Œ์ŠคํŠธ์—๋Š” Postman์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋‹ˆ, ์•„๋งˆ @RequestBody๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•˜์ง€ ์•Š์„๊นŒ! ๋ผ๋Š” ๊ฒฐ๋ก ์ด ๋‚˜์™”๋‹ค.

BlogController.java
// ์„ ํƒํ•œ ๊ฒŒ์‹œ๊ธ€ ์ˆ˜์ •
@PutMapping("/post/{id}")
public BlogResponseDto updateBlogPost(@PathVariable Integer id, @RequestBody BlogRequestDto requestDto) {

    return blogService.updateBlogPost(id, requestDto);
}

Controller๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ฐ’์„ ๋ฐ›๊ธฐ๋งŒ ํ•˜๊ณ , ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํŒ๋ณ„ํ•˜๋Š” ์ผ์€ Service์—๊ฒŒ ๋„˜๊ฒผ๋‹ค. ์‚ฌ์‹ค ์‹ค์ œ๋กœ ํŒ๋ณ„ํ•˜๋Š” ์ผ์€ Repository๊ฐ€ ํ•˜๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค.

BlogService.java
public BlogResponseDto updateBlogPost(Integer id, BlogRequestDto requestDto) {

    // 1. ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€์ด DB์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
    Blog blog = blogRepository.findById(id);
    if(blog != null) {
    
        // 2. ์กด์žฌํ•˜๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ฒดํฌ
        boolean isRightPassword = blogRepository.checkByPassword(blog, requestDto.getPassword());
        if(isRightPassword) {
        
            // 3. ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์˜ณ์œผ๋ฉด ๊ฒŒ์‹œ๊ธ€ ๋‚ด์šฉ ์ˆ˜์ •
            blogRepository.update(id, requestDto); // DB ์ €์žฅ
            BlogResponseDto blogResponseDto = new BlogResponseDto(blog);
            
            return blogResponseDto;
            
        } else {
            throw new IllegalArgumentException("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
        }
    } else {
        throw new IllegalArgumentException("์„ ํƒํ•œ ๊ฒŒ์‹œ๊ธ€์€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
    }
}

Service๋Š” Controller๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•ด์„œ Repository์—๊ฒŒ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํŒ๋ณ„ํ•˜๋„๋ก ์ง€์‹œํ•œ๋‹ค.

// 2. ์กด์žฌํ•˜๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ฒดํฌ
boolean isRightPassword = blogRepository.checkByPassword(blog, requestDto.getPassword());

๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” String.equals(String) ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŒ๋ณ„ํ•˜์˜€๋‹ค.

BlogRepository.java
// ๋น„๋ฐ€๋ฒˆํ˜ธ ์ฒดํฌ
public boolean checkByPassword(Blog blog, String password) {

    // ๋น„๋ฐ€๋ฒˆํ˜ธ(๋ฌธ์ž์—ด) ๋น„๊ต
    if (blog.getPassword().equals(password)) {
        return true;
        
    } else {
        return false;
    }
}

์‹คํ–‰ ๊ฒฐ๊ณผ

๋ฌด์‚ฌํžˆ ์‹คํ–‰๋˜์—ˆ๋‹ค!

์‚ญ์ œ ์„ฑ๊ณต ์—ฌ๋ถ€ Responseํ•˜๊ธฐ

{
	"success":true
}

๋ช…์„ธ๋ฅผ ๋ณด๋ฉด ์ด๋Ÿฐ๊ฒŒ ์žˆ๋‹ค. ๋ญ์ง€? (๋ณด์ž๋งˆ์ž ์ง„์งœ ๋ญ์ง€? ๋ผ๊ณ  ์ƒ๊ฐํ•จ)

๋‹จ์ˆœํ•˜๊ฒŒ true๋ผ๋Š” ๊ฐ’๋งŒ ๋„์›Œ์ค„ ๊ฒŒ ์•„๋‹ˆ๋ผ, Dto๋ฅผ ํ†ตํ•ด์„œ ๋ฐ˜ํ™˜ํ•ด์ค˜์•ผํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ธฐ์กด์— ์‚ฌ์šฉํ•˜๋˜ BlogResonpseDto ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋‹ค๋ฅธ ๊ฐ’๋“ค๋„ ๊ฐ™์ด ์ถœ๋ ฅ์ด ๋œ๋‹ค. ๋ฐ˜๋Œ€๋กœ "success"๋ผ๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค„ ํ•„์š”๊ฐ€ ์—†์„ ๋•Œ๋„ ๋ณด์—ฌ์ง€๊ฒŒ ๋œ๋‹ค.

๊ทธ๋ž˜์„œ SuccessResponseDto๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค๊ธฐ๋กœ ํ–ˆ๋‹ค! ์ด๋ฆ„์„ ์ด๋ฏธ ์„ค์ •ํ•œ ์ƒํƒœ์—์„œ ์ƒ๊ฐํ•œ ๊ฑฐ์ง€๋งŒ, ResultResponseDto๋ผ๋Š” ์ด๋ฆ„์ด ๋” ์ ์ ˆํ–ˆ์„์ง€๋„ ๋ชจ๋ฅด๊ฒ ๋‹ค...

SuccessResponseDto.java
@Getter
public class SuccessResponseDto {

    private Boolean success; // ์ €์žฅ ์™„๋ฃŒ์ธ์ง€ ์•„๋‹Œ์ง€
    
    public SuccessResponseDto(Boolean success) {
        this.success = success;
    }
}

์ด๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ ์—ฐ๊ด€๋œ ํด๋ž˜์Šค์˜ ๋ฐ˜ํ™˜ํ˜•์„ SuccessResponseDto๋กœ ์„ค์ •ํ•ด์ฃผ์–ด์•ผํ–ˆ๋‹ค. ๋ฐ˜ํ™˜ํ˜•์ด ๋ฐ”๋€ ๋ฉ”์„œ๋“œ๋Š” BlogController.deleteBlogPost()์™€ BlogService.deleteBlogPost()์ด๋‹ค.

BlogController.java
// ์„ ํƒํ•œ ๊ฒŒ์‹œ๊ธ€ ์‚ญ์ œ
@DeleteMapping("/post/{id}")
public SuccessResponseDto deleteBlogPost(@PathVariable Integer id, @RequestBody BlogRequestDto requestDto) {

    return blogService.deleteBlogPost(id, requestDto);
}
BlogService.java
public SuccessResponseDto deleteBlogPost(Integer id, BlogRequestDto requestDto) {
    
    // 1. ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€์ด DB์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
    Blog blog = blogRepository.findById(id);
    if (blog != null) {
    
        // 2. ์กด์žฌํ•˜๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ฒดํฌ
        boolean isRightPassword = blogRepository.checkByPassword(blog, requestDto.getPassword());
        if(isRightPassword) {
        
            // 3. ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์˜ณ์œผ๋ฉด blog ์‚ญ์ œ
            blogRepository.delete(id);
            
            // 4. Success ์—ฌ๋ถ€ ๋ฐ˜ํ™˜
            return new SuccessResponseDto(true);
            
        } else {
            return new SuccessResponseDto(false);
        }
    } else {
        throw new IllegalArgumentException("์„ ํƒํ•œ ๊ฒŒ์‹œ๊ธ€์€ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
    }
}

BlogService.deleteBlogPost()์˜ ๊ฒฝ์šฐ๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ฆฌ๋ฉด false๋ฅผ ๋„์šฐ๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ, ์•„๋ž˜์ฒ˜๋Ÿผ ์˜ค๋ฅ˜๋ฅผ ๋˜์ง€๋ ค๊ณ  ํ–ˆ์—ˆ๋‹ค. ํ˜„์žฌ ์ƒํƒœ์—์„œ๋Š” ๋‘˜ ์ค‘ ๋ญ๊ฐ€ ๋” ์ข‹์€์ง€ ๋ชจ๋ฅด๊ณ , api ๋ช…์„ธ์—์„œ๋Š” "success"๋ฅผ ๋„์šฐ๋ผ๊ณ  ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋ช…์„ธ์„œ๋ฅผ ๋” ์šฐ์„ ํ•ด์„œ ์„ ํƒํ–ˆ๋‹ค.

throw new IllegalArgumentException("์ž˜๋ชป๋œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋‹ˆ๋‹ค.");

๋‚ด์ผ ํ•  ์ผ

  1. JPA ๋ฐ ๋‚จ์€ ๋ถ„๋Ÿ‰์„ ๋น›์˜ ์†๋„๋กœ ํ•™์Šตํ•œ๋‹ค
  2. ๋น›์˜ ์†๋„๋กœ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•œ๋‹ค
  3. ์šด๋™!!
profile
`ISFJ` T 49% F 51% /

0๊ฐœ์˜ ๋Œ“๊ธ€