Spring/spring boot

spring boot를 사용한 게시판 만들기(2): 백엔드 개발

성장호소 2024. 4. 4. 16:24

https://sonnyday.tistory.com/14

에서 데이터로 게시판 번호, 게시글 제목, 작성자, 내용을 사용한다 했다.

이를 게시판 객체로 먼저 만들자.

게시판 도메인

package board.boardspring.domain;

public class Board {

    private Long id;
    private String title;
    private String content;
    private String author;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

 

간단하게 게시판 객체를 구현해 보았고 리포지토리 구조는 다음과 같다.

 

나중에 JPA로 바꿔서도 구현해 보려고 확장에 용이하게 인터페이스로 구현해 보았다.

 

일단 스프링 JdbcTemplate을 사용해 구현할 것이다.

스프링 JdbcTemplate은 순수 Jdbc에서 반복문을 제거해 개발자가 더 편리하게 구현할 수 있게 해주는 라이브러리이다. 하지만 SQL은 직접 작성해야 한다.

 

테이블 생성하기

drop table if exists board CASCADE;
CREATE TABLE board
(
    id bigint PRIMARY KEY,
    author varchar(255) ,
    title varchar(255),
    content varchar(255),
);

 

게시판 리포지토리 인터페이스

package board.boardspring.repository;

import board.boardspring.domain.Board;

import java.util.List;
import java.util.Optional;

public interface BoardRepository {
    Board save(Board board);
    List<Board> findAll();
    Optional<Board> findById(Long id);
    Board updatePost(Board board);
    void deletePost(Long id);
}

 

기본 CRUD의 추상 클래스를 선언했다.

 

게시판 리포지토리 JdbcTemplate 구현체

package board.boardspring.repository;

import board.boardspring.domain.Board;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class JdbcBoardRepository implements BoardRepository{

    private final JdbcTemplate jdbcTemplate;

    public JdbcBoardRepository(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Override
    public Board save(Board board) {
        SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
        jdbcInsert.withTableName("board").usingGeneratedKeyColumns("id");

        Map<String, Object> parameters = new HashMap<>();
        parameters.put("author", board.getAuthor());
        parameters.put("title", board.getTitle());
        parameters.put("content", board.getContent());

        Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameters));
        board.setId(key.longValue());

        return board;
    }

    @Override
    public List<Board> findAll() {
        return jdbcTemplate.query("select * from board", boardRowMapper());
    }

    @Override
    public Optional<Board> findById(Long id) {
        List<Board> result = jdbcTemplate.query("select * from board where id = ?", boardRowMapper(), id);
        return result.stream().findAny();
    }

    @Override
    public Board updatePost(Board board) {
        jdbcTemplate.update("update board set author = ?, title = ?, content = ? where id = ?", board.getAuthor(), board.getTitle(), board.getContent(), board.getId());
        return board;
    }

    @Override
    public void deletePost(Long id) {
        jdbcTemplate.update("delete from board where id = ?", id);
    }

    private RowMapper<Board> boardRowMapper() {
        return (rs, rowNum) -> {
            Board board = new Board();
            board.setId(rs.getLong("id"));
            board.setAuthor(rs.getString("author"));
            board.setContent(rs.getString("content"));
            board.setTitle(rs.getString("title"));
            return board;
        };
    }
}

 

JdbcTemplate은 sql문의 결과를 resultSet으로 가져오기에 이를 받아주는 boardRowMapper 메서드가 있어야 한다.

 

게시판 서비스 개발

서비스는 리포지토리를 통해 DB에 접근해 웹의 핵심 기능을 수행하므로 리포지토리 객체를 알아야 한다.

package board.boardspring.service;

import board.boardspring.domain.Board;
import board.boardspring.repository.BoardRepository;

import java.util.List;

public class BoardService {
    BoardRepository boardRepository;

    public BoardService(BoardRepository boardRepository) {
        this.boardRepository = boardRepository;
    }

    public Long savePost(Board board) {
        return boardRepository.save(board).getId();
    }

    public List<Board> findPosts() {
        return boardRepository.findAll();
    }

    public Board findOne(Long boardId) {
        return boardRepository.findById(boardId).get();
    }

    public Board updateOne(Board board) {
        return boardRepository.updatePost(board);
    }

    public void deleteOne(Long id) {
        boardRepository.deletePost(id);
    }
}

 

기존에는 게시판 서비스 객체가 게시판 리포지토리 구현체를 의존해야 했다.

하지만 스프링을 사용하면 스프링이 자동으로 스프링 컨테이너에 리포지토리 객체를 스프링 빈으로 등록해 관리해준다. 

그러면 개발자는 서비스 생성자만 만들어주면 스프링이 자동으로 컨테이너에서 생성된 객체를 가져와 연결해 줌으로써 DI, 즉 의존성 주입을 받을 수 있다.

스프링 빈과 의존 관계에 대한 내용은 다음 글에 정리해보겠다.