๐Ÿฏ[TIL] 250704-025

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

๐Ÿ’ซ Lombok

โœ”๏ธ ์™œ Lombok์„ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

  • ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ œ๊ฑฐ
    • ๋ฐ˜๋ณต๋˜๋Š” ์ƒ์„ฑ์ž, getter/setter, toString, equals/hashCode ๋“ฑ์„ ์–ด๋…ธํ…Œ์ด์…˜ ํ•œ ์ค„๋กœ ์ž๋™ ์ƒ์„ฑ
  • ์ฝ”๋“œ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ
    • ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๊ณ , ํด๋ž˜์Šค ์ •์˜๊ฐ€ ๊ฐ„๊ฒฐํ•ด์ง
  • ์œ ์ง€๋ณด์ˆ˜์„ฑ ์ฆ๋Œ€
    • ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•  ๋•Œ ์–ด๋…ธํ…Œ์ด์…˜ ์˜ต์…˜๋งŒ ์กฐ์ •ํ•˜๋ฉด ๋˜๋ฏ€๋กœ ์ˆ˜์ • ๋ฒ”์œ„ ์ตœ์†Œํ™”
  • ์ปดํŒŒ์ผ ํƒ€์ž„ ์ฒ˜๋ฆฌ
    • IDE์™€ ๋นŒ๋“œ ํˆด์—์„œ ์ž๋™์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ๋Ÿฐํƒ€์ž„ ์˜ค๋ฒ„ํ—ค๋“œ๋Š” ์—†์Œ

๐Ÿ‘‰ ํ•ต์‹ฌ: Lombok์€ ์ฝ”๋“œ ์ž๋™ ์ƒ์„ฑ์„ ํ†ตํ•ด ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ๊ณผ ์ฝ”๋“œ ํ’ˆ์งˆ์„ ๋™์‹œ์— ๋Œ์–ด์˜ฌ๋ ค ์ค๋‹ˆ๋‹ค.

โœ”๏ธ Lombok ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฃผ์š” ์–ด๋…ธํ…Œ์ด์…˜ ํ™œ์šฉ ๊ฐ€์ด๋“œ

โœ… 1. @Getter / @Setter

  • ์—ญํ• : ๊ฐ ํ•„๋“œ์— ๋Œ€ํ•œ getter ๋ฐ setter ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์„ฑ
  • ์ ์šฉ๋ฒ•: ํด๋ž˜์Šค ๋ ˆ๋ฒจ ๋˜๋Š” ๊ฐœ๋ณ„ ํ•„๋“œ์— ๋ถ™์ด๋ฉด ์ž๋™ ์ƒ์„ฑ
  • ํ™•์ธ๋ฒ•: IDE์—์„œ ๋ฉ”์„œ๋“œ ์ž๋™ ์™„์„ฑ ๋˜๋Š” ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋กœ ํ˜ธ์ถœํ•ด ๋ณด๊ธฐ
@Getter @Setter
public class Memo {
    private int id;
    private String title;
    private String content;
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ (๋‹จ์œ„ ํ…Œ์ŠคํŠธ)
public void testGetterSetter() {
    Memo memo = new Memo();
    memo.setTitle("Hello");
    assert "Hello".equals(memo.getTitle());
}

โœ… 2. @NoArgsConstructor / @AllArgsConstructor

  • @NoArgsConstructor: ๋งค๊ฐœ๋ณ€์ˆ˜ ์—†๋Š” ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ์ƒ์„ฑ
  • @AllArgsConstructor: ๋ชจ๋“  ํ•„๋“œ๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š” ์ƒ์„ฑ์ž ์ƒ์„ฑ
  • ํ™•์ธ๋ฒ•: IDE์—์„œ ์ƒ์„ฑ์ž ํ˜ธ์ถœ ๋˜๋Š” ๋ฆฌํ”Œ๋ ‰์…˜ ์‚ฌ์šฉ
@NoArgsConstructor
@AllArgsConstructor
public class CustomerRank {
    private int customerId;
    private BigDecimal totalSpent;
    private int rank;
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
public void testConstructors() {
    CustomerRank empty = new CustomerRank();          // NoArgs
    CustomerRank full  = new CustomerRank(1, new BigDecimal("100.00"), 1);
    assert full.getCustomerId() == 1;
}

โœ… 3. @RequiredArgsConstructor

  • ์—ญํ• : final ๋˜๋Š” @NonNull ํ•„๋“œ๋งŒ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›๋Š” ์ƒ์„ฑ์ž ์ƒ์„ฑ
  • ์žฅ์ : ์ƒ์„ฑ์ž ์ฃผ์ž… ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑ
  • ํ™•์ธ๋ฒ•: final ํ•„๋“œ ์ž๋™ ์ฃผ์ž… ํ™•์ธ, IDE์—์„œ ์ƒ์„ฑ์ž ํ™•์ธ
@RequiredArgsConstructor
public class DashboardController {
    private final DashboardRepository repo;
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
public void testRequiredArgs() {
    DashboardRepository repo = new DashboardRepository(...);
    DashboardController ctrl = new DashboardController(repo);
    assert ctrl.getRepo() == repo;
}

โœ… 4. @ToString

  • ์—ญํ• : toString() ๋ฉ”์„œ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑ
  • ์˜ต์…˜: exclude, of, callSuper ๋“ฑ์œผ๋กœ ํ•„๋“œ ์ง€์ • ๊ฐ€๋Šฅ
  • ํ™•์ธ๋ฒ•: System.out.println() ์œผ๋กœ ์ถœ๋ ฅ
@ToString(includeFieldNames = true)
public class DailySales {
    private LocalDate saleDate;
    private BigDecimal totalAmount;
    private int orderCount;
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
public void testToString() {
    DailySales ds = new DailySales(LocalDate.now(), new BigDecimal("50.00"), 5);
    System.out.println(ds);  // DailySales(saleDate=..., totalAmount=50.00, orderCount=5)
}

โœ… 5. @EqualsAndHashCode

  • ์—ญํ• : equals() ๋ฐ hashCode() ๋ฉ”์„œ๋“œ๋ฅผ ์ž๋™ ์ƒ์„ฑ
  • ์˜ต์…˜: exclude, onlyExplicitlyIncluded ๋“ฑ์œผ๋กœ ํ•„๋“œ ์ง€์ •
  • ํ™•์ธ๋ฒ•: ์ปฌ๋ ‰์…˜ ๋น„๊ต ๋˜๋Š” equals() ์ง์ ‘ ํ˜ธ์ถœ
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Memo {
    @EqualsAndHashCode.Include
    private int id;
    private String title;
    private String content;
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
public void testEqualsHashCode() {
    Memo m1 = new Memo(1, "A", "B");
    Memo m2 = new Memo(1, "X", "Y");
    assert m1.equals(m2);
    assert m1.hashCode() == m2.hashCode();
}

โœ… 6. @Data

  • ์—ญํ• : @Getter, @Setter, @RequiredArgsConstructor, @ToString, @EqualsAndHashCode๋ฅผ ํ•œ ๋ฒˆ์— ํฌํ•จ
  • ์ถ”์ฒœ: ์ˆœ์ˆ˜ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด ์ •์˜
  • ํ™•์ธ๋ฒ•: ์œ„ ๋ชจ๋“  ๊ธฐ๋Šฅ ํ™•์ธ
@Data
public class CustomerRank {
    private final int customerId;
    private BigDecimal totalSpent;
    private int rank;
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ: getter, setter, toString, equals ๋ชจ๋‘ ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
public void testDataAnnotation() {
    CustomerRank cr = new CustomerRank(1);
    cr.setTotalSpent(new BigDecimal("200"));
    System.out.println(cr);
    assert cr.getCustomerId() == 1;
}

โœ… 7. @Builder

  • ์—ญํ• : ๋นŒ๋” ํŒจํ„ด ์ฝ”๋“œ๋ฅผ ์ž๋™ ์ƒ์„ฑ
  • ์žฅ์ : ๊ฐ€๋…์„ฑ ๋†’์€ ๊ฐ์ฒด ์ƒ์„ฑ, ์„ ํƒ์  ํŒŒ๋ผ๋ฏธํ„ฐ ์ฒ˜๋ฆฌ
  • ํ™•์ธ๋ฒ•: builder() ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
@Builder
public class DailySales {
    private LocalDate saleDate;
    private BigDecimal totalAmount;
    private int orderCount;
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
public void testBuilder() {
    DailySales ds = DailySales.builder()
        .saleDate(LocalDate.of(2025,1,1))
        .totalAmount(new BigDecimal("1000.00"))
        .orderCount(20)
        .build();
    assert ds.getOrderCount() == 20;
}

โ˜‘๏ธ 8. ์‹ค์ „ ํŒ

  • ์Šคํ”„๋ง ๋นˆ ์ƒ์„ฑ์ž ์ฃผ์ž…: @RequiredArgsConstructor + final ํ•„๋“œ โ†’ ๊น”๋”ํ•œ ์ปจํŠธ๋กค๋Ÿฌ/์„œ๋น„์Šค ์„ ์–ธ
  • ๋ฐ์ดํ„ฐ ์ „์†ก ๊ฐ์ฒด(DTO): @Data + @NoArgsConstructor + @AllArgsConstructor๋กœ ๋น ๋ฅด๊ฒŒ ์ •์˜
  • ๋กœ๊น…/๋””๋ฒ„๊น…: @ToString(exclude="password") ์ฒ˜๋Ÿผ ๋ฏผ๊ฐ ์ •๋ณด ์ œ์™ธ ๊ฐ€๋Šฅ

๐Ÿ“ ์‹ค์Šต : ๊ต์‚ฌ, ํ•™์ƒ CRUD

๐Ÿ’ซ DB Table ๊ตฌ์„ฑ

postgreSql๋กœ ๊ตฌ์„ฑ๋œ ๋กœ์ปฌ db์— ํ…Œ์ด๋ธ” ์ƒ์„ฑ

  • powerShell > postgreSQL
psql -U postgres

CREATE USER edu_system WITH PASSWORD 'password';
\du

CREATE DATABASE edu_system OWNER edu_system;
\l

\q

psql -U edu_system -W

CREATE TABLE teacher (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL
);

CREATE TABLE student (
  id SERIAL PRIMARY KEY,
  name VARCHAR(100) NOT NULL,
  score INT NOT NULL,
  teacher_id INT REFERENCES teacher(id)
);

RDB 1:n ๊ฐ™์€๊ฑฐ ์ฒจ์— ๋ฐฐ์šธ๋•Œ ์–ด์ง€๋Ÿฌ์› ๋Š”๋ฐ..
reference ๋ฅผ teacher ํ…Œ์ด๋ธ”์— ๋‘๋ƒ student ํ…Œ์ด๋ธ”์— ๋‘๋ƒ ๋น„๊ตํ•ด์„œ ๋ณด๋‹ˆ๊นŒ ํ™• ์™€๋‹ฟ์•˜๋‹ค.. ๋‹น์—ฐํžˆ student์— ๋‘ฌ์•ผ ์กฐํšŒํ• ๋•Œ ํŽธํ•˜๋‹ค. teacher๊ฐ€ ๋ชจ๋“  ํ•™์ƒ์„ ๊ฐ–๊ณ ์žˆ์œผ๋ฉด ํ•˜๋‚˜ ๊ฒ€์ƒ‰ํ• ๋•Œ ๋ชจ๋“  ๋ฐฐ์—ด์„ ์ˆœํšŒํ•ด์•ผ ํ•˜๋‹ˆ๊นŒ ์—๋„ˆ์ง€๊ฐ€ ๋” ๋“ค์–ด ๋น„ํšจ์œจ์ ์ด๋‹ค.


๐ŸŒ HTTP ๋ฉ”์„œ๋“œ

HTTP ๋ฉ”์„œ๋“œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์— ์–ด๋–ค ๋™์ž‘์„ ์š”์ฒญํ•˜๋Š”์ง€ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฉ์‹์ด๋‹ค.
REST API ์„ค๊ณ„์—์„œ๋„ ์ด ๋ฉ”์„œ๋“œ๋“ค์ด ๋งค์šฐ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•œ๋‹ค.

๋ฉ”์„œ๋“œ์˜๋ฏธ์„ค๋ช…
GET์กฐํšŒ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญ (์ฝ๊ธฐ ์ „์šฉ, ์•ˆ์ „ํ•จ)
POST์ƒ์„ฑ์„œ๋ฒ„์— ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑ (๋ณดํ†ต html form์œผ๋กœ ๋ฐ›์•„์˜ค๊ณ  ์žˆ๋‹ค.)
PUT์ˆ˜์ • (์ „์ฒด)๋ฆฌ์†Œ์Šค๋ฅผ ์ „์ฒด ์ˆ˜์ •
PATCH์ˆ˜์ • (์ผ๋ถ€)๋ฆฌ์†Œ์Šค ์ผ๋ถ€ ํ•„๋“œ๋งŒ ์ˆ˜์ •
DELETE์‚ญ์ œ๋ฆฌ์†Œ์Šค ์ œ๊ฑฐ

๐Ÿ’ซ Spring

โœ”๏ธ Teacher, Student CRUD

โž• Add Teacher

๐Ÿง  model

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Teacher {
    private Integer id;
    private String name;
}
  • lombok์œผ๋กœ ํ•„๋“œ ์ดˆ๊ธฐํ™” ์—†๋Š” ์ƒ์„ฑ์ž, ๋ชจ๋“  ํ•„๋“œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ์ƒ์„ฑ์ž ๋“ฑ ์ฃผ์ž…

๐Ÿ—„๏ธ repository - jdbc๋กœ db์— ์ €์žฅ

@Repository
@RequiredArgsConstructor
//@NoArgsConstructor
public class TeacherRepository {
    private final JdbcTemplate jdbcTemplate;

    public int save(Teacher teacher) {
        return jdbcTemplate.update(
                "INSERT INTO teacher (name) VALUES (?)",
                teacher.getName()
        );
    }
}
  • save ๋ฐ˜ํ™˜ํ˜•์ด int ์ธ ์ด์œ ๋Š” jdbc.update๊ฐ€ ์ฟผ๋ฆฌ ์˜ํ–ฅ ๋ฐ›์€ row ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž„

๐Ÿ“ก controller

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

    @GetMapping
    public String list() {
        return "teacher-list";
    }

    @GetMapping("/add")
    public String addForm() {
        return "teacher-form";
    }

    @PostMapping("/add")
    public String add(@ModelAttribute Teacher teacher) {
        teacherRepository.save(teacher);
        return "redirect:/teachers";
    }
}
@RequestMapping("/teachers")
@GetMapping() -> teacher-list.html
@GetMapping("/add") -> teacher-form.html
@PostMapping("/add") -> (repository)save -> redirect to teacher-list.html
๐ŸŽจ styles.css
/* ์ „์ฒด ๋ฐฐ๊ฒฝ & ๊ธฐ๋ณธ ํฐํŠธ */
body {
  margin: 0;
  padding: 20px;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  background-color: #FFF8F0; /* ์—ฐํ•œ ๋ฒ ์ด์ง€ */
  color: #5A4E4D;            /* ๋ถ€๋“œ๋Ÿฌ์šด ๋ธŒ๋ผ์šด */
}

/* ์ปจํ…Œ์ด๋„ˆ */
.container {
  max-width: 960px;
  margin: 0 auto;
}

/* ์ œ๋ชฉ */
h1 {
  text-align: center;
  margin-bottom: 24px;
  font-size: 2rem;
  color: #A27B5C; /* ํŒŒ์Šคํ…” ๋ธŒ๋ผ์šด */
}

/* ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋งํฌ */
a {
  text-decoration: none;
  color: #7DAEA3; /* ํŒŒ์Šคํ…” ๋ฏผํŠธ */
  margin-right: 12px;
}
a:hover {
  text-decoration: underline;
  color: #60948C;
}

/* ๋ฒ„ํŠผ */
button, .btn {
  display: inline-block;
  padding: 8px 16px;
  font-size: 0.95rem;
  border: none;
  border-radius: 8px;
  background-color: #E3C9C1; /* ํŒŒ์Šคํ…” ํ•‘ํฌ */
  color: #5A4E4D;
  cursor: pointer;
  transition: background-color 0.3s;
}
button:hover, .btn:hover {
  background-color: #D3B6AE;
}

/* ํ‘œ */
table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 16px;
  background-color: #FFF5E4; /* ์•„์ฃผ ์—ฐํ•œ ์‚ด๊ตฌ */
}
th, td {
  padding: 12px;
  border: 1px solid #E3C9C1;
  text-align: center;
}
th {
  background-color: #F6E8E1; /* ํŒŒ์Šคํ…” ์‚ด๊ตฌ */
  color: #7D5A50;
}

/* ํผ */
form, .form-container {
  max-width: 600px;
  margin: 0 auto 24px auto;
  padding: 20px;
  background-color: #FEF9F5; /* ๊ฑฐ์˜ ํฐ์ƒ‰์— ๊ฐ€๊นŒ์šด ์‚ด๊ตฌ */
  border: 1px solid #E3C9C1;
  border-radius: 10px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
input[type="text"],
input[type="number"],
select {
  width: 100%;
  padding: 10px;
  margin-top: 6px;
  margin-bottom: 16px;
  border: 1px solid #E3C9C1;
  border-radius: 6px;
  background-color: #FFFBF8;
  font-size: 1rem;
}
input:focus,
select:focus {
  outline: none;
  border-color: #7DAEA3; /* ํฌ์ปค์Šค ์‹œ ํŒŒ์Šคํ…” ๋ฏผํŠธ */
}

/* ์•ก์…˜ ๋งํฌ(์ทจ์†Œ) */
.cancel {
  margin-left: 12px;
  color: #A27B5C;
}
.cancel:hover {
  color: #7D5A50;
}

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

  • ๊ต์‚ฌ ๋“ฑ๋ก ํผ
<body>
    <h1>๊ต์‚ฌ ๋“ฑ๋ก</h1>
    <p>
        <a href="/">ํ™ˆ์œผ๋กœ</a>
        <a href="/teachers">๊ต์‚ฌ ๋ชฉ๋ก</a>
    </p>
    <form th:action="@{/teachers/add}" th:object="${teacher}" method="post">
        <p><label>์ด๋ฆ„: <input type="text" th:field="*{name}" required/></label></p>
        <p>
            <button type="submit">์ €์žฅํ•˜๊ธฐ</button>
            <a href="/teachers">์ทจ์†Œํ•˜๊ธฐ</a>
        </p>
    </form>
</body>
  • '/' ํ™ˆ์œผ๋กœ ๊ฐ€๋Š” ๋งํฌ, '/teachers' ๊ต์‚ฌ ๋ชฉ๋ก์œผ๋กœ ๊ฐ€๋Š” ๋งํฌ ์ถ”๊ฐ€
  • ํผ ํƒœ๊ทธ์—์„œ
    ํƒ€์ž„๋ฆฌํ”„๋ฅผ ํ™œ์šฉํ•ด์„œ th:object ๋กœ Model์˜ ${teacher} ์— ์ธํ’‹ ๋ฐ์ดํ„ฐ๋ฅผ ํ•„๋“œ *{name} ์œผ๋กœ ๋งคํ•‘ํ•ด์ค€๋‹ค.
  • <button type="submit">
    th:action="@{/teachers/add}" method="post" ์™€ ํ•จ๊ป˜ ๋™์ž‘
  • ๋‹ค์‹œ ๊ต์‚ฌ ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๋Š” ์ทจ์†Œํ•˜๊ธฐ ๋งํฌ ์ถ”๊ฐ€

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

<body>
<h1>๐Ÿง‘โ€๐Ÿซ ๊ต์‚ฌ ๋ชฉ๋ก</h1>
<p>
    <a href="/">๐Ÿ  ํ™ˆ์œผ๋กœ</a>
    <a href="/teachers/add">โž• ๊ต์‚ฌ ๋“ฑ๋ก</a>
</p>
</body>
  • teacher-form.html ์—์„œ th:action=@{/teachers/add} method="post" ์š”์ฒญํ–ˆ์„ ๋•Œ teacher-list๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์ž˜ ๋˜๋Š”์ง€ ํ™•์ธ

๐Ÿ” Retrieve Teacher

๐Ÿ—„๏ธ repository

  • ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋ฐ” ๊ฐ์ฒด๋กœ ๋ฐ”์ธ๋”ฉ ํ•˜๊ธฐ ์œ„ํ•œ RowMapper
    private final RowMapper<Teacher> mapper = (resultSet, rowNum) ->
            Teacher.builder()
                    .id(resultSet.getInt("id"))
                    .name(resultSet.getString("name"))
                    .build();

    public List<Teacher> findAll() {
        return jdbcTemplate.query("SELECT * FROM teacher ORDER BY name", mapper);
    }
  • findAll : jdbc sql๋กœ SELECT * FROM teacher ORDER BY name ๋กœ row๋ฅผ mapper์— ๋„˜๊ฒจ์ค€๋‹ค.

  • RowMapper ๊ฐ€ resultSet์œผ๋กœ ๋ฐ์ดํ„ฐ row๋ฅผ Teacher ๊ฐ์ฒด์— ๋ฐ”์ธ๋”ฉ

    ร— query๋กœ ๋„˜๊ฒจ๋ฐ›์€ row ์ˆ˜๋งŒํผ ๋ฐ˜๋ณต

  • builder ๋ฅผ ์“ฐ์ง€ ์•Š์œผ๋ฉด :

private final RowMapper<DailySales> dailySalesRowMapper = (resultSet, rowNum) ->
       new DailySales(
               resultSet.getDate("sale_date").toLocalDate(),
               resultSet.getBigDecimal("total_amount"),
               resultSet.getInt("order_count")
       );

๐Ÿ“ก controller

  • /teachers ๋กœ ๋“ค์–ด๊ฐ€๋ฉด Model์— teacherRepository.findAll()๋กœ ๋ฐ›์•„์˜จ List<Teacher>๋ฅผ ๋‹ด์•„ ํด๋ผ์ด์–ธํŠธ์— ๋ณด๋‚ธ๋‹ค.
@Controller
@RequestMapping("/teachers")
@RequiredArgsConstructor
public class TeacherController {
    private final TeacherRepository teacherRepository;

    @GetMapping
    public String list(Model model) {
        model.addAttribute("teachers", teacherRepository.findAll());
        return "teacher-list";
    }
}

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

<body>
<h1>๐Ÿง‘โ€๐Ÿซ ๊ต์‚ฌ ๋ชฉ๋ก</h1>
<p>
    <a href="/">๐Ÿ  ํ™ˆ์œผ๋กœ</a>
    <a href="/teachers/add">โž• ๊ต์‚ฌ ๋“ฑ๋ก</a>
</p>
<table>
    <thead>
    <tr>
        <td>ID</td>
        <td>์ด๋ฆ„</td>
        <td>์•ก์…˜</td>
    </tr>
    </thead>
    <tbody th:each="teacher: ${teachers}">
    <tr>
        <td th:text="${teacher.id}"></td>
        <td th:text="${teacher.name}"></td>
        <td>
            <a th:href="@{'/teachers/edit/' + ${teacher.id}}">์ˆ˜์ •</a>
        </td>
    </tr>
    </tbody>
</table>
</body>
  • <tbody th:each="teacher: ${teachers}">
    Model์—์„œ ๋ฐ›์•„์˜จ teachers (List<Teacher>)์—์„œ ํ•˜๋‚˜์”ฉ ๋ฐ›์•„ tr์— ๋งคํ•‘

โœ๏ธ Edit Teacher

๐Ÿ—„๏ธ repository

public Teacher findById(int id) {
    return jdbcTemplate.queryForObject(
    	"SELECT * FROM teacher WHERE id=?", 
        mapper, 
        id);
//        ํ•˜๋‚˜ ์ฐพ์„๋•Œ๋Š” queryForObject ์“ฐ๊ณ  ๋ฐ”์ธ๋”ฉ์€ ์„ธ๋ฒˆ์žฌ arg๋ถ€ํ„ฐ
}

public int <update(Teacher teacher) {
    return jdbcTemplate.update(
            "UPDATE teacher SET name = ? WHERE id = ?",
            teacher.getName(), 
            teacher.getId()
    );
}
  • findById : ํŽธ์ง‘ํ•  ๊ฐ์ฒด๋ฅผ db์—์„œ ์ฐพ๊ธฐ ์œ„ํ•œ id ์ธ๋ฑ์Šค ์ œ๊ณต
  • ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ๋„˜๊ฒจ์ฃผ๋Š” teacher ์—์„œ getName, getId ํ•ด์„œ ๋ฐ์ดํ„ฐ ๋ฎ์–ด์“ฐ๊ธฐ

๐Ÿ“ก controller

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

@PostMapping("/edit")
public String edit(@ModelAttribute Teacher teacher) {
    teacherRepository.update(teacher);
    return "redirect:/teachers";
}
  • editForm : ํด๋ผ์ด์–ธํŠธ๊ฐ€ /edit/{id} ๋กœ ๋“ค์–ด์˜ค๋ฉด findById๋กœ Teacher ๊ฐ์ฒด ๋ฐ›์•„์„œ Model๋กœ teacher-form.html์— ๋„˜๊ธฐ๊ฒŒ๋” ์ •์˜

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

<form th:action="${teacher.id} == null ? @{/teachers/add} : @{/teachers/edit}" th:object="${teacher}" method="post">
        <input type="hidden" th:field="*{id}">
        <p><label>์ด๋ฆ„: <input type="text" th:field="*{name}" required/></label></p>
        <p>
            <button type="submit">์ €์žฅํ•˜๊ธฐ</button>
            <a href="/teachers">์ทจ์†Œํ•˜๊ธฐ</a>
        </p>
    </form>
  • ์•„๊นŒ teacher-form ๊ต์‚ฌ ์ถ”๊ฐ€ ํผ ์žฌ์‚ฌ์šฉ ํ• ๊ฒƒ์ด๋ฏ€๋กœ ์‚ผํ•ญ์—ฐ์‚ฐ์ž๋ฅผ ์ด์šฉํ•ด์„œ action ์ˆ˜์ •ํ•ด์ค€๋‹ค.
  • th:object๋กœ Model ๋„˜๊ธธ์ค€๋น„
  • edit์„ ์œ„ํ•ด ์ธํ’‹ ํžˆ๋“ ์œผ๋กœ *{id} ํ•„๋“œ ๊ฐ’ ์ „๋‹ฌ
  • ์ธํ’‹์œผ๋กœ *{name}๋„ ์ „๋‹ฌ

๐Ÿ“ก controller

@PostMapping("/edit")
public String edit(@ModelAttribute Teacher teacher) {
    teacherRepository.update(teacher);
    return "redirect:/teachers";
}
  • edit : ํด๋ผ์ด์–ธํŠธ์—์„œ Model์— th:object="${teacher}" Teacher ๋„˜๊ธฐ๊ณ  ์žˆ์œผ๋ฏ€๋กœ @ModelAttribute๋กœ ๋ฐ›์•„์™€์„œ repository update

๐Ÿ—‘๏ธ Delete Teacher

๐Ÿ—„๏ธ repository

public int delete(int id) {
    return jdbcTemplate.update(
            "DELETE FROM teacher WHERE id = ?",
            id
    );
}
  • ๋ฐ์ดํ„ฐ ๋‚ด์šฉ์— ๊ด€๊ณ„์—†์ด id์— ๋งž๋Š” ๋ฐ์ดํ„ฐ ์‚ญ์ œ๋งŒ ํ•˜๋ฉด ๋˜๋ฏ€๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ id๋กœ delete ์ฟผ๋ฆฌ ์‹คํ–‰

๐Ÿ“ก controller

@GetMapping("/delete/{id}")
public String delete(@PathVariable int id) {
    teacherRepository.delete(id);
    return "redirect:/teachers";
}
  • db๋กœ ์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ ๊ฐ™์€๊ฑด ์—†์œผ๋ฏ€๋กœ (์ธ๋ฑ์Šค ์ œ์™ธ) Get ๋ฐฉ์‹์œผ๋กœ delete ์ฒ˜๋ฆฌ๋งŒ ํ•˜๊ณ  ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ํ•˜๋ฉด ์•Œ์•„์„œ teachers๋กœ ๋„˜์–ด๊ฐ€์„œ teacher-list.html ๋ฐ˜ํ™˜ํ•œ๋‹ค.

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

<a th:href="@{'/teachers/edit/' + ${teacher.id}}">์ˆ˜์ •</a>
            <a th:href="@{'/teachers/delete/' + ${teacher.id}}">์‚ญ์ œ</a>
  • ๊ฐ„๋‹จํžˆ ์ˆ˜์ • ์˜†์— ๋งํฌ ๋‹ฌ์•„์คฌ๋‹ค

profile
๐Ÿ—‚๏ธ hamstern

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