๐Ÿฏ[TIL] 250707-026

byoยท2025๋…„ 7์›” 7์ผ

๐Ÿ“ ๊ต์‚ฌ/ํ•™์ƒ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ ์‹ค์Šต (ๅฎŒ)

๐Ÿง‘โ€๐Ÿซ๐Ÿ—‘๏ธ ์ง€๋‚œ๋ฒˆ ๊ต์‚ฌ ์‚ญ์ œ ๊ธฐ๋Šฅ ์ถ”๊ฐ€ ๋‚ด์šฉ

๐Ÿ—„๏ธ Repository

public int delete(int id) {
    return jdbcTemplate.update(
            "DELETE FROM teacher WHERE id = ?",
            id
    );
}

๐Ÿ“ก Controller

    @PostMapping("/delete/{id}")
    public String delete(@PathVariable int id, Model model) {
        try {
            int affected = teacherRepository.delete(id);

            if (affected == 0) {
                System.out.println("ํ•ด๋‹น ๊ต์‚ฌ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
            }
        } catch (Exception e) {
            model.addAttribute("error", e.getMessage());
            System.out.println(e.getMessage());
        }
        return "redirect:/teachers";
    }
  • ๋‚˜๋Š” @GetMapping ์œผ๋กœ ์ž‘์„ฑํ–ˆ์—ˆ๋Š”๋ฐ, ๊ทœ์น™์ƒ delete๋Š” @PostMapping ์ด๋ผ๊ณ  ํ•œ๋‹ค. ์ƒ๊ฐํ•ด ๋ณด๋‹ˆ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ํ™”๋ฉด์œผ๋กœ ๋˜์งˆ๋•Œ๋„ ์žˆ์œผ๋‹ˆ post๊ฐ€ ๋” ์ ์ ˆํ•œ๊ฒƒ ๊ฐ™๋‹ค.

๐Ÿ–ผ๏ธ teacher-list.html

<!--            <a th:href="@{'/teachers/delete/' + ${teacher.id}}">์‚ญ์ œ</a>-->
            <form th:action="@{'/teachers/delete/' + ${teacher.id}}" method="post" style="display:inline;">
                <button type="submit">์‚ญ์ œ</button>
            </form>

๐Ÿ‘ฉโ€๐ŸŽ“ ํ•™์ƒ ์—”ํ‹ฐํ‹ฐ ๊ด€๋ จ ๊ธฐ๋Šฅ

๐Ÿง  Student model

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Student {
    private Integer id;
    private String name;
    private Integer score;
    private Integer teacherId;
    private String teacherName;
}
  • data์— ํฌํ•จ๋œ ๊ฒƒ : ๊ฒŸ, ์…‹, ์Šคํƒœํ‹ฑ ์ดˆ๊ธฐํ™”, toString, ์ดํ€„์Šค์•คํ•ด์‹œ์ฝ”๋“œ

๐Ÿ—„๏ธ Student Repository

@Repository
@RequiredArgsConstructor
public class StudentRepository {
    private final JdbcTemplate jdbcTemplate;

    private final RowMapper<Student> mapper = (resultSet, rowNum) ->
            Student.builder()
                    .id(resultSet.getInt("id"))
                    .name(resultSet.getString("name"))
                    .score(resultSet.getInt("score"))
                    .teacherId(resultSet.getInt("teacher_id"))
                    .build();

    public List<Student> findAll() {
        String sql = "SELECT s.id, s.name, s.score, s.teacher_id, t.name AS teacher_name " +
                "FROM student s LEFT JOIN teacher t ON s.teacher_id = t.id " +
                "ORDER BY s.id";
        return jdbcTemplate.query(sql, mapper);
    }

    public Student findById(int id) {
        String sql = "SELECT s.id, s.name, s.score, s.teacher_id, t.name AS teacher_name " +
                "FROM student s LEFT JOIN teacher t ON s.teacher_id = t.id " +
                "WHERE s.id = ?";
        return jdbcTemplate.queryForObject(sql, mapper, id);
    }

    public int save(Student student) {
        return jdbcTemplate.update(
                "INSERT INTO student (name, score, teacher_id) VALUES (?, ?, ?)",
                student.getName(),
                student.getScore(),
                student.getTeacherId()
        );
    }

    public int update(Student student) {
        return jdbcTemplate.update(
                "UPDATE student SET name = ?, score = ?, teacher_id = ? WHERE id = ?",
                student.getName(), student.getScore(), student.getTeacherId(), student.getId()
        );
    }

    public int delete(int id) {
        return jdbcTemplate.update(
                "DELETE FROM student WHERE id = ?",
                id
        );
    }
}
ํ•จ์ˆ˜์„ค๋ช…
mapperRowMapper์™€ ๋žŒ๋‹ค, builder๋ฅผ ์ด์šฉํ•ด data row๋ฅผ ์ž๋ฐ” ์ธ์Šคํ„ด์Šค๋กœ ๋งคํ•‘ํ•˜๋Š” ํ•จ์ˆ˜
findAlljdbcTemplate์ด sql๋กœ rowData, rowNum์„ ๊ฐ€์ ธ์™€ mapper์— ๋„˜๊ฒจ ์ธ์Šคํ„ด์Šค ๋ฆฌ์ŠคํŠธ ์ƒ์„ฑ.
findById"WHERE s.id = ?" ๊ตฌ๋ฌธ์œผ๋กœ Student ๊ฐ์ฒด 1๊ฐœ๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์— queryForObject() ์‚ฌ์šฉ.
saveupdate("INSERT INTO student (name, score, teacher_id) VALUES (?, ?, ?)", student.ยทยทยท
updateupdate("UPDATE student SET name = ?, score = ?, teacher_id = ? WHERE id = ?", student.ยทยทยท
deleteupdate("DELETE FROM student WHERE id = ?", student.ยทยทยท

๐Ÿ“ก Student Controller

@Controller
@RequestMapping("/students")
@RequiredArgsConstructor
public class StudentController {
    private final StudentRepository studentRepository;
    private final TeacherRepository teacherRepository;

    @GetMapping
    public String list(Model model) {
        model.addAttribute("students", studentRepository.findAll());
        return "student-list";
    }

    @GetMapping("/add")
    public String addForm(Model model) {
        List<Teacher> teachers = teacherRepository.findAll();
        model.addAttribute("student", new Student()); // ๋นˆ ๊ฐ์ฒด ๋˜์ง€๊ธฐ
        model.addAttribute("teachers", teachers);
        return "student-form";
    }

    @PostMapping("/add")
    public String add(@ModelAttribute Student student) {
        studentRepository.save(student);
        return "redirect:/students";
    }

    @GetMapping("/edit/{id}")
    public String editForm(@PathVariable int id, Model model) {
        model.addAttribute("student", studentRepository.findById(id));
        model.addAttribute("teachers", teacherRepository.findAll());
        return "student-form";
    }

    @PostMapping("/edit")
    public String edit(@ModelAttribute Student student) {
        studentRepository.update(student);

        return "redirect:/students";
    }

    @PostMapping("/delete/{id}")
    public String delete(@PathVariable int id) {
        studentRepository.delete(id);
        return "redirect:/students";
    }
}
์ปจํŠธ๋กค๋Ÿฌ์„ค๋ช…
@GetMapping๋ชจ๋ธ์— List<Student> ๋‹ด์•„ ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌ
@GetMapping("/add")ํ•™์ƒ ์ž…๋ ฅ ํผ์— Student ๋นˆ ๊ฐ์ฒด, List<Teachers> ์ „๋‹ฌ
@PostMapping("/add")html <form>์—์„œ @ModelAttribute๋กœ Student๊ฐ์ฒด ๋„˜๊ธฐ๋ฉด repository๋กœ ์ €์žฅ
@GetMapping("/edit/{id}")@PathVariable๋กœ Student id ๋ฐ›์•„์„œ repository๋กœ ์ฐพ์•„์„œ teachers์™€ ํ•จ๊ป˜ ๋ฐ˜ํ™˜
@PostMapping("/edit")html <form>์—์„œ @ModelAttribute๋กœ Student๊ฐ์ฒด ๋„˜๊ธฐ๋ฉด repository๋กœ ์—…๋ฐ์ดํŠธ
@PostMapping("/delete/{id}")@PathVariable๋กœ Student id ๋ฐ›์•„์„œ repository๋กœ ์ฐพ์•„์„œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ

๐Ÿ–ผ๏ธ student-list.html

<body>
<h1>๐Ÿ‘ฉโ€๐ŸŽ“ ํ•™์ƒ ๋ชฉ๋ก</h1>
<p>
    <a href="/">๐Ÿ  ํ™ˆ์œผ๋กœ</a>
    <a href="/students/add">โž• ํ•™์ƒ ๋“ฑ๋ก</a>
</p>
<table>
    <p style="color:red;" th:if="${error}" th:text="${error}"></p>
    <thead>
    <tr>
        <td>ID</td>
        <td>์ด๋ฆ„</td>
        <td>์„ฑ์ </td>
        <td>๊ต์‚ฌ</td>
        <td>์•ก์…˜</td>
    </tr>
    </thead>
    <tbody th:each="student: ${students}">
    <tr>
        <td th:text="${student.id}"></td>
        <td th:text="${student.name}"></td>
        <td th:text="${student.score}"></td>
        <td th:text="${student.teacherName} ?: '-'"></td>
        <td>
            <a th:href="@{'/students/edit/' + ${student.id}}">์ˆ˜์ •</a>
            <form th:action="@{'/students/delete/' + ${student.id}}" method="post" style="display:inline;">
                <button type="submit">์‚ญ์ œ</button>
            </form>
        </td>
    </tr>
    </tbody>
</table>
</body>

๐Ÿ–ผ๏ธ Student-form.html

<body>
    <h1 th:text="${student.id} == null ? 'โž• ํ•™์ƒ ๋“ฑ๋ก' : 'ํ•™์ƒ ์ˆ˜์ •'"></h1>
    <p>
        <a href="/">ํ™ˆ์œผ๋กœ</a>
        <a href="/students">ํ•™์ƒ ๋ชฉ๋ก</a>
    </p>
    <form th:action="${student.id} == null ? @{/students/add} : @{/students/edit}" th:object="${student}" method="post">
        <input type="hidden" th:field="*{id}">
        <p><label>์ด๋ฆ„: <input type="text" th:field="*{name}" required/></label></p>
        <p><label>์„ฑ์ : <input type="text" th:field="*{score}" required/></label></p>
        <p><label>๊ต์‚ฌ: <select th:field="*{teacherId}" required>
            <option th:each="teacher: ${teachers}" th:value="${teacher.id}" th:text="${teacher.name}">

            </option>
        </select></label></p>
        <p>
            <button type="submit">์ €์žฅํ•˜๊ธฐ</button>
            <a href="/students">์ทจ์†Œํ•˜๊ธฐ</a>
        </p>
    </form>
</body>

๐Ÿ’ซ DTO

โœ”๏ธ DTO๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

  • Data Transfer Object์˜ ์•ฝ์ž
  • ์ˆœ์ˆ˜ํ•œ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์šฉ ๊ฐ์ฒด
  • ๋‚ด๋ถ€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด๋‚˜ DB ๋งคํ•‘ ์ฝ”๋“œ ์—†์Œ
  • ์ฃผ๋กœ ๊ณ„์ธต ๊ฐ„(Controller โ†” Service โ†” Repository) ๋ฐ์ดํ„ฐ ์ด๋™์— ์‚ฌ์šฉ

โœ”๏ธ ์—”ํ‹ฐํ‹ฐ(Entity)์™€ DTO์˜ ์ฐจ์ด

๊ตฌ๋ถ„์—”ํ‹ฐํ‹ฐ (Entity)DTO
์—ญํ• DB ํ…Œ์ด๋ธ”๊ณผ 1:1 ๋งคํ•‘, ์˜์†์„ฑ ๊ด€๋ฆฌ๋ฐ์ดํ„ฐ ์ „๋‹ฌ๋งŒ, ์˜์†์„ฑ ๋กœ์ง ์—†์Œ
ํฌํ•จ ๋‚ด์šฉPK, ์—ฐ๊ด€๊ด€๊ณ„, JPA ์–ด๋…ธํ…Œ์ด์…˜, ๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”์„œ๋“œ ๋“ฑ ํฌํ•จํ™”๋ฉด/API์— ํ•„์š”ํ•œ ํ•„๋“œ ํ•œ์ •, ๋ณด์•ˆ ๋ฏผ๊ฐ ์ •๋ณด ์ œ์™ธ
์ฑ…์ž„ ๋ถ„๋ฆฌ๋ฐ์ดํ„ฐ ์ €์žฅยท์กฐํšŒยท์—ฐ๊ด€ ์ฒ˜๋ฆฌํŒจํ‚ท์ฒ˜๋Ÿผ ๊ณ„์ธต ๊ฐ„ ๊ฐ’ ๋ฌถ์Œ ์ „๋‹ฌ

์—”ํ‹ฐํ‹ฐ๋Š” โ€œ์ €์žฅยท์กฐํšŒโ€ ๋‹ด๋‹น, DTO๋Š” โ€œ์ „๋‹ฌยท์‘๋‹ตโ€ ๋‹ด๋‹น

โœ”๏ธ ์˜ˆ์‹œ : DTO ๊ธฐ๋ฐ˜ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ ์•ฑ โ€“ ๋กœ๊ทธ์ธยทํšŒ์›๊ฐ€์ž…ยทCRUD ํ๋ฆ„

๐Ÿง  Entity

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  username VARCHAR(50) UNIQUE NOT NULL,
  password VARCHAR(100) NOT NULL
);

CREATE TABLE todo (
  id SERIAL PRIMARY KEY,
  user_id INT REFERENCES users(id) ON DELETE CASCADE,
  title VARCHAR(200) NOT NULL,
  completed BOOLEAN DEFAULT FALSE
);

๐Ÿšš DTO

// ๋กœ๊ทธ์ธ์šฉ
public class LoginDto {
  private String username;
  private String password;
}

// ํšŒ์›๊ฐ€์ž…์šฉ
public class SignupDto {
  private String username;
  private String password;
}

// ํ•  ์ผ CRUD์šฉ
public class TodoDto {
  private Integer id;
  private String title;
  private boolean completed;
}

๐Ÿ—„๏ธ repository

public User findByUsername(String username) {
  try {
    return jdbc.queryForObject("SELECT * FROM users WHERE username=?", mapper, username);
  } catch (EmptyResultDataAccessException e) {
    return null;
  }
}

public int save(User u) { /* ํšŒ์›๊ฐ€์ž… INSERT */ }

public List<Todo> findAllByUserId(int uid) { /* ๋ชฉ๋ก SELECT */ }
public int save(Todo t)   { /* INSERT */ }
public int update(Todo t) { /* UPDATE */ }
public int delete(int id, int uid) { /* DELETE */ }

๐Ÿ“ก ์ปจํŠธ๋กค๋Ÿฌ ํ๋ฆ„ ์š”์•ฝ

  1. ํšŒ์›๊ฐ€์ž…
    • GET /signup โ†’ ๋นˆ SignupDto ์ „๋‹ฌ
    • POST /signup
      • ์ค‘๋ณต ์ฒดํฌ(findByUsername), ์ €์žฅ(save)
      • ์„ฑ๊ณต ์‹œ redirect:/login?registered
  2. ๋กœ๊ทธ์ธ
    • GET /login โ†’ ๋นˆ LoginDto
    • POST /login
      • @ModelAttribute LoginDto โ†’ ํผ ๋ฐ”์ธ๋”ฉ
      • ์ธ์ฆ ํ†ต๊ณผ โ†’ session.setAttribute("user", user)
      • redirect:/todos
  3. ํ•  ์ผ CRUD
    • GET /todos โ†’ findAllByUserId โ†’ ๋ชฉ๋ก
    • GET/POST /todos/add โ†’ ์ƒˆ ํ•ญ๋ชฉ ์ถ”๊ฐ€
    • GET/POST /todos/edit/{id} โ†’ ์ˆ˜์ •
    • POST /todos/delete/{id} โ†’ ์‚ญ์ œ
@PostMapping("/todos/add")
public String add(@ModelAttribute TodoDto dto, HttpSession session) {
  int uid = getCurrentUser(session).getId();
  todoRepo.save(new Todo(uid, dto.getTitle(), dto.isCompleted()));
  return "redirect:/todos";
}

๐Ÿ’ซ CS

โœ”๏ธ Interrupt

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread worker = new Thread(() -> {
            System.out.println("Worker: ์ž‘์—… ์‹œ์ž‘");
            try {
                while (!Thread.currentThread().isInterrupted()) {
                    System.out.println("Working...");
                    Thread.sleep(500);
                }

            } catch(InterruptedException e) {
                System.out.println("Worker: ์ค‘๋‹จ ์‹ ํ˜ธ ์ˆ˜์‹ , ์ •๋ฆฌ ์ž‘์—… ํ›„ ์ข…๋ฃŒ");
            }
        });

        worker.start();
        Thread.sleep(2000);
        System.out.println("๋ฉ”์ธ์—์„œ ์ธํ„ฐ๋ŸฝํŠธ ์‹ ํ˜ธ ์ „์†ก");
        worker.interrupt();
        worker.join();
        System.out.println("Worker: ์ž‘์—… ์™„๋ฃŒ");
    }
}
Worker: ์ž‘์—… ์‹œ์ž‘
Working...
Working...
Working...
Working...
๋ฉ”์ธ์—์„œ ์ธํ„ฐ๋ŸฝํŠธ ์‹ ํ˜ธ ์ „์†ก
Worker: ์ค‘๋‹จ ์‹ ํ˜ธ ์ˆ˜์‹ , ์ •๋ฆฌ ์ž‘์—… ํ›„ ์ข…๋ฃŒ
Worker: ์ž‘์—… ์™„๋ฃŒ

โœ”๏ธ Execption

public class Main {
    public static int divide(int a, int b) throws ArithmeticException {
        if (b ==0) throw new ArithmeticException("0์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.");
        return a /b;
    }
    public static void main(String[] args) {
        try {
            System.out.println(divide(10, 2));
            System.out.println(divide(10, 0));
        } catch (ArithmeticException e) {
            System.out.println("์˜ˆ์™ธ ๋ฐœ์ƒ: " + e.getMessage());
        } finally {
            System.out.println("์ฒ˜๋ฆฌ ์™„๋ฃŒ.");
        }
    }
}
5
์˜ˆ์™ธ ๋ฐœ์ƒ: 0์œผ๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
์ฒ˜๋ฆฌ ์™„๋ฃŒ.
profile
๐Ÿ—‚๏ธ hamstern

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