๐Ÿ’ก  DTO : ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์„œ๋น„์Šค๋กœ, ํ˜น์€ ์„œ๋น„์Šค์—์„œ ์ปจํŠธ๋กค๋Ÿฌ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›์„ ๋•Œ ์‚ฌ์šฉ
       VO : ์„œ๋น„์Šค๋Š” DAO์™€ ๋ฐ์ดํ„ฐ ์ฃผ๊ณ  ๋ฐ›์„ ๋•Œ๋Š” VO๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋น„์Šค์—์„œ DTO ↔ VO ์ž‘์—…์ด ํ•„์š”
  • DTO : ์ปจํŠธ๋กค๋Ÿฌ ↔ ์„œ๋น„์Šค
  • VO : ์„œ๋น„์Šค ↔ DAO

1.  ์ฝ˜์†”์ฐฝ์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—… 

CREATE TABLE `tbl_board` (
    `no` int auto_increment primary key,  
    `title` varchar(100) not null,     // ์ œ๋ชฉ
    `content` text not null ,          // ๋‚ด์šฉ
    `writer` varchar(50) not null ,    // ์ž‘์„ฑ์ž
    `passwd` varchar(100) not null ,   // ๋น„๋ฐ€๋ฒˆํ˜ธ
    `addDate` datetime,                // ์ž‘์„ฑ๋‚ ์งœ
    `hit` int default 0                // ์กฐํšŒ์ˆ˜
);

 


 

2.  BoardVO ์ž‘์„ฑ 

ํ…Œ์ด๋ธ”์— ์ €์žฅํ•  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๊ฑฐ๋‚˜, ํ…Œ์ด๋ธ”์—์„œ ๋“ค๊ณ ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋Š” ์šฉ๋„

์ฃผ๋กœ DAO (๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฒ˜๋ฆฌํ•˜๋Š” ํŒŒํŠธ) ์—์„œ ์‚ฌ์šฉ

@Getter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BoardVO {

    private Integer no;
    private String title;      // ์ œ๋ชฉ
    private String content;    // ๋‚ด์šฉ
    private String writer;     // ์ž‘์„ฑ์ž
    private String passwd;     // ๋น„๋ฐ€๋ฒˆํ˜ธ
    private LocalDate addDate; // ์ž‘์„ฑ์ผ
    private Integer hit;       // ์กฐํšŒ์ˆ˜

}

 


3.  VO๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•˜๋Š” ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ

 ์ž‘์„ฑ ์ˆœ์„œ

 

  1)  BoardMapper ์ธํ„ฐํŽ˜์ด์Šค ์ž‘์„ฑ - ๊ฐ์ฒด ๋ฐ›์•„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ, ์ˆ˜์ •, ์‚ญ์ œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฉ”์†Œ๋“œ ์ž‘์„ฑ

  2) BoardMapperxml ์ž‘์„ฑ - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ๋ฌธ ์ž‘์„ฑ

  3)  BoardMapperTest ํด๋ž˜์Šค ์ž‘์„ฑ - ์‹คํ–‰ ํ…Œ์ŠคํŠธ

 

 

public interface BoardMapper {
    void insert(BoardVO boardVO); // DB ์ €์žฅํ•˜๋Š” ๋ฉ”์†Œ๋“œ
}

 

<mapper namespace="com.example.spring_ex_01_2404.mapper.BoardMapper">
    <insert id="insert">
        INSERT INTO tbl_board (title, content, writer, passwd, addDate)
        VALUES (#{title}, #{content}, #{writer}, SHA2(#{passwd},256), now())
    </insert>
</mapper>

 

  โœ“  mysql๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™” ํ•  ๊ฒฝ์šฐ SHA2(์ž…๋ ฅ๊ฐ’, 256) ํ•จ์ˆ˜ ์‚ฌ์šฉ

  โœ“ addDate๋Š” ๊ธ€ ์ž‘์„ฑ ์‹œ๊ฐ„์ด ๋“ค์–ด๊ฐ€๋‹ˆ now() ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉ

  โœ“ hit๋Š” ์ž‘์„ฑ์‹œ์—๋Š” 0์ด๋‹ˆ ์ปฌ๋Ÿผ์˜ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉ

@Log4j2
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/root-context.xml")
class BoardMapperTest {
    @Autowired(required = false)
    private BoardMapper boardMapper;

    @Test
    public void testInsert() {
        BoardVO boardVO = BoardVO.builder() // ๋นŒ๋”๋ฅผ ์ด์šฉํ•ด์„œ BoardVO ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑ
                .title("์Šคํ”„๋ง ํ…Œ์ŠคํŠธ")
                .content("์Šคํ”„๋ง ํ…Œ์ŠคํŠธ ์ค‘...")
                .writer("river")
                .passwd("1234")
                .addDate(now())
                .build();
        boardMapper.insert(boardVO);
    }
}
02:34:06 DEBUG [com.example.spring_ex_01_2404.mapper.BoardMapper.insert] ==> Preparing: INSERT INTO tbl_board (title, content, writer, passwd, addDate) VALUES (?, ?, ?, SHA2(?,256), now())
02:34:06 DEBUG [com.example.spring_ex_01_2404.mapper.BoardMapper.insert] ==> Parameters: ์Šคํ”„๋ง ํ…Œ์ŠคํŠธ(String), ์Šคํ”„๋ง ํ…Œ์ŠคํŠธ ์ค‘...(String), river(String), 1234(String)
02:34:06 DEBUG [com.example.spring_ex_01_2404.mapper.BoardMapper.insert] <== Updates: 1

 


4.  Service ์ž‘์—…

BoardDTO → BoardService → BoardServiceImpl → ํ…Œ์ŠคํŠธ ์ฝ”๋“œ
@ToString
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BoardDTO {
    private Integer no;
    private String title;
    private String content;
    private String writer;
    private String passwd;
    private LocalDate addDate;
    private Integer hit;
}

 

public interface BoardService {

    void register(BoardDTO boardDTO);
}

 

@Log4j2
@Service
@RequiredArgsConstructor // ์ƒ์„ฑ์ž ๊ฐ์ฒด ์ฃผ์ž…. private final๋กœ ์„ ์–ธ๋œ ์ฐธ์กฐ๋ณ€์ˆ˜์— ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜๋Š” ์ƒ์„ฑ์ž ์ž‘์„ฑ.
public class BoardServiceImpl implements BoardService{
    private final BoardMapper boardMapper;
    private final ModelMapper modelMapper;

    @Override
    public void register(BoardDTO boardDTO) {
        log.info(boardDTO);
        BoardVO boardVO = modelMapper.map(boardDTO, BoardVO.class);
        log.info(boardVO);
        boardMapper.insert(boardVO);
    }
}

 

@Log4j2
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/root-context.xml")
class BoardServiceImplTest {
    @Autowired
    private BoardService boardService;

    @Test
    public void testRegister() {
        BoardDTO boardDTO = BoardDTO.builder()
                .title("service test")
                .content("service test...")
                .writer("user")
                .passwd("12345")
                .addDate(LocalDate.now())
                .build();
        boardService.register(boardDTO);
    }
}
03:23:33 INFO [com.example.spring_ex_01_2404.service.BoardServiceImpl] BoardDTO(no=null, title=service test, content=service test..., writer=user, passwd=12345, addDate=2024-05-01, hit=null)
03:23:33 INFO [com.example.spring_ex_01_2404.service.BoardServiceImpl] BoardVO(no=null, title=service test, content=service test..., writer=user, passwd=12345, addDate=2024-05-01, hit=null)
03:23:33 DEBUG [com.example.spring_ex_01_2404.mapper.BoardMapper.insert] ==> Preparing: INSERT INTO tbl_board (title, content, writer, passwd, addDate) VALUES (?, ?, ?, SHA2(?,256), now())
03:23:33 DEBUG [com.example.spring_ex_01_2404.mapper.BoardMapper.insert] ==> Parameters: service test(String), service test...(String), user(String), 12345(String)
03:23:33 DEBUG [com.example.spring_ex_01_2404.mapper.BoardMapper.insert] <== Updates: 1

 


 

5.  ๋“ฑ๋กํŽ˜์ด์ง€ ์ž‘์„ฑ

  • /board/add๋กœ ์ ‘๊ทผํ•  ๊ฒฝ์šฐ ๋“ฑ๋ก ํŽ˜์ด์ง€ ์ถœ๋ ฅ
  • ๋“ฑ๋กํŽ˜์ด์ง€์—์„œ ์ž…๋ ฅ ํ›„ submit์„ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ธ€์ด ๋“ฑ๋ก
์ž‘์—…์ˆœ์„œ 
  • BoardController ์ž‘์„ฑ
  • get์œผ๋กœ /board/add์— ์ ‘๊ทผํ•  ๊ฒฝ์šฐ ์‹คํ–‰ํ•  ๋ฉ”์„œ๋“œ ์ž‘์„ฑ
  • /board/add๋กœ ์ •์ƒ์ ์œผ๋กœ ์ ‘๊ทผ๋˜๋Š”์ง€ ํ™•์ธ
  • webapp์— add.jsp ์ฝ”๋”ฉ
  • controller์— post๋กœ /board/add์— ์ ‘๊ทผํ•  ๊ฒฝ์šฐ ์‹คํ–‰ํ•  ๋ฉ”์„œ๋“œ ์ž‘์„ฑ
  • ํ…Œ์ŠคํŠธ ํ›„ ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ œ๋Œ€๋กœ ์ „๋‹ฌ๋˜๋Š”์ง€ ํ™•์ธ
  • addPost()๋ฅผ ์ˆ˜์ •ํ•ด์„œ ์„œ๋น„์Šค๋กœ ์—ฐ๊ฒฐ
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ ํ™•์ธ
  • addPost()๋ฅผ ์ˆ˜์ •ํ•ด์„œ /board/list ์ด๋™ ํ™•์ธ
@Log4j2
@Controller
@RequestMapping("/board")
@RequiredArgsConstructor
public class BoardController {
    private final BoardService boardService;

    @GetMapping("/add")
    public void add() {
        log.info("add board...");
    }

    @PostMapping("/add")
    public String addPost(@Valid BoardDTO boardDTO, BindingResult bindingResult, RedirectAttributes redirectAttributes) {
        log.info("board addPost()...");

        if (bindingResult.hasErrors()) {
            log.info("has error...");
            redirectAttributes.addFlashAttribute("errors", bindingResult.getAllErrors());
            return "redirect:/board/add";
        }

        log.info(boardDTO);
        boardService.register(boardDTO);

        return "redirect:/board/list";

    }
 }

 

 <form  method="post">
    <div class="input mb-3">
        <span class="input-group-text">Title</span><br>
        <input type="text" name="title" placeholder="Title"><br><br>
    </div>
    <div class="input mb-3">
        <span class="input-group-text">Content</span><br>
        <textarea name="content" cols="60" rows="18"></textarea><br><br>
    </div>
    <div class="input mb-3">
        <span class="input-group-text">Writer</span><br>
        <input type="text" name="writer" placeholder="Writer"><br><br>
    </div>
    <div class="input mb-3">
        <span class="input-group-text">Password</span><br>
        <input type="password" name="passwd" placeholder="๋น„๋ฐ€๋ฒˆํ˜ธ"><br><br>
    </div>
    <div class="float-end">
        <button type="submit" name="submitBtn">Submit</button>
    </div>
</form>

 

 


 

6.  ๋ชฉ๋กํŽ˜์ด์ง€

  • DAO์— ๋ชฉ๋ก์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” selectAll() ๋ฉ”์„œ๋“œ ์ž‘์„ฑ
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ํ›„ ํ…Œ์ŠคํŠธ
  • Service ์ž‘์—…
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ ํ›„ ํ…Œ์ŠคํŠธ
  • ์ปจํŠธ๋กค๋Ÿฌ์— /board/list ๊ฒฝ๋กœ์™€ ๋งคํ•‘์„ ํ•œ list() ์ž‘์„ฑ
  • list.jsp ์ž‘์„ฑ
public interface BoardMapper {

    void insert(BoardVO boardVO); // DB ์ €์žฅํ•˜๋Š” ๋ฉ”์†Œ๋“œ

    List<BoardVO> selectAll(); // DB์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” ๋ฆฌ์ŠคํŠธ ๋ชฉ๋ก
}
    <select id="selectAll" resultType="com.example.spring_ex_01_2404.domain.BoardVO">
        SELECT * FROM tbl_board ORDER BY no DESC
    </select>
    @Test
    public void selectAll() {
        List<BoardVO> boardVOList = boardMapper.selectAll();
        for(BoardVO boardVO : boardVOList) {
            log.info(boardVO);
        }
    }
public interface BoardService {

    void register(BoardDTO boardDTO);

    List<BoardDTO> getAll();

}
    @Override
    public List<BoardDTO> getAll() {
        List<BoardVO> voList = boardMapper.selectAll(); // dao์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋“ค๊ณ ์˜จ VO๋ฆฌ์ŠคํŠธ๋ฅผ ๋ฆฌํ„ด
        List<BoardDTO> dtoList = new ArrayList<>();
        for (BoardVO boardVO: voList) {
            // ๊ฐœ๋ณ„ VO๋ฅผ DTO๋กœ ๋ณ€ํ™˜.
            BoardDTO boardDTO = modelMapper.map(boardVO, BoardDTO.class);
            dtoList.add(boardDTO); // DTO๋ฆฌ์ŠคํŠธ์— ์ €์žฅ.
        }
        return dtoList;
    }
  @Test
    public void getAll() {
        List<BoardDTO> boardDTOList = boardService.getAll();
        for (BoardDTO boardDTO : boardDTOList) {
            log.info(boardDTO);
        }
    }
  @RequestMapping("/list")
    public void list(Model model) {
        log.info("todo list...");
        model.addAttribute("dtoList", boardService.getAll());
    }
<div class="card">
    <div class="card-header">Board List</div>

        <div class="card-body">
            <table class="table">
                <thead>
                    <tr>
                        <th scope="col">No</th>
                        <th scope="col">Title</th>
                        <th scope="col">Writer</th>
                        <th scope="col">Date</th>
                    </tr>
                </thead>

                <tbody>
                <c:forEach var="dto" items="${dtoList}">
                    <tr>
                         <th scope="row">${dto.no}</th>
                         <td>${dto.title}</td>
                         <td>${dto.writer}</td>
                         <td>${dto.addDate}</td>
                    </tr>
                </c:forEach>
                </tbody>
            </table>
        </div>
    </div>
</div>

 


7.  ์กฐํšŒ

๋ฆฌ์ŠคํŠธ์—์„œ ํด๋ฆญ์„ ํ•˜๋ฉด ํ•ด๋‹น ๊ธ€์„ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€ ๊ตฌํ˜„

  • DAO์— ๊ฒŒ์‹œ๋ฌผ์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” selectOne() ๋ฉ”์„œ๋“œ ์ž‘์„ฑ
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ  ํ›„ ํ…Œ์ŠคํŠธ
  • Service ์ž‘์—…
  • ์ปจํŠธ๋กค๋Ÿฌ์— /board/read ๊ฒฝ๋กœ์™€ ๋งคํ•‘์„ ํ•œ read() ์ž‘์„ฑ
  • read.jsp ์ž‘์„ฑ
  • updatehit ์ถ”๊ฐ€ (์กฐํšŒ์ˆ˜ ์ฆ๊ฐ€)
public interface BoardMapper {

    void insert(BoardVO boardVO); // DB ์ €์žฅํ•˜๋Š” ๋ฉ”์†Œ๋“œ

    List<BoardVO> selectAll();

    BoardVO selectOne(Integer no); // ์กฐํšŒ
    
    void updateHit(Integer no); // ์กฐํšŒ์ˆ˜ ์ฆ๊ฐ€
 
}
    <select id="selectOne" resultType="com.example.spring_ex_01_2404.domain.BoardVO">
        SELECT * FROM tbl_board WHERE no = #{no}
    </select>
    
    <update id="updateHit">
        UPDATE tbl_board SET hit = hit + 1 where no = #{no}
    </update>
    @Test
    public void selectOne() {
        BoardVO boardVO = boardMapper.selectOne(1);
        log.info(boardVO);
    }
11:46:50 DEBUG [com.example.spring_ex_01_2404.mapper.BoardMapper.selectOne] ==> Preparing: SELECT * FROM tbl_board WHERE no = ?
11:46:50 DEBUG [com.example.spring_ex_01_2404.mapper.BoardMapper.selectOne] ==> Parameters: 1(Integer)
11:46:50 TRACE [com.example.spring_ex_01_2404.mapper.BoardMapper.selectOne] <== Columns: no, title, content, writer, passwd, addDate, hit
11:46:50 TRACE [com.example.spring_ex_01_2404.mapper.BoardMapper.selectOne] <== Row: 1, ์Šคํ”„๋ง ํ…Œ์ŠคํŠธ, <<BLOB>>, river, 1234, 2024-05-01 00:00:00, 1
11:46:50 DEBUG [com.example.spring_ex_01_2404.mapper.BoardMapper.selectOne] <== Total: 1

 

public interface BoardService {

    void register(BoardDTO boardDTO);

    List<BoardDTO> getAll();

    BoardDTO getOne(Integer no);
}
    @Override
    public BoardDTO getOne(Integer no) {
        boardMapper.updateHit(no);
        BoardVO boardVO = boardMapper.selectOne(no);
        BoardDTO boardDTO = modelMapper.map(boardVO, BoardDTO.class);
        return boardDTO;
    }

 

 @GetMapping("/read")
    public void read(Integer no, Model model) {
        BoardDTO boardDTO = boardService.getOne(no);
        log.info(boardDTO);
        model.addAttribute("dto", boardDTO);
    }

 

<div class="card-body">
    <div class="input-group">
        <span class="input-group-text">No</span>
        <input type="text" name="tno" class="form-control" value="${dto.no}" readonly>
    </div> <br>
    <div class="input-group">
        <span class="input-group-text">Title</span>
        <input type="text" name="title" class="form-control" value="${dto.title}" readonly>
    </div><br>
    <div class="input-group">
       <span class="input-group-text">Content</span>
       <textarea name="title" class="form-control" readonly>${dto.content}</textarea>
    </div><br>
    <div class="input-group">
        <span class="input-group-text">Writer</span>
        <input type="text" name="writer" class="form-control" value="${dto.writer}" readonly>
    </div><br>
    <div class="input-group">
        <span class="input-group-text">Date</span>
        <input type="date" name="dueDate" class="form-control" value="${dto.addDate}" readonly>
    </div><br>
    <div class="input-group">
        <span class="input-group-text">Hit</span>
        <input type="text" name="writer" class="form-control" value="${dto.hit}" readonly>
    </div><br>
    <div class="my-4">
        <div class="float-end">
            <button type="submit" class="btn btn-primary">Modify</button>
            <button type="reset" class="btn btn-secondary">List</button>
        </div>
    </div>

    <script>
        document.querySelector('.btn-primary').addEventListener('click', function (e) {
            self.location = `/board/modify?no=${dto.no}&${boardDTO.link}`;
        }, false);
        document.querySelector('.btn-secondary').addEventListener('click', function (e) {
            self.location = "/board/list?${boardDTO.link}";
        }, false);
    </script>
</div>

 

 

 

 

 

 

 

 

[ ๋‚ด์šฉ ์ฐธ๊ณ  : IT ํ•™์› ๊ฐ•์˜ ]

+ Recent posts