Spring

TIL Spring 2-1

๋ฆฐ์˜ˆ์กฐ 2023. 12. 7. 21:38

Spring์˜ 3 Layer Architecture


- Controller ํด๋ž˜์Šค ํ•˜๋‚˜๋กœ ๋ชจ๋“  API๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์€ ๋ฐ”๋žŒ์งํ•˜์ง€ ์•Š๋‹ค!

- ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜๋ฅผ ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด ์„œ๋ฒ„์—์„œ์˜ ์ฒ˜๋ฆฌ ๊ณผ์ •์„ Controller, Service, Repository ๋กœ ๋ถ„๋ฆฌํ–ˆ๋‹ค.

 

1. 3 Layer Architecture

Controller

ํด๋ผ์ด์–ธํŠธ์˜ HTTP Request๋ฅผ ๋ฐ›์•„ Service์— ์ „๋‹ฌํ•œ๋‹ค. (๋งŒ์•ฝ ๋ฐ์ดํ„ฐ๊ฐ€ ์š”์ฒญ์— ์žˆ๋‹ค๋ฉด ํ•จ๊ป˜ ์ „๋‹ฌ)

- Service์—์„œ ์ฒ˜๋ฆฌ ์™„๋ฃŒ๋œ ๊ฒฐ๊ณผ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์‘๋‹ตํ•œ๋‹ค.

 

Service

์‹ค์ œ ์‚ฌ์šฉ์ž์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. (๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ๊ตฌํ˜„)

- DB๊ด€๋ จ ์ž‘์—…์€ Repository์—๊ฒŒ ์š”์ฒญ

 

Repository

DB์™€ ๊ด€๋ จํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

- DB CRUD ์ž‘์—…์„ ์ฒ˜๋ฆฌ!

 

 

 

์‹ค์ œ ๊ตฌ์กฐ๋ฅผ ์‚ดํŽด๋ณด๋ฉด ์ด์™€ ๊ฐ™๋‹ค! 

 

 

2. ์—ญํ•  ๋ถ„๋ฆฌํ•˜๊ธฐ

 

# Controller - Service ๋ฅผ ๋ถ„๋ฆฌํ•ด๋ณด์ž

- Service ์—ญํ• ์„ ๊ตฌํ˜„ํ•ด์ค„ ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•˜๋‹ค. 

 

2-1) Controller ํด๋ž˜์Šค

- ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ๋ฐ›์•„ Service์— ์ „๋‹ฌํ•˜๋Š” ์ฝ”๋“œ๋งŒ ์žˆ๋‹ค.(์‹ค์ œ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ถ€๋ถ„์€ Service๋กœ ๋„˜์–ด๊ฐ.)



@RestController
@RequestMapping("/api")
public class MemoController {

    private final JdbcTemplate jdbcTemplate;

    public MemoController(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @PostMapping("/memos")
    public MemoResponseDto createMemo(@RequestBody MemoRequestDto requestDto) {
        MemoService memoService = new MemoService(jdbcTemplate); 
        return memoService.createMemo(requestDto);
    }

    @GetMapping("/memos")
    public List<MemoResponseDto> getMemos() {
        MemoService memoService = new MemoService(jdbcTemplate);
        return memoService.getMemos();
    }

    @PutMapping("/memos/{id}")
    public Long updateMemo(@PathVariable Long id, @RequestBody MemoRequestDto requestDto) {
        MemoService memoService = new MemoService(jdbcTemplate);
        return memoService.updateMemo(id, requestDto);
    }

    @DeleteMapping("/memos/{id}")
    public Long deleteMemo(@PathVariable Long id) {
        MemoService memoService = new MemoService(jdbcTemplate);
        return memoService.deleteMemo(id);
    }
}

 

2-2) Service์—์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ถ€๋ถ„!

- ์ด์ œ ๊ธฐ์กด Controller์—์„œ ์ฒ˜๋ฆฌํ•˜๋˜ ๋กœ์ง์ด Service ํด๋ž˜์Šค์—์„œ ์ˆ˜ํ–‰๋œ๋‹ค.


public class MemoService {

    private final JdbcTemplate jdbcTemplate;

    public MemoService(JdbcTemplate jdbcTemplate) { //jdbc template์„ ์ƒ์„ฑ์ž๋กœ ๋ฐ›๊ณ  ์žˆ์Œ
        this.jdbcTemplate = jdbcTemplate;
    }

    public MemoResponseDto createMemo(MemoRequestDto requestDto) {
        // RequestDto -> Entity
        Memo memo = new Memo(requestDto);

        // DB ์ €์žฅ
        KeyHolder keyHolder = new GeneratedKeyHolder(); // ๊ธฐ๋ณธ ํ‚ค๋ฅผ ๋ฐ˜ํ™˜๋ฐ›๊ธฐ ์œ„ํ•œ ๊ฐ์ฒด

        String sql = "INSERT INTO memo (username, contents) VALUES (?, ?)";
        jdbcTemplate.update( con -> {
                    PreparedStatement preparedStatement = con.prepareStatement(sql,
                            Statement.RETURN_GENERATED_KEYS);

                    preparedStatement.setString(1, memo.getUsername());
                    preparedStatement.setString(2, memo.getContents());
                    return preparedStatement;
                },
                keyHolder);

        // DB Insert ํ›„ ๋ฐ›์•„์˜จ ๊ธฐ๋ณธํ‚ค ํ™•์ธ
        Long id = keyHolder.getKey().longValue();
        memo.setId(id);

        // Entity -> ResponseDto
        MemoResponseDto memoResponseDto = new MemoResponseDto(memo);

        return memoResponseDto;
    }

    public List<MemoResponseDto> getMemos() {
        // DB ์กฐํšŒ
        String sql = "SELECT * FROM memo";

        return jdbcTemplate.query(sql, new RowMapper<MemoResponseDto>() {
            @Override
            public MemoResponseDto mapRow(ResultSet rs, int rowNum) throws SQLException {
                // SQL ์˜ ๊ฒฐ๊ณผ๋กœ ๋ฐ›์•„์˜จ Memo ๋ฐ์ดํ„ฐ๋“ค์„ MemoResponseDto ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ค„ ๋ฉ”์„œ๋“œ
                Long id = rs.getLong("id");
                String username = rs.getString("username");
                String contents = rs.getString("contents");
                return new MemoResponseDto(id, username, contents);
            }
        });
    }

    public Long updateMemo(Long id, MemoRequestDto requestDto) {
        // ํ•ด๋‹น ๋ฉ”๋ชจ๊ฐ€ DB์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
        Memo memo = findById(id);
        if(memo != null) {
            // memo ๋‚ด์šฉ ์ˆ˜์ •
            String sql = "UPDATE memo SET username = ?, contents = ? WHERE id = ?";
            jdbcTemplate.update(sql, requestDto.getUsername(), requestDto.getContents(), id);

            return id;
        } else {
            throw new IllegalArgumentException("์„ ํƒํ•œ ๋ฉ”๋ชจ๋Š” ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
        }
    }

    public Long deleteMemo(Long id) {
        // ํ•ด๋‹น ๋ฉ”๋ชจ๊ฐ€ DB์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
        Memo memo = findById(id);
        if(memo != null) {
						// memo ์‚ญ์ œ
            String sql = "DELETE FROM memo WHERE id = ?";
            jdbcTemplate.update(sql, id);

            return id;
        } else {
            throw new IllegalArgumentException("์„ ํƒํ•œ ๋ฉ”๋ชจ๋Š” ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
        }
    }

    private Memo findById(Long id) {
        // DB ์กฐํšŒ
        String sql = "SELECT * FROM memo WHERE id = ?";

        return jdbcTemplate.query(sql, resultSet -> {
            if(resultSet.next()) {
                Memo memo = new Memo();
                memo.setUsername(resultSet.getString("username"));
                memo.setContents(resultSet.getString("contents"));
                return memo;
            } else {
                return null;
            }
        }, id);
    }
}



 

๋”๋ณด๊ธฐ

<์ •๋ฆฌ>

๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•  ์„œ๋น„์Šค ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•จ.

์„œ๋น„์Šค๋กœ ์š”์ฒญ์„ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์„œ๋น„์Šค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์คŒ.

๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ๋ฉ”์„œ๋“œ์˜ ๋ฆฌํ„ด๊ฐ’์€ ์ปจํŠธ๋กค๋Ÿฌ์˜ ๋ฉ”์„œ๋“œ์ž„.

๊ทธ ์š”์ฒญ ๋‚ด์šฉ์„ ์ฒ˜๋ฆฌํ•  ๋ฉ”์„œ๋“œ๊ฐ€ ๋‹น์—ฐํžˆ ์„œ๋น„์Šค ์ธก์—๋„ ํ•„์š”ํ•จ

๊ทธ๋ž˜์„œ ์ปจํŠธ๋กค๋Ÿฌ์™€ ๋™์ผํ•œ ์ด๋ฆ„์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ 

์‹ค์ œ ๋น„์ง€๋‹ˆ์Šค ๋กœ์ง์„ ํ•ด๋‹น ๋ฉ”์„œ๋“œ์— ๊ตฌํ˜„ํ•œ๋‹ค.

 

# Service - Repository ๋ถ„๋ฆฌํ•˜๊ธฐ! 

- DB ์—ฐ๊ฒฐ ๋ฐ CRUD ์ž‘์—… Repository์—์„œ ์ง„ํ–‰

- ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํด๋ž˜์Šค ๋งŒ๋“ค์–ด์ค€๋‹ค!

- Service์—์„œ Repository ์ธ์Šคํ„ด์Šคํ™”ํ•ด์„œ ํ˜ธ์ถœ ๊ทธ๋ฆฌ๊ณ  DB๊ด€๋ จํ•œ ์ž‘์—… ๋„˜๊ฒจ์คŒ

 

2-3) Repository ํด๋ž˜์Šค

public class MemoRepository {

    private final JdbcTemplate jdbcTemplate;

    public MemoRepository(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public Memo save(Memo memo) {
        // DB ์ €์žฅ
        KeyHolder keyHolder = new GeneratedKeyHolder(); // ๊ธฐ๋ณธ ํ‚ค๋ฅผ ๋ฐ˜ํ™˜๋ฐ›๊ธฐ ์œ„ํ•œ ๊ฐ์ฒด

        String sql = "INSERT INTO memo (username, contents) VALUES (?, ?)";
        jdbcTemplate.update(con -> {
                    PreparedStatement preparedStatement = con.prepareStatement(sql,
                            Statement.RETURN_GENERATED_KEYS);

                    preparedStatement.setString(1, memo.getUsername());
                    preparedStatement.setString(2, memo.getContents());
                    return preparedStatement;
                },
                keyHolder);

        // DB Insert ํ›„ ๋ฐ›์•„์˜จ ๊ธฐ๋ณธํ‚ค ํ™•์ธ
        Long id = keyHolder.getKey().longValue();
        memo.setId(id);

        return memo;
    }

    public List<MemoResponseDto> findAll() {
        // DB ์กฐํšŒ
        String sql = "SELECT * FROM memo";

        return jdbcTemplate.query(sql, new RowMapper<MemoResponseDto>() {
            @Override
            public MemoResponseDto mapRow(ResultSet rs, int rowNum) throws SQLException {
                // SQL ์˜ ๊ฒฐ๊ณผ๋กœ ๋ฐ›์•„์˜จ Memo ๋ฐ์ดํ„ฐ๋“ค์„ MemoResponseDto ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ค„ ๋ฉ”์„œ๋“œ
                Long id = rs.getLong("id");
                String username = rs.getString("username");
                String contents = rs.getString("contents");
                return new MemoResponseDto(id, username, contents);
            }
        });
    }

    public void update(Long id, MemoRequestDto requestDto) {
        String sql = "UPDATE memo SET username = ?, contents = ? WHERE id = ?";
        jdbcTemplate.update(sql, requestDto.getUsername(), requestDto.getContents(), id);
    }

    public void delete(Long id) {
        String sql = "DELETE FROM memo WHERE id = ?";
        jdbcTemplate.update(sql, id);
    }

    public Memo findById(Long id) {
        // DB ์กฐํšŒ
        String sql = "SELECT * FROM memo WHERE id = ?";

        return jdbcTemplate.query(sql, resultSet -> {
            if (resultSet.next()) {
                Memo memo = new Memo();
                memo.setUsername(resultSet.getString("username"));
                memo.setContents(resultSet.getString("contents"));
                return memo;
            } else {
                return null;
            }
        }, id);
    }
}

 

4) DB ๊ด€๋ จ ์ž‘์—…์€ ๋ชจ๋‘ Repository์— ๋„˜๊ธด ํ›„์˜ Service! 

public class MemoService {

    private final JdbcTemplate jdbcTemplate;

    public MemoService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public MemoResponseDto createMemo(MemoRequestDto requestDto) {
        // RequestDto -> Entity
        Memo memo = new Memo(requestDto);

        // DB ์ €์žฅ
        MemoRepository memoRepository = new MemoRepository(jdbcTemplate);
        //๋ฉ”๋ชจ๋ฅผ ์ €์žฅํ•  ๋ฉ”์„œ๋“œ ํ•˜๋‚˜ ๋งŒ๋“ค์–ด์คŒ!
        Memo saveMemo = memoRepository.save(memo);

        // Entity -> ResponseDto
        MemoResponseDto memoResponseDto = new MemoResponseDto(saveMemo);

        return memoResponseDto;
    }

    public List<MemoResponseDto> getMemos() {
        // DB ์กฐํšŒ
        MemoRepository memoRepository = new MemoRepository(jdbcTemplate);
        return memoRepository.findAll();
    }

    public Long updateMemo(Long id, MemoRequestDto requestDto) {
        MemoRepository memoRepository = new MemoRepository(jdbcTemplate);
        // ํ•ด๋‹น ๋ฉ”๋ชจ๊ฐ€ DB์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
        Memo memo = memoRepository.findById(id);
        if (memo != null) {
            // memo ๋‚ด์šฉ ์ˆ˜์ •
            memoRepository.update(id, requestDto);

            return id;
        } else {
            throw new IllegalArgumentException("์„ ํƒํ•œ ๋ฉ”๋ชจ๋Š” ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
        }
    }

    public Long deleteMemo(Long id) {
        MemoRepository memoRepository = new MemoRepository(jdbcTemplate);
        // ํ•ด๋‹น ๋ฉ”๋ชจ๊ฐ€ DB์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
        Memo memo = memoRepository.findById(id);
        if (memo != null) {
            // memo ์‚ญ์ œ
            memoRepository.delete(id);

            return id;
        } else {
            throw new IllegalArgumentException("์„ ํƒํ•œ ๋ฉ”๋ชจ๋Š” ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.");
        }
    }
}

 

๋”๋ณด๊ธฐ

์ด๋ ‡๊ฒŒ 3 Layer Architecture ๋กœ ๋ถ„๋ฆฌ๋ฅผ ํ•ด์ฃผ๋ฉด

DB ๊ด€๋ จ ์ˆ˜์ • -> Repository

๋น„์ง€๋‹ˆ์Šค ๋กœ์ง ์ˆ˜์ • -> Service

๋ฐ์ดํ„ฐ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹ ์ˆ˜์ • -> Controller

๊ฐ๊ฐ ์šฉ๋„์— ๋งž๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์ˆ˜์ • ์‚ฌํ•ญ ๋˜ํ•œ ๊ฐ๊ฐ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด ๋œ๋‹ค!

์ด๋ ‡๊ฒŒ ๋ถ„๋ฆฌํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด ์œ ์ง€๋ณด์ˆ˜์— ํ›จ์”ฌ ์œ ๋ฆฌํ•  ๊ฒƒ์ด๋‹ค!

'Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

TIL Spring #2-3  (0) 2023.12.12
TIL Spring 2-2  (0) 2023.12.08
TIL Spring 1-3  (0) 2023.12.06
TIL Spring 1-2  (0) 2023.12.05
TIL Spring #1-1  (0) 2023.12.04