Wanna be Brilliant Full-Stack Developer

2/15 SpringBoot QLRM 라이브러리로 DTO 매핑하기 본문

Back-End/Spring Boot

2/15 SpringBoot QLRM 라이브러리로 DTO 매핑하기

Flashpacker 2022. 2. 15. 20:51


 

SELECT u.id, u.username, u.profileImageUrl,
(SELECT true FROM subscribe WHERE fromUserId = 1 AND toUserId = u.id) subscribeState,
(1=u.id) equalUserState
FROM user u INNER JOIN subscribe s
ON u.id = s.toUserId 
WHERE s.fromUserId = 2;

이쿼리를 if문을 넣어서 조금만 수정을 해보려고하는데 

SELECT u.id, u.username, u.profileImageUrl,
if ((SELECT 1 FROM subscribe WHERE fromUserId = 1 AND toUserId = u.id), 1, 0) subscribeState,
if((1=u.id), 1, 0) equalUserState
FROM user u INNER JOIN subscribe s
ON u.id = s.toUserId 
WHERE s.fromUserId = 2;

 

Repository는 EntityManager를 구현해서 만들어져 있는 구현체  직접 em으로 구현해서 SubscribeService에 작성해보려고하는데! 

package com.cos.photogramstart.service;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.qlrm.mapper.JpaResultMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cos.photogramstart.domain.subscribe.SubscribeRepository;
import com.cos.photogramstart.handler.ex.CustomApiException;
import com.cos.photogramstart.web.dto.subscribe.SubscribeDto;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Service
public class SubscribeService {
	
	private final SubscribeRepository subscribeRepository;
	private final EntityManager em; // Repository는 EntityManager를 구현해서 만들어져 있는 구현체 
	

	@Transactional(readOnly = true)
	public List<SubscribeDto> 구독리스트(int principalId, int pageUserId) {
		
		//쿼리 준비
		StringBuffer sb = new StringBuffer();
		sb.append("SELECT u.id, u.username, u.profileImageUrl, ");
		sb.append("if ((SELECT 1 FROM subscribe WHERE fromUserId = ? AND toUserId = u.id), 1, 0) subscribeState, ");
		sb.append("if ((?=u.id), 1, 0) equalUserState ");
		sb.append("FROM user u INNER JOIN subscribe s ");
		sb.append("ON u.id = s.toUserId  ");
		sb.append("WHERE s.fromUserId = ?"); // 세미콜론 첨부하면 안됨
		
		//물음표 principalId
		//물음표 principalId
		// 마지막 물음표 pageUserId
		
		// 쿼리 완성
		Query query = em.createNativeQuery(sb.toString())
				.setParameter(1, principalId)
				.setParameter(2, principalId)
				.setParameter(3, pageUserId);
		
		//쿼리 실행
		JpaResultMapper result = new JpaResultMapper();
		List<SubscribeDto> subscribeDtos =	result.list(query, SubscribeDto.class);
		
		return subscribeDtos;
	}
	
	@Transactional
	public void 구독하기(int fromUserId, int toUserId) {
		try {
			subscribeRepository.mSubscribe(fromUserId, toUserId);
		} catch (Exception e) {
			throw new CustomApiException("이미 구독을 하였습니다.");
		}
	
		
	}
	@Transactional
	public void 구독취소하기(int fromUserId, int toUserId) {
		subscribeRepository.mUnSubscribe(fromUserId, toUserId);
	
	}
}

JpaResultMapper result = new JpaResultMapper(); 이거를 보면 import된것을 보면 

import org.qlrm.mapper.JpaResultMapper; : qlrm 이라고 되어있는데 qlrm은 스프링부트에서 제공하는 라이브러리가 아니다! 

그래서 pom.xml에 

<!-- qlrm -->
<dependency>
<groupId>org.qlrm</groupId>
<artifactId>qlrm</artifactId>
<version>2.1.1</version>
</dependency> 이렇게 등록을 해놓은 상태이다

qlrm이 무엇인가?데이터베이스에서 리절트 된 결과를 자바클래스 매핑 해주는 라이브러리이다.  이라이브러리가 있으면 굉장히 편하게DTO를 받을 수 있다. 이것이 없으면 받기가 굉장히 힘들다!리턴 받을 결과가 모델이랑 똑같이 생긴 모델의 결과가 아닌 어떤 새로운 데이터의 조합이면 DTO로 받아야한다.JPA 레파지토리를 사용하지 못한다. SubscribeRepository는 결과가 int값이 나와서 가능한데 내가 select해서 어떤 결과를 맘대로 쓰려면 못받아낸다.

PostMan으로 /api/user/2/subscribe 뒤 결과

이정보를 받아서 내가 구독정보를 클릭했을때 구독정보에 뿌리기만 하면된다! 


이제 API는 다 만들어졌으니까 ResponseEntity만 호출하면된다!  호출하는 타이밍이 언젠지만 알아내면 되는데 

profile.jsp에서 구독정보를 클릭할때 SubscribeInfoModalOpen 실행이 되는데  profile.js에 가서 

// (2) 구독자 정보  모달 보기
function subscribeInfoModalOpen() {
	$(".modal-subscribe").css("display", "flex");
}

function getSubscribeModalItem() {

}

이부분을 수정해야하는데! 머가 필요할까요 , 현재 페이지의 아이디를 받아와야한다!

// (2) 구독자 정보  모달 보기
function subscribeInfoModalOpen(pageUserId) {
	alert(pageUserId);
	$(".modal-subscribe").css("display", "flex");
}

function getSubscribeModalItem() {

}
	<li><a href="javascript:subscribeInfoModalOpen(${dto.user.id});"> 구독정보<span>${dto.subscribeCount }</span>
// (2) 구독자 정보  모달 보기
function subscribeInfoModalOpen(pageUserId) {
	$(".modal-subscribe").css("display", "flex");
	
	$.ajax({
		url: `/api/user/${pageUserId}/subscribe`,
		dataType: "json"
	}).done(res=>{
		console.log(res.data);
	}).fail(error=>{
		console.log("구독정보 불러오기 오류",error);
	});
	
}

/**
  1. 유저 프로파일 페이지
  (1) 유저 프로파일 페이지 구독하기, 구독취소
  (2) 구독자 정보 모달 보기
  (3) 구독자 정보 모달에서 구독하기, 구독취소
  (4) 유저 프로필 사진 변경
  (5) 사용자 정보 메뉴 열기 닫기
  (6) 사용자 정보(회원정보, 로그아웃, 닫기) 모달
  (7) 사용자 프로파일 이미지 메뉴(사진업로드, 취소) 모달 
  (8) 구독자 정보 모달 닫기
 */

// (1) 유저 프로파일 페이지 구독하기, 구독취소
function toggleSubscribe(toUserId, obj) {
	if ($(obj).text() === "구독취소") {
		
		$.ajax({
			type: "delete",
			url: "/api/subscribe/"+toUserId,
			dataType: "json"
		}).done(res => {
			 $(obj).text("구독하기");
			 $(obj).toggleClass("blue");
		}).fail(error => {
			console.log("구독취소실패", error);
		});
	} else {
			
	$.ajax({
			type: "post",
			url: "/api/subscribe/"+toUserId,
			dataType: "json"
		}).done(res => {
			 $(obj).text("구독취소");
			 $(obj).toggleClass("blue");
		}).fail(error => {
			console.log("구독하기실패", error);
		});
	}
}

// (2) 구독자 정보  모달 보기
function subscribeInfoModalOpen(pageUserId) {
	$(".modal-subscribe").css("display", "flex");
	
	$.ajax({
		url: `/api/user/${pageUserId}/subscribe`,
		dataType: "json"
	}).done(res=> {
		console.log(res.data);
		
		res.data.forEach((u)=>{
			let item = getSubscribeModalItem(u);
			$("#subscribeModalList").append(item);
		});
	}).fail(error=> {
		console.log("구독정보 불러오기 오류",error);
	});
	
}

function getSubscribeModalItem(u) {
 	let item=` <div class="subscribe__item" id="subscribeModalItem-${u.id}">
<div class="subscribe__img">
	<img src="/upload/${u.profileImageUrl}" onerror="this.src='/images/person.jpeg'" />
</div>
<div class="subscribe__text">
	<h2>${u.username}</h2>
</div>
<div class="subscribe__btn">`;

	if(!u.equalUserState) {	//동일 유저가 아닐 떄 버튼이 만들어 져야함
		if(u.subscribeState) { // 구독한 상태
				item += `	<button class="cta blue" onclick="toggleSubscribeModal(this)">구독취소</button>`;
	}else { // 구독안한 상태
			item += `	<button class="cta" onclick="toggleSubscribeModal(this)">구독하기</button>`;
	}
	}
	item += `
	</div>
</div>`;
 	
 	console.log(item);
 	return item;
}


// (3) 구독자 정보 모달에서 구독하기, 구독취소
function toggleSubscribeModal(obj) {
	if ($(obj).text() === "구독취소") {
		$(obj).text("구독하기");
		$(obj).toggleClass("blue");
	} else {
		$(obj).text("구독취소");
		$(obj).toggleClass("blue");
	}
}

// (4) 유저 프로파일 사진 변경 (완)
function profileImageUpload() {
	$("#userProfileImageInput").click();

	$("#userProfileImageInput").on("change", (e) => {
		let f = e.target.files[0];

		if (!f.type.match("image.*")) {
			alert("이미지를 등록해야 합니다.");
			return;
		}

		// 사진 전송 성공시 이미지 변경
		let reader = new FileReader();
		reader.onload = (e) => {
			$("#userProfileImage").attr("src", e.target.result);
		}
		reader.readAsDataURL(f); // 이 코드 실행시 reader.onload 실행됨.
	});
}


// (5) 사용자 정보 메뉴 열기 닫기
function popup(obj) {
	$(obj).css("display", "flex");
}

function closePopup(obj) {
	$(obj).css("display", "none");
}


// (6) 사용자 정보(회원정보, 로그아웃, 닫기) 모달
function modalInfo() {
	$(".modal-info").css("display", "none");
}

// (7) 사용자 프로파일 이미지 메뉴(사진업로드, 취소) 모달
function modalImage() {
	$(".modal-image").css("display", "none");
}

// (8) 구독자 정보 모달 닫기
function modalClose() {
	$(".modal-subscribe").css("display", "none");
	location.reload();
}