
1. 화면보기


2. BoardController 에 index()
- Model 객체의 데이터를 model에 담음
내부에 Request가 담겨있음
- request에 담으면 알아서 버려지니까 용량 관리를 안해도 됨
- session에 담으면 안 버려져서 용량 관리를 해야 함
오래 기록 가능 - 여러 번 이동 후 불러올 때
package shop.mtcoding.blog.board;
import ch.qos.logback.core.model.Model;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@RequiredArgsConstructor
@Controller
public class BoardController {
private final BoardNativeRepository boardNativeRepository;
@GetMapping("/")
public String index(HttpServletRequest request) {
return "index";
}
@PostMapping("/board/save")
public String save(String title, String content, String username) { // DTO 없이 구현
boardNativeRepository.save(title, content, username);
return "redirect:/";
}
@GetMapping("/board/save-form")
public String saveForm() {
return "board/save-form";
}
@GetMapping("/board/{id}")
public String detail(@PathVariable Integer id) { // Integer : 없으면 null, int : 0
return "board/detail";
}
}
3. BoardNativeRepository에 findAll() 만들기
3-1. 목록에 뿌려질 데이터 조회하기
package shop.mtcoding.blog.board;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.transaction.Transactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import java.util.List;
// 나중에 안쓰고 새로운 레파지토리를 쓰고 이건 버릴거임
@RequiredArgsConstructor
@Repository
public class BoardNativeRepository {
private final EntityManager em;
public List<Board> findAll() {
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class); // join은 DTO로 받아야
return (List<Board>) query.getResultList(); // 캐스팅 해주기
}
@Transactional
public void save(String title, String content, String username) {
Query query = em.createNativeQuery("insert into board_tb (title, content, username, created_at) values (?,?,?,now())");
query.setParameter(1, title);
query.setParameter(2, content);
query.setParameter(3, username);
query.executeUpdate();
}
}
3-2. 단위 테스트 하기
- 검색해서 찾기
ctrl + R

- 크기 확인하기
package shop.mtcoding.blog.Board;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import shop.mtcoding.blog.board.Board;
import shop.mtcoding.blog.board.BoardNativeRepository;
import java.util.List;
@Import(BoardNativeRepository.class)
@DataJpaTest
public class BoardNativeRepositoryTest{
@Autowired // DI
private BoardNativeRepository boardNativeRepository;
@Test
public void findAll_test(){
//given - 지금은 넣을게 없음
//when
List<Board> boardList = boardNativeRepository.findAll();
//then
System.out.println("findAll_test/size : " + boardList.size());
}
}

- 크기와 사용자 확인하기
package shop.mtcoding.blog.Board;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import shop.mtcoding.blog.board.Board;
import shop.mtcoding.blog.board.BoardNativeRepository;
import java.util.List;
@Import(BoardNativeRepository.class)
@DataJpaTest
public class BoardNativeRepositoryTest{
@Autowired // DI
private BoardNativeRepository boardNativeRepository;
@Test
public void findAll_test(){
//given - 지금은 넣을게 없음
//when
List<Board> boardList = boardNativeRepository.findAll();
//then
System.out.println("findAll_test/size : " + boardList.size());
System.out.println("findAll_test/username : " + boardList.get(2).getUsername());
}
}

3-3. Assertions 사용하기
package shop.mtcoding.blog.Board;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import shop.mtcoding.blog.board.Board;
import shop.mtcoding.blog.board.BoardNativeRepository;
import java.util.List;
@Import(BoardNativeRepository.class)
@DataJpaTest
public class BoardNativeRepositoryTest{
@Autowired // DI
private BoardNativeRepository boardNativeRepository;
@Test
public void findAll_test(){
//given - 지금은 넣을게 없음
//when
List<Board> boardList = boardNativeRepository.findAll();
//then
System.out.println("findAll_test/size : " + boardList.size());
System.out.println("findAll_test/username : " + boardList.get(2).getUsername());
//org.assertj.core.api
Assertions.assertThat(boardList.size()).isEqualTo(4);
Assertions.assertThat(boardList.get(2).getUsername()).isEqualTo("ssar");
}
}
- 오류가 없으면 결과 값만 출력

- 오류가 나면 알려줌

4. BoardController index()에 추가하기
- 서버가 내부적으로 index를 요청
외부에서는 다이렉트 접근이 안됨
- 요청이 내부적으로 2번 일어나지만 데이터가 들어있는 request는 1개임
내부적으로 request dispatch(내부 데이터 유지)가 일어남
package shop.mtcoding.blog.board;
import ch.qos.logback.core.model.Model;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import java.util.List;
@RequiredArgsConstructor
@Controller
public class BoardController {
private final BoardNativeRepository boardNativeRepository;
@GetMapping("/")
public String index(HttpServletRequest request) {
// 조회하기
List<Board> boardList = boardNativeRepository.findAll();
// 가방에 담기
request.setAttribute("boardList", boardList);
return "index"; // 서버가 내부적으로 index를 요청 - 외부에서는 다이렉트 접근이 안됨
}
@PostMapping("/board/save")
public String save(String title, String content, String username) { // DTO 없이 구현
boardNativeRepository.save(title, content, username);
return "redirect:/";
}
@GetMapping("/board/save-form")
public String saveForm() {
return "board/save-form";
}
@GetMapping("/board/{id}")
public String detail(@PathVariable Integer id) { // Integer : 없으면 null, int : 0
return "board/detail";
}
}
5. 화면에 뿌리기
5-1. 정보 가져오기
- 화면에 보이는 정보만 가지고 와야 함
Board가 아니라 BoardDTO를 줘야 함
새로운 클래스를 만들어서 옮겨담는 것 / 객체 복사
{{> /layout/header}}
<div class="container p-5">
{{#boardList}} <!--for문 돌리기-->
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title mb-3">{{title}}</h4>
<a href="/board/{{id}}" class="btn btn-primary">상세보기</a>
</div>
</div>
{{/boardList}}
<ul class="pagination d-flex justify-content-center">
<li class="page-item disabled"><a class="page-link" href="#">Previous</a></li>
<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>
</div>
{{> /layout/footer}}

5-2. 날짜, 시간 추가하기
{{> /layout/header}}
<div class="container p-5">
{{#boardList}} <!--for문 돌리기-->
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title mb-3">{{title}}</h4>
<div class="mb-3">{{createdAt}}</div> <!--날짜 시간 추가하기-->
<a href="/board/{{id}}" class="btn btn-primary">상세보기</a>
</div>
</div>
{{/boardList}}
<ul class="pagination d-flex justify-content-center">
<li class="page-item disabled"><a class="page-link" href="#">Previous</a></li>
<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>
</div>
{{> /layout/footer}}

5-3. 날짜, 시간 커스터마이징하기
- 라이브러리 추가하기
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.0'
- 메서드 찾아서 테스트하기
package shop.mtcoding.blog.util;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.junit.jupiter.api.Test;
import java.sql.Timestamp;
import java.util.Date;
public class DateTest {
@Test
public void format_test(){
Timestamp currentTimestamp = new Timestamp(System.currentTimeMillis());
// Timestamp를 Date 객체로 변환
Date currentDate = new Date(currentTimestamp.getTime());
// 원하는 포맷으로 날짜를 변환
String formattedDate = DateFormatUtils.format(currentDate, "yyyy-MM-dd HH:mm");
// 포맷된 날짜 출력
System.out.println("Formatted Date: " + formattedDate);
}
}
- 테스트 된 코드 재사용 가능하게 만들기
package shop.mtcoding.blog.util;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.sql.Timestamp;
import java.util.Date;
public class MyDateUtil {
public static String timestampFormat(Timestamp boardDate){ // 재사용 가능함
Date currentDate = new Date(boardDate.getTime());
return DateFormatUtils.format(currentDate, "yyyy-MM-dd HH:mm");
}
}
- 단위 테스트하기
package shop.mtcoding.blog.util;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.junit.jupiter.api.Test;
import java.sql.Timestamp;
import java.util.Date;
public class DateTest {
@Test
public void timestampFormat(){
//given
Timestamp currentTimestamp = new Timestamp(System.currentTimeMillis());
//when
String createdAt = MyDateUtil.timestampFormat(currentTimestamp);
//then
System.out.println("timestampFormat_test: " + createdAt);
}
@Test
public void format_test(){
Timestamp currentTimestamp = new Timestamp(System.currentTimeMillis());
// Timestamp를 Date 객체로 변환
Date currentDate = new Date(currentTimestamp.getTime());
// 원하는 포맷으로 날짜를 변환
String formattedDate = DateFormatUtils.format(currentDate, "yyyy-MM-dd HH:mm");
// 포맷된 날짜 출력
System.out.println("Formatted Date: " + formattedDate);
}
}

5-4. Board 테이블에 getBoardDate() 추가하기
- 원래는 DTO에 넣어야 함
package shop.mtcoding.blog.board;
import jakarta.persistence.*;
import lombok.Data;
import shop.mtcoding.blog.util.MyDateUtil;
import java.sql.Timestamp;
@Data // 변경되는 데이터에만 setter가 필요함
@Table(name = "board_tb")
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String title;
private String content;
private String username;
private Timestamp createdAt;
public String getBoardDate(){
return MyDateUtil.timestampFormat(createdAt);
}
}
- view에 boardDate 로 변경하기
{{> /layout/header}}
<div class="container p-5">
{{#boardList}} <!--for문 돌리기-->
<div class="card mb-3">
<div class="card-body">
<h4 class="card-title mb-3">{{title}}</h4>
<div class="mb-3">{{boardDate}}</div> <!--날짜 시간 추가하기-->
<a href="/board/{{id}}" class="btn btn-primary">상세보기</a>
</div>
</div>
{{/boardList}}
<ul class="pagination d-flex justify-content-center">
<li class="page-item disabled"><a class="page-link" href="#">Previous</a></li>
<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>
</div>
{{> /layout/footer}}

Share article