티스토리 뷰
간단한 개념은 앞선 글에 정리.
Item 클래스를 가지고 보다 심화된 내용 정리할 것.
기본으로 만들어주는 쿼리는 복잡한 것 사용하기 어려움. WHERE의 여러 조건문들을(?)
그래서 자동으로 만들어주는 쿼리 메소드 대신 직접 만들어서 사용하는 쿼리?
간단한 쿼리는 JPA - CRUD 같은 거는 엄청 편함
근데 쿼리가 복잡해지면... Mybatis 사용이 편하기도?
repository에서 작업하는 것은 서비스단 작업 - 앞쪽 작업.
♣ 원래 쿼리 메소드는 동적 처리 불가 → Annotation으로 동적 쿼리 작업
♣ 동적 쿼리를 위한 dsl 사용
동적쿼리 생성. 쿼리 재사용할 수 있어 제약조건 조립 및 가독성 향상/
문자열 x 자바 소스코드로 작성하기 때문에 컴파일 시점에서 오류 발견 가능. 자동완성기능 사용가능
♣ 연관관계 매핑
♣ 시큐리티(Security) - 수요일?
2. Member 만들어서 실습
(0) 만약 프로젝트 만들 때, 필요한 라이브러리를 선택하지 않았다면
pom.xml에 추가하면 된다. maven repository에서 검색해서
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
JPA 선택했는데 누락되어 있어서 테이블 생성이 안 됐던 것임. 위의 것을 추가해줘야 JPA 테이블 생성할 수 있음.
(1) 클래스 Member 생성
-위치 : com.wsy.demojpa01.domain
package com.wsy.demojpa01.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import com.wsy.demojpa01.constant.Role;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Data
@Entity
@Table(name="member")
@Getter @Setter @ToString
public class Member {
@Id //pk
@Column(name="member_id")
@GeneratedValue(strategy = GenerationType.IDENTITY) //pk 자동 생성될 때, 전략 - AutoIncrement
private Long id;
private String password;
private String name;
private String address;
@Column(unique=true)
private String email;
@Enumerated(EnumType.STRING)
private Role role;
}
(1-1) enum 생성
package com.wsy.demojpa01.constant;
public enum Role {
USER, ADMIN
}
(1-3) MemberRepository01 인터페이스 생성
package com.wsy.demojpa01.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.wsy.demojpa01.domain.Member;
public interface MemberRepository01 extends JpaRepository<Member, Long>{
}
(2) MemberTest 클래스 생성 해 테스트
-위치 : src/test/java
(3-1) insert 데이터 입력/추가
package com.wsy.demojpa01.repository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import com.wsy.demojpa01.constant.Role;
import com.wsy.demojpa01.domain.Member;
@SpringBootTest
@TestPropertySource(locations="classpath:application.properties")
public class MemberTest {
@Autowired
MemberRepository01 memberRepository;
@Test
public void createMemberTest() {
Member member = new Member();
member.setName("홍길동");
member.setEmail("hong@gmail.com");
member.setPassword("1234");
member.setAddress("부산 부산진구");
member.setRole(Role.ADMIN);
memberRepository.save(member);
}
@Test
public void createMemberListTest() {
for(int i=0; i<5; i++) {
Member member = new Member();
member.setName("고길동"+i);
member.setEmail("go"+i+"@gmail.com");
member.setPassword("1234");
member.setAddress("부산 부산진구"+i);
member.setRole(Role.USER);
memberRepository.save(member);
}
}
@Test
public void createMemberListTest02() {
for(int i=5; i<10; i++) {
Member member = new Member();
member.setName("희동이"+i);
member.setEmail("go"+i+"@gmail.com");
member.setPassword("1234");
member.setAddress("부산 부산진구"+i);
member.setRole(Role.USER);
memberRepository.save(member);
}
}
}
└각각 junit 테스트 후 데이터가 제대로 들어갔는지 확인
(3-2) 데이터 가져오기 - MemberTest.java
//리스트 전체 가져오기
@Test
public void getMemberList() {
List<Member> members = memberRepository.findAll(); //findAll은 만들지 않아도 쓸 수 있음.
for(int i = 0; i<members.size(); i++) {
System.out.println(members.get(i)); //toString이 있기 때문에 이것만 써도 됨.
}
}
//데이터 하나 가져오기
@Test
public void getMember2() {
Member member2 = memberRepository.findById(2L).get();
System.out.println(member2);
}
Member(id=1, password=1234, name=고길동0, address=부산 부산진구0, email=go0@gmail.com, role=USER) Member(id=2, password=1234, name=고길동1, address=부산 부산진구1, email=go1@gmail.com, role=USER) Member(id=3, password=1234, name=고길동2, address=부산 부산진구2, email=go2@gmail.com, role=USER) Member(id=4, password=1234, name=고길동3, address=부산 부산진구3, email=go3@gmail.com, role=USER) Member(id=5, password=1234, name=고길동4, address=부산 부산진구4, email=go4@gmail.com, role=USER) Member(id=6, password=1234, name=홍길동, address=부산 부산진구, email=hong@gmail.com, role=ADMIN) Member(id=7, password=1234, name=희동이5, address=부산 부산진구5, email=go5@gmail.com, role=USER) Member(id=8, password=1234, name=희동이6, address=부산 부산진구6, email=go6@gmail.com, role=USER) Member(id=9, password=1234, name=희동이7, address=부산 부산진구7, email=go7@gmail.com, role=USER) Member(id=10, password=1234, name=희동이8, address=부산 부산진구8, email=go8@gmail.com, role=USER) Member(id=11, password=1234, name=희동이9, address=부산 부산진구9, email=go9@gmail.com, role=USER) 2022-03-21 11:07:39.346 INFO 5208 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2022-03-21 11:07:39.349 INFO 5208 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2022-03-21 11:07:39.371 INFO 5208 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. |
Member(id=2, password=1234, name=고길동1, address=부산 부산진구1, email=go1@gmail.com, role=USER) 2022-03-21 11:17:54.821 INFO 10552 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2022-03-21 11:17:54.826 INFO 10552 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2022-03-21 11:17:54.841 INFO 10552 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed. |
(3-3) 업데이트/딜리트
//updqte
@Test
public void updateMemberTest() {
Member member = new Member();
member.setId(1L); //PK //member_id 1번 수정
member.setName("둘리"); //변경
member.setEmail("ddd@gmail.com"); //변경
member.setPassword("1234");
member.setAddress("제주 서귀포시"); //변경
member.setRole(Role.ADMIN);
memberRepository.save(member);
}
//delete
//delete
@Test
public void delete() {
Member member = new Member();
member.setId(8L);
memberRepository.delete(member);
memberRepository.deleteById(9L); //mebmer_id 9번 지우겠다.
}
>> MySQL 에서 확인
└1번 변경되었고 8번과 9번이 삭제된 것을 알 수 있다.
>> repository에 아무것도 작성하지 않고
데이터 입력/수정/삭제 했음. 기본 제공 쿼리로
특정한 쿼리를 사용하고 싶다면, 추가해주면 된다.
-특정 열의 데이터를 가져오는 것. 기본적으로 제공하지 않는.
-[ findBy~ ] WHERE절
(3-4) repository에 쿼리 추가해서 사용
package com.wsy.demojpa01.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.wsy.demojpa01.domain.Member;
public interface MemberRepository01 extends JpaRepository<Member, Long>{
public List<String> findByName();
public List<String> findByEmail();
}
>> 수정
이름과 이메일을 찾는 쿼리문을 찾을 수 있는 이유. 디비 컬럼에 있으니까!
package com.wsy.demojpa01.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.wsy.demojpa01.domain.Member;
public interface MemberRepository01 extends JpaRepository<Member, Long>{
//select * from member where name = ${name}
public List<Member> findByName(String name);
}
//특정한 데이터만 가져오기. 쿼리문 추가
@Test
public void name() {
List<Member> members = memberRepository.findByName("홍길동"); //repository에서 추가한 것
for(Member member:members) {
System.out.println(member);
}
}
//
@Test
public void name_email() {
List<Member> members = memberRepository.findByName("홍길동"); //repository에서 추가한 것
for(Member member:members) {
System.out.println(member);
}
List<Member> members2 = memberRepository.findByEmail("ddd@gmail.com"); //repository에서 추가한 것
for(Member member22:members2) {
System.out.println(member22);
}
}
이름이 홍길동인 사람을 찾아 List 형식으로 데이터 출력
Member(id=6, password=1234, name=홍길동, address=부산 부산진구, email=hong@gmail.com, role=ADMIN) |
Member(id=1, password=1234, name=둘리, address=제주 서귀포시, email=ddd@gmail.com, role=ADMIN) |
-MemberRepository.java
package com.wsy.demojpa01.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.wsy.demojpa01.domain.Member;
public interface MemberRepository01 extends JpaRepository<Member, Long>{
//컬럼명에 없는 것은 사용할 수 없음. findByNames 같은 거.
//WHERE절
//select * from member where name = ${name}
public List<Member> findByName(String name);
// public List<Member> findByEmail();
//select * from member where email = ${name}
public List<Member> findByEmail(String email);
//AND절
//select * from member where name = ${name} and email = ${name}
public List<Member> findByNameAndEmail(String name, String email);
//OR절
//select * from member where name = ${name} Or email = ${name}
public List<Member> findByNameOrEmail(String name, String email);
//LIKE
//select * from member where name Like '%홍길동%'
public List<Member> findByNameLike(String name);
//IN
//select * from member where name in('고길동1', '고길동3')
public List<Member> findByNameIn(String...names); //보낼 때, 배열로 보내면 됨.
//정렬
//select * from member order by id desc;
public List<Member> findAllByOrderByIdDesc();
}
-MemberTest.java :
package com.wsy.demojpa01.repository;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import com.wsy.demojpa01.constant.Role;
import com.wsy.demojpa01.domain.Member;
@SpringBootTest
@TestPropertySource(locations="classpath:application.properties")
public class MemberTest {
@Autowired
MemberRepository01 memberRepository;
...
@Test
public void nameAndEmail() {
List<Member> nae = memberRepository.findByNameAndEmail("둘리", "ddd@gmail.com");
for(Member m : nae) {
System.out.println(m);
}
}
@Test
public void nameOrEmail() {
List<Member> aoe = memberRepository.findByNameOrEmail("둘리", "hong@gmail.com");
for(Member m2 : aoe) {
System.out.println(m2);
}
}
@Test
public void nameLikeEmail() {
List<Member> nle = memberRepository.findByNameLike("%희동이%");
for(Member m : nle) {
System.out.println(m);
}
}
@Test
//배열로 받아오면 된대
public void nameIn() {
/*
* List<Member>[] ni = memberRepository.findByName("고길동1", "고길동2"); for(Member m
* : ni) { System.out.println(m); }
*/
String[] names = {"희동이9", "고길동1"};
List<Member> members = memberRepository.findByNameIn(names);
for(Member m:members) {
System.out.println(m);
}
}
//oreder by - 전체 데이터 가져와서 id로 역순 정렬
@Test
public void orderby() {
// List<Member> members = memberRepository.findAllByOrderByIdDesc();
List<Member> members = memberRepository.findAll(Sort.by(Sort.Direction.DESC, "id")); //(정렬방향, 정렬기준)
//findAll 자동완성 중에 (Sort sort) 선택해서 위와 같이 입력할 수 있음.
for(Member m : members) {
System.out.println(m);
}
}
}
└정렬할 때 둘 중 어느걸 사용해도 같은 결과.
>> 콘솔 결과 출력 :
findByNameAndEmail | |
Member(id=1, password=1234, name=둘리, address=제주 서귀포시, email=ddd@gmail.com, role=ADMIN) | |
findByNameOrEmail | |
Member(id=1, password=1234, name=둘리, address=제주 서귀포시, email=ddd@gmail.com, role=ADMIN) Member(id=6, password=1234, name=홍길동, address=부산 부산진구, email=hong@gmail.com, role=ADMIN) |
|
findByNameLike | |
Member(id=7, password=1234, name=희동이5, address=부산 부산진구5, email=go5@gmail.com, role=USER) Member(id=10, password=1234, name=희동이8, address=부산 부산진구8, email=go8@gmail.com, role=USER) Member(id=11, password=1234, name=희동이9, address=부산 부산진구9, email=go9@gmail.com, role=USER) |
|
findByNameIn | |
Member(id=2, password=1234, name=고길동1, address=부산 부산진구1, email=go1@gmail.com, role=USER) Member(id=11, password=1234, name=희동이9, address=부산 부산진구9, email=go9@gmail.com, role=USER) |
|
findallByOrderByIdDesc | |
Member(id=11, password=1234, name=희동이9, address=부산 부산진구9, email=go9@gmail.com, role=USER) Member(id=10, password=1234, name=희동이8, address=부산 부산진구8, email=go8@gmail.com, role=USER) Member(id=7, password=1234, name=희동이5, address=부산 부산진구5, email=go5@gmail.com, role=USER) Member(id=6, password=1234, name=홍길동, address=부산 부산진구, email=hong@gmail.com, role=ADMIN) Member(id=5, password=1234, name=고길동4, address=부산 부산진구4, email=go4@gmail.com, role=USER) Member(id=4, password=1234, name=고길동3, address=부산 부산진구3, email=go3@gmail.com, role=USER) Member(id=3, password=1234, name=고길동2, address=부산 부산진구2, email=go2@gmail.com, role=USER) Member(id=2, password=1234, name=고길동1, address=부산 부산진구1, email=go1@gmail.com, role=USER) Member(id=1, password=1234, name=둘리, address=제주 서귀포시, email=ddd@gmail.com, role=ADMIN) |
|
-있는 것- findAll(Sort, sort) | |
Member(id=11, password=1234, name=희동이9, address=부산 부산진구9, email=go9@gmail.com, role=USER) Member(id=10, password=1234, name=희동이8, address=부산 부산진구8, email=go8@gmail.com, role=USER) Member(id=7, password=1234, name=희동이5, address=부산 부산진구5, email=go5@gmail.com, role=USER) Member(id=6, password=1234, name=홍길동, address=부산 부산진구, email=hong@gmail.com, role=ADMIN) Member(id=5, password=1234, name=고길동4, address=부산 부산진구4, email=go4@gmail.com, role=USER) Member(id=4, password=1234, name=고길동3, address=부산 부산진구3, email=go3@gmail.com, role=USER) Member(id=3, password=1234, name=고길동2, address=부산 부산진구2, email=go2@gmail.com, role=USER) Member(id=2, password=1234, name=고길동1, address=부산 부산진구1, email=go1@gmail.com, role=USER) Member(id=1, password=1234, name=둘리, address=제주 서귀포시, email=ddd@gmail.com, role=ADMIN) |
게시판에서 데이터 일부만 가져오는 것. Controller에서 작업.
(3) Pageable
Query 메소드의 입력 변수. Pageable 변수를 추가하면 Page 타입을 반환형으로 사용
Pageable 객체를 통해 페이징과 정렬을 위한 파라미터 전달
-page : 몇번째 페이지 인지를 전달
-size : 한 페이지에 몇 개의 항목을 보여줄 것인지 전달
-sort : 정렬정보 전달. 정렬정보는 필드 이름, 정렬방향의 포맷으로 전달. 여러 필드로 순차적으로 정렬 가능
ex) sort=createdAt,desc&sort=userId,asc
*매핑할 때, GET은 안 적어도 됨. POST는 반드시 전송 메소드 적어줘야 함.
RequestMapping("") 안 적으면 GET, POST일 경우는 반드시 적어줘야함 : RequestMapping(value="post")
(3-1) MemberTest.java
//pageable - 레코드 일부만 가져오기 !pageDTO 안 만들어돔(PageVO를 말하는 건가?)
@Test
public void pageTest() {
//여러 pageable 중에서 domain인 거 가져옴
Pageable pageable = PageRequest.of(0, 5);
Page<Member> memberPage = memberRepository.findAll(pageable);
//그냥 쓰는게 아니라 페이지를 뽑아내야 함
List<Member> members = memberPage.getContent();
for(Member m : members) {
System.out.println(m);
}
}
└한 페이지에 출력될 것이 0번부터 5번이란 건가?
>> junit 테스트 결과
Member(id=1, password=1234, name=둘리, address=제주 서귀포시, email=ddd@gmail.com, role=ADMIN) Member(id=2, password=1234, name=고길동1, address=부산 부산진구1, email=go1@gmail.com, role=USER) Member(id=3, password=1234, name=고길동2, address=부산 부산진구2, email=go2@gmail.com, role=USER) Member(id=4, password=1234, name=고길동3, address=부산 부산진구3, email=go3@gmail.com, role=USER) Member(id=5, password=1234, name=고길동4, address=부산 부산진구4, email=go4@gmail.com, role=USER) |
3. 실습
domain 패키지의 Item 가지고 배운 내용 복습
(0) 기존의 Item.java
package com.wsy.demojpa01.domain;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.wsy.demojpa01.constant.ItemSellstatus;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Entity
@Table(name="item")
@Getter @Setter @ToString
public class Item {
@Id
@Column(name="item_id")
@GeneratedValue(strategy = GenerationType.AUTO) //시퀀스 생성한다.
private Long id;
@Column(nullable = false, length=50)
private String itemNm;
@Column(name ="price", nullable = false)
private int price;
@Column(nullable = false)
private int stockNumber;
@Lob // BLOB, CLOB 형태로 데이터를 저장한다.
@Column(nullable = false)
private String itemDetail;
@Enumerated(EnumType.STRING)
private ItemSellstatus itemSellStatus;
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
@DateTimeFormat(pattern="yyyy-MM-dd'T'HH:mm:ss")
@CreationTimestamp //생성 날짜 자동
private LocalDateTime regTime;
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone="Asia/Seoul")
@DateTimeFormat(pattern="yyyy-MM-dd'T'HH:mm:ss")
@UpdateTimestamp //수정날짜 자동 갱신
private LocalDateTime updateTime;
}
(1) ItemRepository 생성
package com.wsy.demojpa01.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.wsy.demojpa01.domain.Item;
public interface ItemRepository extends JpaRepository<Item, Long> {
//데이터 저장, list 조회, entity 1개 조회, 수정, 삭제 작성
}
-테스트에서 함수를 만들어서 Repository에 자동생성(create)되도록해도 되고
Repository에서 미리 만들어둬서 ItemTest에서 자동 완성되도록 할 수도 있음. 본인 선택
(2) ItemTest.java
package com.wsy.demojpa01.repository;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import com.wsy.demojpa01.constant.ItemSellstatus;
import com.wsy.demojpa01.domain.Item;
@SpringBootTest
@TestPropertySource(locations="classpath:application.properties")
public class ItemTest {
@Autowired
ItemRepository itemRepository;
//Item
@Test
public void createItem() {
Item item = new Item();
item.setItemDetail("test");
item.setItemNm("test");
item.setPrice(50000);
item.setItemSellStatus(ItemSellstatus.SOLD_OUT);
item.setStockNumber(1234);
// item.setRegTime(LocalDateTime.now());
// item.setUpdateTime(LocalDateTime.now());
//domain 패키지 폴더의 Item 클래스에 createTimeStamp 사용하지 않을 경우 이렇게 넣어주면 됨.
itemRepository.save(item);
}
//여러 개 입력
@Test
public void createItemList() {
for(int i =0; i<10; i++) {
Item item = new Item();
item.setItemNm("상품번호"+i);
item.setItemDetail("상품설명"+i);
item.setPrice(500000);
item.setStockNumber(i);
item.setItemSellStatus(ItemSellstatus.SELL);
itemRepository.save(item);
}
}
//조회
@Test
public void getListItem() {
List<Item> iLists = itemRepository.findAll();
for(int i = 0; i<iLists.size(); i++) {
System.out.println(iLists.get(i));
}
}
//하나 조회 ??
@Test
public void getItemOne() {
Item item = itemRepository.findById(1L).get();
System.out.println(item);
}
//Item(id=1, itemNm=0000, price=100000, stockNumber=9876, itemDetail=상품설명예제, itemSellStatus=SELL, regTime=null, updateTime=2022-03-21T14:07:43.983720)
//update
@Test
public void updateItem() {
Item item = new Item();
item.setId(1L);
item.setItemDetail("상품설명예제");
item.setItemNm("0000");
item.setPrice(100000);
item.setItemSellStatus(ItemSellstatus.SELL);
item.setStockNumber(9876);
itemRepository.save(item);
}
//delete
@Test
public void deleteItem() {
Item item = new Item();
item.setId(6L);
itemRepository.delete(item);
}
//특정 상품 조회
@Test
@DisplayName("상품명 조회 테스트")
public void findByItemNmTest() {
List<Item> itemList = itemRepository.findByItemNm("상품번호1");
for(Item item : itemList) {
System.out.println(item);
}
}
//결과 Item(id=3, itemNm=상품번호1, price=1, stockNumber=1, itemDetail=상품설명1, itemSellStatus=SELL, regTime=2022-03-21T14:02:46.486364, updateTime=2022-03-21T14:02:46.486364)
//OR
@Test
@DisplayName("상품명, 상품상세설명 or 테스트")
public void findByItemNmOrItemDetailTest() {
List<Item> itemList = itemRepository.findByItemNmOrItemDetail("상품번호9", "상품설명5");
for(Item item : itemList) {
System.out.println(item.toString());
}
}
/*
Item(id=18, itemNm=상품번호5, price=500000, stockNumber=5, itemDetail=상품설명5, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.918709, updateTime=2022-03-21T14:25:17.918709)
Item(id=22, itemNm=상품번호9, price=500000, stockNumber=9, itemDetail=상품설명9, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.959530, updateTime=2022-03-21T14:25:17.959530)
* */
//
@Test
@DisplayName("가격 LessThan 테스트")
public void findByPriceLessThanTest() {
// this.createItemList(); //가상데이터베이스 사용해서 테스트할 때 사용
List<Item> itemList = itemRepository.findByPriceLessThan(450000);
for(Item item : itemList) {
System.out.println(item.toString());
}
}
//Item(id=1, itemNm=0000, price=100000, stockNumber=9876, itemDetail=상품설명예제, itemSellStatus=SELL, regTime=null, updateTime=2022-03-21T14:07:43.983720)
@Test
@DisplayName("가격 GreaterThanEqual 테스트")
public void findByPriceGreaterThanEqualTest() {
List<Item> itemList = itemRepository.findByPriceGreaterThanEqual(500000);
for(Item item : itemList) {
System.out.println(item.toString());
}
}
/*
Item(id=13, itemNm=상품번호0, price=500000, stockNumber=0, itemDetail=상품설명0, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.840744, updateTime=2022-03-21T14:25:17.840744)
Item(id=14, itemNm=상품번호1, price=500000, stockNumber=1, itemDetail=상품설명1, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.873729, updateTime=2022-03-21T14:25:17.873729)
Item(id=15, itemNm=상품번호2, price=500000, stockNumber=2, itemDetail=상품설명2, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.884724, updateTime=2022-03-21T14:25:17.884724)
Item(id=16, itemNm=상품번호3, price=500000, stockNumber=3, itemDetail=상품설명3, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.894720, updateTime=2022-03-21T14:25:17.894720)
Item(id=17, itemNm=상품번호4, price=500000, stockNumber=4, itemDetail=상품설명4, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.907714, updateTime=2022-03-21T14:25:17.907714)
Item(id=18, itemNm=상품번호5, price=500000, stockNumber=5, itemDetail=상품설명5, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.918709, updateTime=2022-03-21T14:25:17.918709)
Item(id=19, itemNm=상품번호6, price=500000, stockNumber=6, itemDetail=상품설명6, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.928705, updateTime=2022-03-21T14:25:17.928705)
Item(id=20, itemNm=상품번호7, price=500000, stockNumber=7, itemDetail=상품설명7, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.940700, updateTime=2022-03-21T14:25:17.940700)
Item(id=21, itemNm=상품번호8, price=500000, stockNumber=8, itemDetail=상품설명8, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.949695, updateTime=2022-03-21T14:25:17.949695)
Item(id=22, itemNm=상품번호9, price=500000, stockNumber=9, itemDetail=상품설명9, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.959530, updateTime=2022-03-21T14:25:17.959530)
*/
@Test
@DisplayName("상품명 내림차순 정렬")
public void orderByItem() {
List<Item> items = itemRepository.findAllByOrderByIdDesc();
// List<Item> items = itemRepository.findAll(Sort.by(Sort.Direction.DESC), "id");
for(Item item:items) {
System.out.println(item);
}
}
/*
Item(id=22, itemNm=상품번호9, price=500000, stockNumber=9, itemDetail=상품설명9, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.959530, updateTime=2022-03-21T14:25:17.959530)
Item(id=21, itemNm=상품번호8, price=500000, stockNumber=8, itemDetail=상품설명8, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.949695, updateTime=2022-03-21T14:25:17.949695)
Item(id=20, itemNm=상품번호7, price=500000, stockNumber=7, itemDetail=상품설명7, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.940700, updateTime=2022-03-21T14:25:17.940700)
Item(id=19, itemNm=상품번호6, price=500000, stockNumber=6, itemDetail=상품설명6, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.928705, updateTime=2022-03-21T14:25:17.928705)
Item(id=18, itemNm=상품번호5, price=500000, stockNumber=5, itemDetail=상품설명5, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.918709, updateTime=2022-03-21T14:25:17.918709)
Item(id=17, itemNm=상품번호4, price=500000, stockNumber=4, itemDetail=상품설명4, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.907714, updateTime=2022-03-21T14:25:17.907714)
Item(id=16, itemNm=상품번호3, price=500000, stockNumber=3, itemDetail=상품설명3, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.894720, updateTime=2022-03-21T14:25:17.894720)
Item(id=15, itemNm=상품번호2, price=500000, stockNumber=2, itemDetail=상품설명2, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.884724, updateTime=2022-03-21T14:25:17.884724)
Item(id=14, itemNm=상품번호1, price=500000, stockNumber=1, itemDetail=상품설명1, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.873729, updateTime=2022-03-21T14:25:17.873729)
Item(id=13, itemNm=상품번호0, price=500000, stockNumber=0, itemDetail=상품설명0, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.840744, updateTime=2022-03-21T14:25:17.840744)
Item(id=1, itemNm=0000, price=100000, stockNumber=9876, itemDetail=상품설명예제, itemSellStatus=SELL, regTime=null, updateTime=2022-03-21T14:07:43.983720)
*/
}
>> 근데,
업데이트할 때, 현재등록시간이 초기화가 되버림.
>> 해결방법 :
Spring DATA JPA @Query Annotation
실제 쿼리를 사용하는 것. SQL과 유사한 JPQL이라는 객체지향 쿼리 언어 사용
(문법을 잘 지켜야 해서...기본 제공 문법은 쓰면 안 됨, 사용자 지정 쿼리를 만들 때)
@Query("select i from Item i where i.itemDetail like %:itemDetail% order by i.price desc")
List<Item> findByItemDetail(@Param("itemDetail") String itemDetail);
//쿼리 안에 엔티티 값이 들어감.
//Native Query쓸 때, 이블에 있는 실제 테이블 이름 사용
// 파라매터 값에 itemDetail이 아니라 ? 사용해야함.
//@Query(value="select * from Item i where i.item_detail like %:itemDetail% order by i.price desc", nativeQuery=true)
@Query(value="select * from Item i where i.item_detail like %:?% order by i.price desc", nativeQuery=true)
List<Item> findByItemDetailByNative(@Param("itemDetail") String itemDetail);
-% : like
(0)ItemRepository
package com.wsy.demojpa01.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.wsy.demojpa01.domain.Item;
public interface ItemRepository extends JpaRepository<Item, Long> {
//데이터 저장, list 조회, entity 1개 조회, 수정, 삭제 작성
List<Item> findByItemNm(String string);
List<Item> findByPriceLessThan(int i);
List<Item> findByItemNmOrItemDetail(String string, String string2);
List<Item> findByPriceGreaterThanEqual(int i);
List<Item> findAllByOrderByIdDesc();
//★ Spring Data JPA @Query 사용
@Query(value="select * from item", nativeQuery = true) //실제 쿼리를 사용한다는 뜻.
List<Item> getListAA();
//테이블 item_detail / 필드명 itemDetail ★
@Query("select i from Item i where i.itemDetail like %:itemDetail% order by i.price desc")
List<Item> selectItemDetailNative(@Param("itemDetail") String itemDetail);
}
(0) ItemTest
@Test
@DisplayName("@Query를 이용한 상품 조회 테스트")
public void findByItemDetailTest() {
this.createItemList();
List<Item> itemList = itemRepository.selectItemDetailNative("상품설명2");
for (Item item : itemList) {
System.out.println(item.toString());
}
}
/*
Item(id=15, itemNm=상품번호2, price=500000, stockNumber=2, itemDetail=상품설명2, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.884724, updateTime=2022-03-21T14:25:17.884724)
Item(id=25, itemNm=상품번호2, price=500000, stockNumber=2, itemDetail=상품설명2, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.033004, updateTime=2022-03-21T15:56:11.033004)
*/
4. Spring Data JPA Querydsl
동적쿼리 생성
쿼리 재사용할 수 있어 제약조건 조립 및 가독성 향상
문자열이 아닌 자바 소스코드로 작성하기 때문에 컴파일 시점 오류 발견
IDE 도움을 받아서 자동 완성 기능 사용
(1) 환경설정
(1-1) pom.xml - dependecies에 querydsl-jap와 querydsl-apt 코드를 넣고 / plugin에 apt-maven-plugin을 넣어줘야함.
<!-- 동적쿼리 사용을 위한 코드 추가 -->
<dependencies>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
</dependency>
</dependencies>
...
<plugins>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
(1-2) ItemRepository
public interface ItemRepository extends JpaRepository<Item, Long>, QuerydslPredicateExecutor<Item>{
//QuerydslPredicateExecutor<Item> 이거 추가 ↑
}
(2) Querydsl 테스트
(2-1) ItemTest
프로그램. 코드에서 바로 디비에 연결해서 사용. 자동완성 기능이라 오타 줄이고 사용이 편이.
package com.wsy.demojpa01.repository;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.wsy.demojpa01.constant.ItemSellstatus;
import com.wsy.demojpa01.domain.Item;
import com.wsy.demojpa01.domain.QItem;
@SpringBootTest
@TestPropertySource(locations="classpath:application.properties")
public class ItemTest {
@Autowired
ItemRepository itemRepository;
//4. dsl사용하기
@PersistenceContext
EntityManager em; //실제 사용할 때, Service에 넣음 - 서비스단
@Test
@DisplayName("상품 Querydsl 조회 테스트")
public void queryDslTest() {
//boolean 검색조건
// BooleanBuilder builder = new BooleanBuilder(); //빌드 만들었음.
JPAQueryFactory queryFactory = new JPAQueryFactory(em); //엔티티 매니저를 매개변수로 넣음.
QItem qitem = QItem.item; //쿼리 라이브러리 넣으면 자동 생성
JPAQuery<Item> query = queryFactory.selectFrom(qitem) //셀렉트 쿼리를 사용할 거란 뜻.
//select * from item
.where(qitem.itemSellStatus.eq(ItemSellstatus.SELL))
//WHERE item_sell_status = 'SELL'
.where(qitem.itemDetail.like("%"+"설명"+"%")) // 공통 쿼리. 이후에 추가 쿼리를 점(.)을 이용해 붙일 수 있음. 점(.)은 AND
.orderBy(qitem.price.desc()); //세미콜론(;)을 찍지 않으면 계속 이어진다는 의미.
List<Item> items = query.fetch(); //fetch는 모든 내용을 넣는다. 어디에? items에?
//fetch : 결과를 받아오는 것. resultSet re = query.execute()
//결과를 받아와 List 형태의 items에 넣음.
for(Item item : items) {
System.out.println(item.toString());
}
}
...
}
%설명%인 것 모두 출력
(2-2) junit 테스트
Item(id=13, itemNm=상품번호0, price=500000, stockNumber=0, itemDetail=상품설명0, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.840744, updateTime=2022-03-21T14:25:17.840744) Item(id=14, itemNm=상품번호1, price=500000, stockNumber=1, itemDetail=상품설명1, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.873729, updateTime=2022-03-21T14:25:17.873729) Item(id=15, itemNm=상품번호2, price=500000, stockNumber=2, itemDetail=상품설명2, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.884724, updateTime=2022-03-21T14:25:17.884724) Item(id=16, itemNm=상품번호3, price=500000, stockNumber=3, itemDetail=상품설명3, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.894720, updateTime=2022-03-21T14:25:17.894720) Item(id=17, itemNm=상품번호4, price=500000, stockNumber=4, itemDetail=상품설명4, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.907714, updateTime=2022-03-21T14:25:17.907714) Item(id=18, itemNm=상품번호5, price=500000, stockNumber=5, itemDetail=상품설명5, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.918709, updateTime=2022-03-21T14:25:17.918709) Item(id=19, itemNm=상품번호6, price=500000, stockNumber=6, itemDetail=상품설명6, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.928705, updateTime=2022-03-21T14:25:17.928705) Item(id=20, itemNm=상품번호7, price=500000, stockNumber=7, itemDetail=상품설명7, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.940700, updateTime=2022-03-21T14:25:17.940700) Item(id=21, itemNm=상품번호8, price=500000, stockNumber=8, itemDetail=상품설명8, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.949695, updateTime=2022-03-21T14:25:17.949695) Item(id=22, itemNm=상품번호9, price=500000, stockNumber=9, itemDetail=상품설명9, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.959530, updateTime=2022-03-21T14:25:17.959530) Item(id=23, itemNm=상품번호0, price=500000, stockNumber=0, itemDetail=상품설명0, itemSellStatus=SELL, regTime=2022-03-21T15:56:10.988024, updateTime=2022-03-21T15:56:10.988024) Item(id=24, itemNm=상품번호1, price=500000, stockNumber=1, itemDetail=상품설명1, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.017011, updateTime=2022-03-21T15:56:11.017011) Item(id=25, itemNm=상품번호2, price=500000, stockNumber=2, itemDetail=상품설명2, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.033004, updateTime=2022-03-21T15:56:11.033004) Item(id=26, itemNm=상품번호3, price=500000, stockNumber=3, itemDetail=상품설명3, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.042999, updateTime=2022-03-21T15:56:11.042999) Item(id=27, itemNm=상품번호4, price=500000, stockNumber=4, itemDetail=상품설명4, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.053995, updateTime=2022-03-21T15:56:11.053995) Item(id=28, itemNm=상품번호5, price=500000, stockNumber=5, itemDetail=상품설명5, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.063990, updateTime=2022-03-21T15:56:11.063990) Item(id=29, itemNm=상품번호6, price=500000, stockNumber=6, itemDetail=상품설명6, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.073986, updateTime=2022-03-21T15:56:11.073986) Item(id=30, itemNm=상품번호7, price=500000, stockNumber=7, itemDetail=상품설명7, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.086980, updateTime=2022-03-21T15:56:11.086980) Item(id=31, itemNm=상품번호8, price=500000, stockNumber=8, itemDetail=상품설명8, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.095976, updateTime=2022-03-21T15:56:11.095976) Item(id=32, itemNm=상품번호9, price=500000, stockNumber=9, itemDetail=상품설명9, itemSellStatus=SELL, regTime=2022-03-21T15:56:11.105972, updateTime=2022-03-21T15:56:11.105972) Item(id=1, itemNm=0000, price=100000, stockNumber=9876, itemDetail=상품설명예제, itemSellStatus=SELL, regTime=null, updateTime=2022-03-21T14:07:43.983720) |
(3) 조건을 미리 만들어두면 재활용가능
(3-1)
//4-2.
@Test
@DisplayName("test")
public void queryDslTest2() {
BooleanBuilder booleanbuilder = new BooleanBuilder(); //booleanBuilder.and : 조건절(WHERE)
QItem qitem = QItem.item;
String itemDetail = "상품";
int price = 400000;
String itemSellStat = "SELL"; //조건 설정하는 부분
booleanbuilder.and(qitem.itemDetail.like("%"+itemDetail+"%"));
booleanbuilder.and(qitem.price.gt(price)); //gt는 greaterThan
System.out.println(ItemSellstatus.SELL);
if(itemSellStat.equals(ItemSellstatus.SELL)) {
booleanbuilder.and(qitem.itemSellStatus.eq(ItemSellstatus.SELL));
}
//page 기능
Pageable pageable = PageRequest.of(0, 5);
Page<Item> itemPagingResult = itemRepository.findAll(booleanbuilder, pageable);
System.out.println("total elements : "+ itemPagingResult.getTotalElements());
List<Item> resultItemList = itemPagingResult.getContent();
for(Item resultItem: resultItemList) {
System.out.println(resultItem.toString());
}
}
(3-2) 제이유닛 결과
total elements : 20 Item(id=13, itemNm=상품번호0, price=500000, stockNumber=0, itemDetail=상품설명0, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.840744, updateTime=2022-03-21T14:25:17.840744) Item(id=14, itemNm=상품번호1, price=500000, stockNumber=1, itemDetail=상품설명1, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.873729, updateTime=2022-03-21T14:25:17.873729) Item(id=15, itemNm=상품번호2, price=500000, stockNumber=2, itemDetail=상품설명2, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.884724, updateTime=2022-03-21T14:25:17.884724) Item(id=16, itemNm=상품번호3, price=500000, stockNumber=3, itemDetail=상품설명3, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.894720, updateTime=2022-03-21T14:25:17.894720) Item(id=17, itemNm=상품번호4, price=500000, stockNumber=4, itemDetail=상품설명4, itemSellStatus=SELL, regTime=2022-03-21T14:25:17.907714, updateTime=2022-03-21T14:25:17.907714) |
- Total
- Today
- Yesterday
- html layout
- selcetor
- scanner
- 미디어 태그
- 기본선택자
- Java
- initialized
- html
- CascadingStyleSheet
- html pre
- A%B
- html input type
- empty-cell
- css
- border-spacing
- 변수
- caption-side
- ScriptTag
- BAEKJOON
- improt
- html base tag
- JavaScript
- input type 종류
- 외부구성요소
- html atrribute
- html a tag
- 스크립태그
- text formatting
- typeof
- 입력양식
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |