💡  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