풀스택 백엔드 2026.06.09

syyu21b·2026년 6월 9일

풀스택 - 백엔드

목록 보기
26/49
post-thumbnail

[능력 단위 평가]

문제

요구사항


정답

Board

package com.example.board;

public class Board {
    private Long id;
    private String title;
    private String content;

    public Board() {}

    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;
    }
}

BoardController

package com.example.board;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.List;

@Controller
public class BoardController {

    private final BoardRepository boardRepository;

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

    @GetMapping("/")
    public String index(Model model) {
        List<Board> boards = boardRepository.findAll();
        model.addAttribute("boards", boards);
        return "index";
    }

    @GetMapping("/write")
    public String writeForm() {
        return "write";
    }

    @PostMapping("/write")
    public String write(Board board) {
        boardRepository.save(board);
        return "redirect:/";
    }

    @PostMapping("/delete")
    public String delete(Board board) {

        boardRepository.deleteById(board.getId());
        return "redirect:/";
    }
}

BoardRepository

package com.example.board;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class BoardRepository {

    private final JdbcTemplate jdbcTemplate;

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

    public List<Board> findAll() {
        String sql = "SELECT * FROM board ORDER BY id DESC";

        return jdbcTemplate.query(sql, (rs, rowNum) -> {
            Board board = new Board();
            board.setId(rs.getLong("id"));
            board.setTitle(rs.getString("title"));
            board.setContent(rs.getString("content"));
            return board;
        });
    }

    public void save(Board board) {
        String sql = "INSERT INTO board (title, content) VALUES (?, ?)";
        jdbcTemplate.update(sql, board.getTitle(), board.getContent());
    }

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

index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>게시판 메인</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(-45deg, #a18cd1, #fbc2eb, #84fab0, #8fd3f4);
            background-size: 400% 400%;
            animation: gradientBG 15s ease infinite;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        @keyframes gradientBG {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }

        .glass-container {
            background: rgba(255, 255, 255, 0.25);
            backdrop-filter: blur(15px);
            -webkit-backdrop-filter: blur(15px);
            border-radius: 20px;
            border: 1px solid rgba(255, 255, 255, 0.4);
            box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
            padding: 40px;
            width: 90%;
            max-width: 800px;
            animation: fadeIn 0.8s ease-out;
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-20px); }
            to { opacity: 1; transform: translateY(0); }
        }

        h1 {
            color: #333;
            text-align: center;
            margin-bottom: 30px;
        }

        .btn-write {
            display: inline-block;
            margin-bottom: 20px;
            padding: 10px 20px;
            background: rgba(255, 255, 255, 0.5);
            color: #333;
            text-decoration: none;
            border-radius: 10px;
            font-weight: bold;
            transition: all 0.3s;
        }

        .btn-write:hover {
            background: rgba(255, 255, 255, 0.8);
            transform: scale(1.05);
        }

        table {
            width: 100%;
            border-collapse: collapse;
            background: rgba(255, 255, 255, 0.3);
            border-radius: 10px;
            overflow: hidden;
        }

        th, td {
            padding: 15px;
            text-align: center;
            border-bottom: 1px solid rgba(255, 255, 255, 0.3);
            color: #222;
        }

        th {
            background: rgba(255, 255, 255, 0.5);
            font-weight: bold;
        }

        .btn-delete {
            background: rgba(255, 99, 71, 0.7);
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 8px;
            cursor: pointer;
            transition: 0.3s;
        }

        .btn-delete:hover {
            background: rgba(255, 99, 71, 1);
        }
    </style>
</head>
<body>

<div class="glass-container">
    <h1>자유 게시판</h1>

    <a th:href="@{/write}" class="btn-write">✨ 새 게시글 작성하기</a>

    <table>
        <thead>
        <tr>
            <th>ID</th>
            <th>제목</th>
            <th>내용</th>
            <th>관리</th>
        </tr>
        </thead>
        <tbody>
        <tr th:each="board : ${boards}">
            <td th:text="${board.id}"></td>
            <td th:text="${board.title}"></td>
            <td th:text="${board.content}"></td>
            <td>
                <form th:action="@{/delete}" method="post" style="margin: 0;">
                    <input type="hidden" name="id" th:value="${board.id}" />
                    <button type="submit" class="btn-delete">삭제</button>
                </form>
            </td>
        </tr>
        </tbody>
    </table>
</div>

</body>
</html>

write.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>게시글 작성</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(-45deg, #a18cd1, #fbc2eb, #84fab0, #8fd3f4);
            background-size: 400% 400%;
            animation: gradientBG 15s ease infinite;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        @keyframes gradientBG {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }

        .glass-container {
            background: rgba(255, 255, 255, 0.25);
            backdrop-filter: blur(15px);
            -webkit-backdrop-filter: blur(15px);
            border-radius: 20px;
            border: 1px solid rgba(255, 255, 255, 0.4);
            box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.2);
            padding: 40px;
            width: 90%;
            max-width: 500px;
            animation: fadeIn 0.8s ease-out;
        }

        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(-20px); }
            to { opacity: 1; transform: translateY(0); }
        }

        h1 {
            color: #333;
            text-align: center;
            margin-bottom: 30px;
        }

        .form-group {
            margin-bottom: 20px;
            display: flex;
            flex-direction: column;
        }

        label {
            margin-bottom: 8px;
            font-weight: bold;
            color: #333;
        }

        input[type="text"], textarea {
            background: rgba(255, 255, 255, 0.5);
            border: 1px solid rgba(255, 255, 255, 0.6);
            border-radius: 10px;
            padding: 12px;
            font-size: 16px;
            color: #333;
            outline: none;
            transition: 0.3s;
        }

        input[type="text"]:focus, textarea:focus {
            background: rgba(255, 255, 255, 0.8);
            box-shadow: 0 0 10px rgba(255,255,255,0.5);
        }

        .btn-group {
            display: flex;
            justify-content: space-between;
            margin-top: 30px;
        }

        button[type="submit"] {
            background: rgba(40, 167, 69, 0.7);
            color: white;
            border: none;
            padding: 12px 25px;
            border-radius: 10px;
            font-size: 16px;
            cursor: pointer;
            transition: 0.3s;
            flex: 1;
            margin-right: 10px;
        }

        button[type="submit"]:hover {
            background: rgba(40, 167, 69, 1);
        }

        .btn-cancel {
            background: rgba(108, 117, 125, 0.7);
            color: white;
            text-decoration: none;
            padding: 12px 25px;
            border-radius: 10px;
            font-size: 16px;
            text-align: center;
            transition: 0.3s;
            flex: 1;
        }

        .btn-cancel:hover {
            background: rgba(108, 117, 125, 1);
        }
    </style>
</head>
<body>

<div class="glass-container">
    <h1>게시글 작성</h1>

    <form th:action="@{/write}" method="post">
        <div class="form-group">
            <label for="title">제목</label>
            <input type="text" id="title" name="title" placeholder="제목을 입력하세요" required />
        </div>

        <div class="form-group">
            <label for="content">내용</label>
            <textarea id="content" name="content" rows="6" placeholder="내용을 입력하세요" required></textarea>
        </div>

        <div class="btn-group">
            <button type="submit">저장하기</button>
            <a th:href="@{/}" class="btn-cancel">취소</a>
        </div>
    </form>
</div>

</body>
</html>

schema.sql

CREATE TABLE IF NOT EXISTS board (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(100) NOT NULL,
    content VARCHAR(500) NOT NULL
    );

application.properties

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.h2.console.enabled=true
spring.sql.init.mode=always

0개의 댓글