Wanna be Brilliant Full-Stack Developer

2/15 SpringBoot 구독정보 완성하기 #1 본문

Back-End/Spring Boot

2/15 SpringBoot 구독정보 완성하기 #1

Flashpacker 2022. 2. 15. 16:47


목표


 

구독자수 랜더링하는것을 해보려고한다! 

내 구독자수 확인과 상대방 user에게 갔을떄 구독할떄와 취소할때 구독자수 랜더링도 적용해보려고한다

 

처음에는 UserProfileDto에 두가지를 추가해야한다!

package com.cos.photogramstart.web.dto.user;




import com.cos.photogramstart.domain.user.User;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class UserProfileDto {
	private boolean pageOwnerState;
	private int imageCount;
	private boolean subscribeState;
	private int subscribeCount;
	private User user;
}

구독자수를 알아보기위해서는 쿼리를 작성해봐야한다!

1번이 2번 구독한 상태에서 2번 페이지를 가게되면 이미 구독을 한상태이기 떄문에 구독취소인 상태로 보여야한다!

구독정보 또한 로그인 한사람의 구독정보가 아니라 2번 페이지 의 구독정보이기 떄문에 2번인 사람에 대한 몇명이 구독을 했는지 가 나와야한다! 

 

-- 구 독 수
SELECT COUNT(*) FROM subscribe WHERE fromUserId = 3;

-- 구독 여부( ssar로 로그인, cos페이지로감
SELECT COUNT(*) FROM subscribe WHERE fromUserId = 1 AND toUserId = 2;

 

이 두가지 쿼리로 만들어볼수 있다!

 

SubscribeRepository에 가서

package com.cos.photogramstart.domain.subscribe;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

public interface SubscribeRepository extends JpaRepository<Subscribe, Integer> {
	
	@Modifying // INSERT, DELETE, UPDATE를 네이티브 쿼리로 작성하려면 해당 어노테이션 필요!!
	@Query(value = "INSERT INTO subscribe(fromUserId, toUserId, createDate) VALUES(:fromUserId, :toUserId, now())", nativeQuery = true)
	void mSubscribe(int fromUserId, int toUserId); 
	
	@Modifying
	@Query(value = "DELETE FROM subscribe WHERE fromUserId = :fromUserId AND toUserId = :toUserId", nativeQuery = true)
	void mUnSubscribe(int fromUserId, int toUserId);
	
	@Query(value ="SELECT COUNT(*) FROM subscribe WHERE fromUserId = :principalId  AND toUserId = :pageUserId", nativeQuery = true)
	int mSubscribeState(int principalId, int pageUserId);
	
	@Query(value ="SELECt COUNT(*) FROM subscribe WHERE fromUserId = :pageUserId", nativeQuery = true)
	int mSubscribeCount(int pageUserId);
	
}

principalId는 로그인한 아이디! , pageUserId: 그 페이지 아이디! 

구독수는 그 페이지 아이디만 있으면된다! 

이들을 실행하기 위해서는 유저컨트롤러에서 회원프로필로 갈때 저 정보를 같이 UserProfileDto에 담아갈것이기 때문에 

회원프로필에서 UserService에서 

package com.cos.photogramstart.service;

import java.util.function.Supplier;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.cos.photogramstart.domain.subscribe.SubscribeRepository;
import com.cos.photogramstart.domain.user.User;
import com.cos.photogramstart.domain.user.UserRepository;
import com.cos.photogramstart.handler.ex.CustomException;
import com.cos.photogramstart.handler.ex.CustomValidationApiException;
import com.cos.photogramstart.web.dto.user.UserProfileDto;

import lombok.RequiredArgsConstructor;


@RequiredArgsConstructor
@Service
public class UserService {

	private final UserRepository userRepository;
	private final SubscribeRepository subscribeRepository;
	private final BCryptPasswordEncoder bCryptPasswordEncoder;
	
	@Transactional(readOnly = true)
	public UserProfileDto 회원프로필(int pageUserId, int principalId) {
		UserProfileDto dto = new UserProfileDto();
		
		//SELECT * FROM image WHERE userId = :userId;
		User userEntity = userRepository.findById(pageUserId).orElseThrow(()-> {
			throw new CustomException("해당 프로필 페이지는 없는 페이지입니다.");
		});
		
		dto.setUser(userEntity);
		dto.setPageOwnerState(pageUserId == principalId);
		dto.setImageCount(userEntity.getImages().size());
		
		int subscribeState = subscribeRepository.mSubscribeState(principalId, pageUserId);
		int subscribeCount = subscribeRepository.mSubscribeCount(pageUserId);
		
		dto.setSubscribeState(subscribeState == 1);
		dto.setSubscribeCount(subscribeCount);
		
		return dto;
	}
	
	
	
	@Transactional
	public User 회원수정(int id, User user ) {
		//1. 영속화
		//1. 무조건 찾았다. 걱정마 get() 2. 못찾았어 익섹션 발통시킬때 orElseThrow()
		User userEntity = userRepository.findById(id).orElseThrow(() -> {return new CustomValidationApiException("찾을 수 없는 id입니다."); });
			
	
	
		//2. 영속화된 오브젝트를 수정 - 수정이 완료되면 더티체킹 ( 업데이트 완료) 
		userEntity.setName(user.getName());
		
		String rawPassword = user.getPassword();
		String encPassword = bCryptPasswordEncoder.encode(rawPassword);
		
		userEntity.setPassword(encPassword);
		userEntity.setBio(user.getBio());
		userEntity.setWebsite(user.getWebsite());
		userEntity.setPhone(user.getPhone());
		userEntity.setGender(user.getGender());
		return userEntity;
		
	}//더티체킹이 일어나서 업데이트가 완료됨. 
}

dto를 만드는것이 굉장히 효과적이다. 페이지에서 할것이 없고 페이지에서는 출력만 하면된다!

 

이제 profile.jsp로 가서 

<li><a href="javascript:subscribeInfoModalOpen();"> 구독정보<span>${dto.subscribeCount }</span>

 

<c:choose>
<c:when test="${dto.pageOwnerState}">
<button class="cta" onclick="location.href='/image/upload'">사진등록</button>
</c:when>
<c:otherwise>
<c:choose>
<c:when test="${dto.subscribeState}" >
<button class="cta blue" onclick="toggleSubscribe(this)">구독취소</button>
</c:when>
<c:otherwise>
<button class="cta" onclick="toggleSubscribe(this)">구독하기</button>
</c:otherwise>
</c:choose>
</c:otherwise>
</c:choose>

cta가 붙으면 버튼 디자인만 붙은건데 blue라고 하면 파란색상이 나오는데 그것은 구독취소! 

왜냐하면 구독 한상태의 페이지에갔을떄는 구독취소버튼만 보이면 되기떄문에!

2번유저
3번유저