MapleStory Finger Point

๐ŸŸค JAVA/๐ŸŸค Spring Boot

[SpringBoot] JPA

HYEJU01 2024. 8. 26. 22:05

โ—ˆ JPA ๋ž€?

JPA(Java Persistence API)๋Š” ์ž๋ฐ”(Java) ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋Š” ํ‘œ์ค€ API์ž…๋‹ˆ๋‹ค. JPA๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‚ฌ์ด์˜ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์„ค๊ณ„๋œ ORM(Object-Relational Mapping) ๊ธฐ์ˆ ์˜ ํ•œ ์ข…๋ฅ˜์ž…๋‹ˆ๋‹ค.

JPA์˜ ์ฃผ์š” ๊ฐœ๋…

  1. ORM(Object-Relational Mapping): ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์ธ ์ž๋ฐ”์™€ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”์„ ๋งคํ•‘ํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ„์˜ ๋ฐ์ดํ„ฐ ๋ณ€ํ™˜์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. Entity: JPA์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๊ณผ ๋งคํ•‘๋˜๋Š” ์ž๋ฐ” ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ด ํด๋ž˜์Šค๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์˜ ํ–‰์„ ํ‘œํ˜„ํ•˜๋ฉฐ, ๊ฐ ํ•„๋“œ๋Š” ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ์— ๋งคํ•‘๋ฉ๋‹ˆ๋‹ค.
  3. Persistence Context: ์—”ํ‹ฐํ‹ฐ์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ™˜๊ฒฝ์ž…๋‹ˆ๋‹ค. Persistence Context๋Š” ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†์„ฑ ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๊ณ , ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๋™๊ธฐํ™”ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
  4. EntityManager: ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ƒ์„ฑ, ์ˆ˜์ •, ์‚ญ์ œ, ์กฐํšŒ ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” JPA์˜ ํ•ต์‹ฌ ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ์ œ์–ดํ•˜๊ณ , Persistence Context๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  5. JPQL(Java Persistence Query Language): JPA์—์„œ ์ œ๊ณตํ•˜๋Š” SQL๊ณผ ์œ ์‚ฌํ•œ ๊ฐ์ฒด ์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด์ž…๋‹ˆ๋‹ค. ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, SQL์— ๋น„ํ•ด ๋” ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ด๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…๋ฆฝ์ ์ž…๋‹ˆ๋‹ค.

JPA์˜ ์žฅ์ 

  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…๋ฆฝ์„ฑ: JPA๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ข…์†์ ์ด์ง€ ์•Š์€ ์ฝ”๋“œ ์ž‘์„ฑ์ด ๊ฐ€๋Šฅํ•˜์—ฌ, ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ข…์†๋˜์ง€ ์•Š๊ณ  ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ„์˜ ์ „ํ™˜์ด ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.
  • ์ƒ์‚ฐ์„ฑ ํ–ฅ์ƒ: SQL์„ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ , ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.
  • ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด์„ฑ: ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋กœ์ง์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ๊ฐœ์„ ๋ฉ๋‹ˆ๋‹ค.
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”: 1์ฐจ ์บ์‹œ, ์ง€์—ฐ ๋กœ๋”ฉ(Lazy Loading) ๋“ฑ ๋‹ค์–‘ํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

JPA์™€ ๊ด€๋ จ๋œ ๊ธฐ์ˆ 

JPA๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์˜ ํ‘œ์ค€ API๋กœ, ์ด๋ฅผ ๊ตฌํ˜„ํ•œ ์—ฌ๋Ÿฌ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ๊ตฌํ˜„์ฒด๋กœ๋Š” Hibernate, EclipseLink, DataNucleus ๋“ฑ์ด ์žˆ์œผ๋ฉฐ, Spring Data JPA๋Š” ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์™€ JPA๋ฅผ ํ†ตํ•ฉํ•ด ๋ณด๋‹ค ๊ฐ„ํŽธํ•˜๊ฒŒ JPA๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

๊ฒฐ๋ก 

JPA๋Š” ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ๋‹จ์ˆœํ™”ํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋…๋ฆฝ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ORM ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


 

 

 


 

package com.example.jpa.memo.repository;
import com.example.jpa.entity.MemberMemoDTO;
import com.example.jpa.entity.Memo;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
public interface MemoRepository extends JpaRepository<Memo, Long>, //์—”ํ‹ฐํ‹ฐํƒ€์ž…, ID์— ๋Œ€ํ•œ ํƒ€์ž…
MemoCustomRepository, //์ปค์Šคํ…€๋ ˆํฌ์ง€ํ† ๋ฆฌ
QuerydslPredicateExecutor<Memo> { //์ฟผ๋ฆฌDSL์—์„œ ์ œ๊ณต๋˜๋Š” ๋ช‡๋ช‡ ํ•จ์ˆ˜๋“ค์„ ์ œ๊ณตํ•ด์ฃผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค
//JpaRepository๋กœ ๋ถ€ํ„ฐ, ๋ช‡๊ฐœ์˜ ์ถ”์ƒ๋ฉ”์„œ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์†๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
//์ฟผ๋ฆฌ๋ฉ”์„œ๋“œ
Memo findByWriterAndText(String writer, String text);
List<Memo> findByMnoLessThan(Long mno);
// SELECT * FROM MEMO WHERE MNO = 11;
Memo findByMno(Long mno);
// SELECT * FROM MEMO WHERE MNO BETWEEN 10 AND 20;
List<Memo> findByMnoBetween(Long start, Long end);
// SELECT * FROM MEMO WHERE WRITER LIKE '%10%';
List<Memo> findByWriterLike(String str);
// SELECT * FROM MEMO WHERE WRITER = 'example1' ORDER BY WRITER DESC;
List<Memo> findByWriterOrderByWriterDesc(String writer);
// SELECT * FROM MEMO WHERE MNO IN (10,20,30,40,50);
List<Memo> findByMnoIn(List<Long> list);
//์ฟผ๋ฆฌ๋ฉ”์„œ๋“œ์˜ ๋งˆ์ง€๋ง‰ ๋งค๊ฐœ๋ณ€์ˆ˜์— Pageable์„ ์ฃผ๋ฉด, ํŽ˜์ด์ง•์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
List<Memo> findByMnoLessThanEqual(Long mno, Pageable pageable);
//////////////////////////////////////////////////////////////
//JPQL - SQL๊ณผ ๋น„์Šทํ•˜๋‚˜, ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ sql๋ฌธ์„ ์ž‘์„ฑ
//select, update, delete๋Š” ์ œ๊ณต๋˜๋Š”๋ฐ, insert๋Š” ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
//1. ํ…Œ์ด๋ธ”๋ช…์ด ์•„๋‹ˆ๋ผ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์‚ฌ์šฉ๋จ
//2. ์†์„ฑ(ํ•„๋“œ)์€ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ์ „๋ถ€ ๊ตฌ๋ถ„
//3. ๋ณ„์นญ์€ ํ•„์ˆ˜
//4. SQLํ‚ค์›Œ๋“œ ๊ตฌ๋ถ„ x
@Query("select m from Memo m order by m.mno desc")
List<Memo> getListDesc(); //๋ฉ”์„œ๋“œ๋ช… ์ž์œ 
//JPQLํŒŒ๋ผ๋ฏธํ„ฐ ์ „๋‹ฌ @Param(์ด๋ฆ„), :์ด๋ฆ„
@Query("select m from Memo m where m.mno > :num order by m.mno desc")
List<Memo> getListDesc2(@Param("num") Long mno);
//JPQL select๋ฌธ์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์„ ๋ณ„์ ์œผ๋กœ ๋ฐ›์œผ๋ ค๋ฉด Object[]์‚ฌ์šฉ ํ•ฉ๋‹ˆ๋‹ค.
@Query("select m.writer, m.text from Memo m where m.mno > :num order by m.mno desc")
List<Object[]> getListDesc3(@Param("num") Long mno);
//JPQL์—…๋ฐ์ดํŠธ
@Transactional //ํŠธ๋žœ์žญ์…˜ ๋ฐ˜์˜
@Modifying //์—…๋ฐ์ดํŠธ์ž„
@Query("update Memo m set m.writer = :a where m.mno = :b")
int updateMemo(@Param("a") String a, @Param("b") Long b);
//JPQL์—…๋ฐ์ดํŠธ - ๊ฐ์ฒดํŒŒ๋ผ๋ฏธํ„ฐ ๋ฅผ ๋„˜๊ธฐ๋Š” ๋ฐฉ๋ฒ• #{๊ฐ์ฒด}
@Transactional
@Modifying
@Query("update Memo m set m.writer = :#{#a.writer}, m.text = :#{#a.text} where m.mno = :#{#a.mno}")
int updateMemo(@Param("a") Memo memo);
//delete from memo where mno = 10;
//JPQL๋”œ๋ฆฌํŠธ๋ฌธ -
@Transactional
@Modifying
@Query("delete from Memo m where m.mno = :a")
int deleteMemo(@Param("a") Long mno);
//JPQL ๋งˆ์ง€๋ง‰๋งค๊ฐœ๋ณ€์ˆ˜์— Pageable์„ ์ฃผ๋ฉด, ํŽ˜์ด์ง€์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
//page์ฒ˜๋ฆฌ์—๋Š” countQuery๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค (countQuery๊ตฌ๋ฌธ์€ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š”๊ฒŒ ๊ฐ€๋Šฅํ•จ)
@Query(value = "select m from Memo m where m.mno <= :a",
countQuery = "select count(m) from Memo m where m.mno <= :a")
Page<Memo> getListJPQL(@Param("a") Long mno, Pageable pageable);
// select mno, writer, text, concat(writer, text) as col, current_timestamp
// from memo
// where mno <= 100;
// ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ฒ˜๋ฆฌํ•˜๋Š” JPQL์œผ๋กœ
@Query("select m.mno, m.writer, m.text, concat(m.writer, m.text) as col, current_timestamp " +
"from Memo m where m.mno <= :a")
Page<Object[]> getListJPQL2(@Param("a") Long mno, Pageable pageable);
//๋„ค์ดํ‹ฐ๋ธŒ์ฟผ๋ฆฌ - JPQL์ด ๋„ˆ๋ฌด ์–ด๋ ค์šฐ๋ฉด, SQL๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ œ๊ณตํ•ด์ค๋‹ˆ๋‹ค.
@Query(value = "select * from memo where mno = ?", nativeQuery = true)
Memo getNative(Long mno);
//๊ตฌํ˜„์ฒด์— ๋งŒ๋“œ๋Š” ๊ตฌ๋ฌธ์€ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์ด๋ ‡๊ฒŒ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.
// @Query("select m from Memo m inner join m.member x where m.mno >= :a")
// List<Memo> mtoJoin1(@Param("a") long a);
@Query(value = "select new com.example.jpa.entity.MemberMemoDTO(x.id, x.name, x.signDate, m.mno, m.writer, m.text) " +
"from Memo m left join m.member x where m.text like %:text%"
,countQuery = "select count(m) from Memo m left join m.member x where m.text like %:text%"
)
Page<MemberMemoDTO> joinPage(@Param("text") String text, Pageable pageable);
}

 

 

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 8px;
text-align: left;
border: 1px solid #ddd;
}
th {
background-color: #f2f2f2;
}
tbody tr:nth-child(even) {
background-color: #f9f9f9;
}
tbody tr:hover {
background-color: #f1f1f1;
}
.pagination {
display: flex;
justify-content: center;
margin-top: 20px;
list-style: none;
padding: 0;
}
.pagination li {
margin: 0 5px;
}
.pagination a {
display: block;
padding: 8px 16px;
text-decoration: none;
color: #007bff;
border: 1px solid #ddd;
border-radius: 4px;
}
.pagination a.active {
background-color: #007bff;
color: white;
border-color: #007bff;
}
.pagination a:hover {
background-color: #ddd;
}
</style>
</head>
<body>
<select name="searchType">
<option value="mno">๋ฒˆํ˜ธ</option>
<option value="text">๋‚ด์šฉ</option>
<option value="writer">์ž‘์„ฑ์ž</option>
<option value="textWriter">๋‚ด์šฉ + ์ž‘์„ฑ์ž</option>
</select>
<input type="text" name="searchName">
<button type="button" onclick="searchList()">๊ฒ€์ƒ‰</button>
<table>
<thead>
<tr>
<th>MNO</th>
<th>Writer</th>
<th>Text</th>
<th>Id</th>
<th>Name</th>
<th>Sign Date</th>
</tr>
</thead>
<tbody id="tableBody">
<!-- Rows will be inserted here by JavaScript -->
</tbody>
</table>
<ul class="pagination" id="pagination">
<!-- Pagination buttons will be inserted here by JavaScript -->
</ul>
<script>
var pagination = document.getElementById("pagination"); //ํŽ˜์ด์ง€๋„ค์ด์…˜ ํƒœ๊ทธ
var page = 1;
var amount = 10;
var start = 0; //์‹œ์ž‘ํŽ˜์ด์ง€๋„ค์ด์…˜๊ฐ’
var end = 0; //๋ํŽ˜์ด์ง€๋„ค์ด์…˜๊ฐ’
//๋ฐ์ดํ„ฐ ajax์š”์ฒญ
function getList() {
//searchName๊ฐ’
var searchName = document.querySelector("input[name=searchName]").value;
var url = "/getList?page=" + page + "&amount=" + amount + "&searchName=" + searchName;
fetch(url)
.then( function(response) {
return response.json()
})
.then( function(data) {
createBody(data.pageData) //๋ฐ”๋”” ์ƒ์„ฑํ•จ์ˆ˜ ํ˜ธ์ถœ
createPage(data); //ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ƒ์„ฑํ•จ์ˆ˜
})
} //end
//๋‚ด์šฉ ์ƒ์„ฑ ํ•จ์ˆ˜
function createBody(list) { //item์€ list์ผ ๊ฒƒ์ž„
var tableBody = document.getElementById("tableBody");
var str = "";
list.forEach( function(data) {
str += "<tr>";
str += "<td>" + data.mno + "</td>";
str += "<td>" + data.writer + "</td>";
str += "<td>" + data.text + "</td>";
str += "<td>" + data.id + "</td>";
str += "<td>" + data.name + "</td>";
str += "<td>" + data.signDate + "</td>";
str += "</tr>";
})
tableBody.innerHTML = str; //tbody๋ฐ‘์— ์ถ”๊ฐ€
}
//ํŽ˜์ด์ง€ ๋„ค์ด์…˜ ์ƒ์„ฑํ•จ์ˆ˜
function createPage(item) {
console.log(item);
var pageList = item.pageList; //ํŽ˜์ด์ง€๋„ค์ด์…˜๊ฐ’
var next = item.next; //๋‹ค์Œ๋ฒ„ํŠผ
var prev = item.prev; //์ด์ „๋ฒ„ํŠผ
start = item.start; //ํŽ˜์ด์ง€๋„ค์ด์…˜ ์‹œ์ž‘
end = item.end; //ํŽ˜์ด์ง€๋„ค์ด์…˜ ๋
var str = "";
//์ด์ „๋ฒ„ํŠผ
if(prev) {
str += "<a href='#' class='prev'>์ด์ „</a>";
}
//ํŽ˜์ด์ง€ ๋„ค์ด์…˜
pageList.forEach( function(data) {
str += "<a href='#' class='number' >" + data + "</a>";
})
//๋‹ค์Œ๋ฒ„ํŠผ
if(next) {
str += "<a href='#' class='next'>๋‹ค์Œ</a>";
}
pagination.innerHTML = str;
} //end
//ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ด๋ฒคํŠธ -> ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ๋’ค๋Šฆ๊ฒŒ ๊ทธ๋ ค์ง€๋Š” ํƒœ๊ทธ ( ๋ถ€๋ชจ์— ๊ฑธ๊ณ  ์ž์‹์—์„œ ์œ„์ž„ )
//์ด๋ฒคํŠธ๋Š” ๋ถ€๋ชจ์— ๊ฒ€~
pagination.addEventListener('click', function(e) {
e.preventDefault(); //a์ด๋ฒคํŠธ ์ค‘๋‹จ
if(e.target.className == 'pagination' ) return; //pagenationํด๋ฆญ์‹œ ํ•จ์ˆ˜ ์ข…๋ฃŒ
if(e.target.className == 'prev') { //์ด์ „๋ฒ„ํŠผ
page = start - 1; //์‹œ์ž‘๋ฒˆํ˜ธ์˜ 1
} else if(e.target.className == 'next') { //๋‹ค์Œ๋ฒ„ํŠผ
page = end + 1; //๋๋ฒˆํ˜ธ์˜ + 1
} else if(e.target.className == 'number') { //ํŽ˜์ด์ง€๋ฒˆํ˜ธ
page = e.target.innerHTML; //aํƒœ๊ทธ ์‚ฌ์ด๊ฐ’์„ ์ „์—ญ๋ณ€์ˆ˜ ์ €์žฅ
}
getList(); //๋ฐ์ดํ„ฐ ์กฐํšŒ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
});
//๊ฒ€์ƒ‰๊ธฐ๋Šฅ - ๊ฒ€์ƒ‰์„ ํ•œ๋‹ค๋Š” ๊ฒƒ์€~? ๋‹ค์‹œ ํƒœ์ดˆ๋กœ ๋Œ์•„๊ฐ„๋‹ค๋Š” ์˜๋ฏธ.
function searchList() {
page = 1;
amount = 10;
getList();
}
//์ฆ‰์‹œ์‹คํ–‰ํ•จ์ˆ˜
(function() {
getList(); //๋ฐ์ดํ„ฐ ์š”์ฒญ ํ˜ธ์ถœ
})();
</script>
</body>
</html>
package com.example.jpa.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@Controller
public class JpaController {
@GetMapping("/memoList")
public String main() {
return "memoList";
}
}
package com.example.jpa.entity;
import lombok.*;
import javax.persistence.*;
@Entity //jpa๊ฐ€ ์—”ํ‹ฐํ‹ฐ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค๋Š” ์˜๋ฏธ
@Table(name = "MEMO") //MEMOํ…Œ์ด๋ธ”
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Memo {
//์—”ํ‹ฐํ‹ฐ๋ฅผ ์ •์˜ํ•˜๋ฉด, ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๊ฐ€ DDL๊ตฌ๋ฌธ์„ ๋Œ€์‹  ์‹คํ–‰ํ•ด์ฃผ๋Š”๋ฐ, spring.jpa.hibernate.ddl-auto=update ์˜ต์…˜
@Id //pk
@GeneratedValue(strategy = GenerationType.IDENTITY) //auto_increment๋™์ž‘
// ์˜ค๋ผํด์ „๋žต
// @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "์ด๋ฆ„")
// @SequenceGenerator(name = "์ด๋ฆ„", sequenceName = "์‹œํ€€์Šค๋ช…", initialValue = 1, allocationSize = 1)
private long mno;
@Column(length = 200, nullable = false)
private String writer;
@Column(columnDefinition = "varchar(200) default 'y' ") //๋งŒ๋“ค๊ณ  ์‹ถ์€ ์ œ์•ฝ์„ ์ง์ ‘ ๋ช…์‹œ
private String text;
//N:1
//FK ์ปฌ๋Ÿผ๋ช…์„ ๋ช…์‹œํ•˜์ง€ ์•Š์œผ๋ฉด Member์—”ํ‹ฐํ‹ฐ์— member_์ฃผํ‚ค ๋กœ ์ž๋™ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
// @ManyToOne(fetch = FetchType.LAZY) //manyToOne ๊ธฐ๋ณธ๊ฐ’์€ EAGER๋ฐฉ์‹
// @JoinColumn(name = "member_id") //Member์—”ํ‹ฐํ‹ฐ์˜ ์ฃผํ‚ค๋ฅผ member_id์ปฌ๋Ÿผ์— ์ €์žฅํ•˜๊ฒ ๋‹ค(FK)
// private Member member; //๋ฉค๋ฒ„ ์—”ํ‹ฐํ‹ฐ
//์–‘๋ฐฉํ–ฅ ๋งตํ•‘
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
}