타임리프와 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 작성