
타임리프와 JPA를 활용해서 데이터를 입력하고 검색하는 페이지를 만든다.
Point
자바 어플리케이션에서 관계형 데이터베이스를 사용하는
방식을 정의한 인터페이스 관련 API.
테이블(엔티티)과 테이블 간의 관계로
데이터를 저장하는 방식의 데이터베이스
- MySQL, 오라클, 마리아DB 등.
Hibernate : JPA의 구현체 (JPA는 인터페이스, Hibernate는 구현 클래스)
Spring Data JPA : JPA와 Hibernate를 사용하기 쉽게 만든 Spring 라이브러리.
Entity 클래스(DTO)를 구현하면 해당 클래스에서 지정한 테이블 이름 및 컬럼 이름으로
DB 테이블을 자동으로 생성하며, DB CRUD에 대한 메소드도 제공.
메소드 이름으로 SQL 쿼리문을 생성하는 방식을 사용한다.
spring.jpa.generate-ddl : true로 설정하면 해당 데이터를 근거로 서버 시작 시에 DDL문을 생성하여 DB에 적용.
DDL 생성 시 데이터베이스 고유의 기능을 사용하는지에 대한 유무 체크.
→ false로 설정.
spring.jpa.hibernate.ddl-auto : 'create table' 관련 설정.
spring.jpa.database-platform : 각 DBMS에 맞게 SQL을 생성하도록 도와주는 dialect(방언) 객체를 지정한다.
# DevTools setting
spring.devtools.livereload.enabled=true
spring.devtools.restart.enabled=true
spring.thymeleaf.cache=false
# static resource
spring.web.resources.static-locations=classpath:static/
# datasource setting
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/berrydb?serverTimezone=Asia/Seoul
#DB유저 id, 비밀번호
spring.datasource.username=buser
spring.datasource.password=12341234
# JPA setting
spring.jpa.database=mysql
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=update
# JPA log setting
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
logging.level.org.hibernate.type.descriptor.sql=trace
DB 테이블과 연계하기 위한 클래스.
DTO의 역할도 함께 처리할 수 있음.(따로 작성하는 경우가 일반적임)
DAO 역할을 하는 인터페이스.
이 인터페이스 내부에 다양한 작업을 위한 메소드를 작명 규칙에 맞게 작성한다.
@Entity //entity임을 선언하는 어노테이션(DB DDL 생성 시 활요)
@Table(name="jpatbl") //DB 테이블의 이름을 지정하는 어노테이션. 생략 시 클래스 이름으로 테이블 생성.
@Data //Lombok 어노테이션
public class JpaData {
@Id //필드를 테이블의 기본키로 설정하는 어노테이션
@GeneratedValue(strategy = GenerationType.IDENTITY) //자동으로 생성되는 키값에 대한 설정
private Long code;
@Column(name = "str_data", nullable = false, length = 50) //nullable=false : null을 허용하지 않는다.
private String strdata;
@Column(name = "int_data")
private int intdata;
@Column(name = "reg_date")
@CreationTimestamp //작성일 기준으로 db에 저장한다.
private Timestamp regdate;
}
jpatbl 테이블을 만들어주는 entity class
public interface JpaDataRepository extends JpaRepository<JpaData, Long> {
//DB CRUD(insert, update, delete, select 용 인터페이스)
//기본으로 전체 내용 삽입, 전체 내용 수정, 행 삭제
//전체 내용 검색 및 키 검색용 메소드를 제공.
List<JpaData> findByStrdata(String strdata);
//SELECT * FROM jpatbl WHERE str_data = 'abcd'
}
인터페이스로 작성하며 메소드를 이용해서 데이터를 조작한다.
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<h1>첫 페이지</h1>
<a th:href="@{writeForm}">[데이터입력]</a>
home페이지에서는 데이터 입력 클릭창만 보여주고 [데이터입력] 버튼 클릭스 writeForm 페이지로 이동한다.
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<h1>데이터 입력</h1>
<form th:action="@{dataProc}" method="post">
<input type="text" name="strdata"><br>
<input type="number" name="intdata"><br>
<input type="submit" value="Send">
</form>
writeForm 페이지에서는 데이터 입력 창을 보여주고 해당 데이터는 dataProc를 통해서 처리하도록 th:action 태그를 걸어준다.

//writeForm.html로 보내주는 컨트롤러 동작
@GetMapping("writeForm")
public String writeForm(){
log.info("writeForm()");
return "writeForm";
}
//서비스의 insertData 작업을 받아서 view로 결과를 내보낸다.
@PostMapping("dataProc")
public String dataProc(JpaData data){
log.info("dataProc()");
String view = jServ.insertData(data);
return view;
}
@Autowired
private JpaDataRepository jRepo;
public String insertData(JpaData data){
log.info("insertData()");
String view = null;
try{
jRepo.save(data);//insert/update
view = "redirect:/";
} catch (Exception e){
e.printStackTrace();
view = "redirect:writeForm";
}
return view;
}
JpaData를 data로 받아서 리포지토리로 넘겨 사용자가 입력한 데이터를 DB에 저장한다.
저장에 성공하면 redirect를 이용해서 메인 페이지로 이동하고, 실패 시에는 writeForm 화면을 유지한다.

input 입력창에 데이터를 입력 후 Send로 데이터를 전송하면

첫페이지로 이동하면서 데이터 목록에 방금 입력한 데이터와 함께 데이터 목록이 출력된다.
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<!-- 데이터 목록 -->
<h2>데이터 목록</h2>
<table border="1">
<thead>
<tr>
<th width="50">번호</th>
<th width="200">문자열</th>
<th width="100">숫자</th>
<th width="200">날짜와 시간</th>
</tr>
</thead>
<tbody>
<th:block th:if="${#lists.isEmpty(jList)}">
<tr><td colspan="4">데이터가 없습니다.</td></tr>
</th:block>
<th:block th:unless="${#lists.isEmpty(jList)}">
<th:block th:each="item:${jList}">
<tr>
<td th:text="${item.code}"></td>
<td th:text="${item.strdata}"></td>
<td th:text="${item.intdata}"></td>
<td th:text="${#dates.format(item.regdate,'yyyy-MM-dd HH:mm:ss')}"></td>
</tr>
</th:block>
</th:block>
</tbody>
</table>
DB에 저장된 데이터 목록을 가져오는 html소스
타임리프로 jList를 불러온다.
@GetMapping("/")
public ModelAndView home(){
log.info("home()");
mv = jServ.getList();
return mv;
}
서비스에서 getList 메소드 작업해서 ModelAndView로 가져오는 역할
@Autowired
private JpaDataRepository jRepo;
private ModelAndView mv;
public ModelAndView getList(){
log.info("getList()");
mv = new ModelAndView();
mv.setViewName("home");
//목록 추가 작업
List<JpaData> jList = jRepo.findAll();
//findAll() -> SELECT * FROM table
mv.addObject("jList", jList);
return mv;
}
데이터를 home.html로 반환하기 위해서 ModelAndView로 getList 메소드를 생성하고 리포지토리를 사용해서 JpaData 데이터를 jList로 반환한다.
만약 리스트가 없다면 데이터가 없습니다. 문자열을 내보낸다.

검색할 문자열을 input 창에 넣고 검색을 누르면

데이터 목록에서 검색한 결과값만 나타나는 것을 확인할 수 있다.
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<form th:action="@{search}" method="get">
<input type="text" name="keyword" placeholder="검색할 문자열을 입력하세요.">
<input type="submit" value="검색">
</form>
@GetMapping("search")
public ModelAndView search(String keyword){
log.info("search()");
mv = jServ.getData(keyword);
return mv;
}
컨트롤러는 search action태그를 받고 getData 서비스 처리로 넘겨주는 역할을 한다.
public ModelAndView getData(String keyword) {
log.info("getData()");
mv = new ModelAndView();
mv.setViewName("home");
List<JpaData> jList = jRepo.findByStrdata(keyword);
mv.addObject("jList", jList);
return mv;
}
검색 문자열을 keyword로 보내서 해당 문자열의 데이터만 보여지도록 한다.
2023.06.01 작성