본문 바로가기
Back-End/Spring

Spring) 게시물 찜하기 기능 구현 - 데이터 전달 (1/2)

by 어렵다어려웡 2021. 3. 30.

 


 

환경) sts3 , MySQL , MyBatis

 

게시물을 조회하고 해당 게시물을 저장할 수 있는 찜하기 기능을 구현하였다.

 

시큐리티를 적용시킬 경우 테스트하는데 복잡하기 떄문에 우선 임의로 로그인 사용자를 지정해서 하였다.

 

해당 기능의 로직은 다음과 같다.

1. 상세페이지의 찜하기 버튼을 클릭한다.

 -> 나는 fontAwesome에 있는 아이콘을 이용해서 만들었다.

 

2-1. 로그인한 사용자가 해당 게시물을 이미 찜한 상태라면 alert창을 생성

2-2 찜하지 않은 상태라면 confirm을 통해 찜리스트 페이지로 들어갈지 말지 결정.

 

3. 찜리스트 페이지에 찜한 게시물의 정보가 출력된다.

 

* 구현코드 및 사진

1. DB

간단하게 사용자(userid)와 게시물번호(Cno - [PK])만 받아서 설계하였다.

정답은 아니겠지만 일단 내가 찜한 게시물의 정보를 얻어와야하기 떄문에 게시물의 정보를 가진 데이터 중 

기본키인 cno 를 가지고 얻어오는 것이 맞다고 판단,

 

정규화의 성격에도 알맞기 때문이다.

 

2. VO & Mapper (XML)

@Data
@AllArgsConstructor
@NoArgsConstructor
public class LikeVO {

	private String userid;
	private Long cno;
	
}

public interface LikeMapper {
	// 찜하기 ( 추가 )
	public int insert(LikeVO vo);
	// 찜 목록 확인
	public List<LikeVO> getLikeListByUserid(String userid);
	// 찜 목록 1개 삭제
	public boolean delete(@Param("cno")Long cno, @Param("userid")String userid);
	// 게시물삭제시 전체삭제
	public boolean deleteAllByCno(Long cno);
	// 이미 찜한 게시물인지 조회
	public LikeVO getByCnoWithUserid(@Param("vo")LikeVO vo);
}
<mapper namespace="com.cs.mapper.LikeMapper">
	
	<resultMap type="com.cs.domain.LikeVO" id="likeMap">
		<result property="userid" column="userid"/>
		<result property="cno" column="like_cno"/>
	</resultMap>

	<insert id="insert" parameterType="com.cs.domain.LikeVO">
		insert into tbl_like ( userid , like_cno ) value ( #{userid} , #{cno} )
	</insert>
	
	<select id="getLikeListByUserid" resultMap="likeMap" resultType="com.cs.domain.LikeVO">
		select * from tbl_like where userid = #{userid}
	</select>
	
	<delete id="delete">
		delete from tbl_like where userid = #{userid} and like_cno = #{cno}
	</delete>
	
	<delete id="deleteAllByCno">
		delete from tbl_like where like_cno = #{cno}
	</delete>
 
 	<select id="getByCnoWithUserid" resultMap="likeMap" resultType="com.cs.domain.LikeVO">
 		select * from tbl_like where like_cno = #{vo.cno} and userid = #{vo.userid}
 	</select>

</mapper>

LikeVO의 property들과 DB 테이블의 column의 이름이 다르기 때문에 resultMap으로 해당 필드들을 매핑시켜준다.

나머지 설명은 어떤식으로 구성된 것인지 이해하실거같으니 패스.

 

 

3. Service 계층

public interface LikeService {

	public int register(LikeVO vo);
	
	public List<ClothesVO> getLikeListByUserid(String userid);
	
	public boolean remove(Long cno, String userid);
	
	public LikeVO getByCnoWithUserid(LikeVO vo);
}
@Service
@Log4j
@RequiredArgsConstructor
public class LikeServiceImpl implements LikeService {
	
	private final LikeMapper likeMapper;
	
	private final ClothesMapper clothesMapper;

	private final ClothesAttachMapper clothesAttachMapper;
	
	@Transactional
	@Override
	public List<ClothesVO> getLikeListByUserid(String userid) {
		// 1. 사용자가 찜한 목록을 찾는다
		List<LikeVO> likeList = likeMapper.getLikeListByUserid(userid);
		// 2. 찜한 게시물의 정보를 담을 그릇을 만든다.
		List<ClothesVO> clothesList = new ArrayList<ClothesVO>();
        // 3. 찜한 목록이 없으면 null을 반환.
		if(Objects.isNull(likeList)) {
			return null;
		}
        // 4. 찜한 목록을 DB를 하나씩 조회한다.
		likeList.forEach(i -> {
         //	4.1 해당 사용자가 찜한 게시물의 번호로 게시물과 첨부파일 정보를 조회한다.
			ClothesVO vo = clothesMapper.read(i.getCno());
			List<ClothesAttachVO> attachList = clothesAttachMapper.findByCno(i.getCno());
			// 4.2 첨부파일이 없으면 그냥 add
			if(Objects.isNull(attachList) || attachList.size() == 0) {
				log.warn("No have Attach By Cno : " + i.getCno());
			} else {
            // 4.3 첨부파일이 있으면 대표이미지의 경로를 썸네일Url로 설정
				ClothesAttachVO attachVO = clothesAttachMapper.findByCno(i.getCno()).get(0);
			
				vo.setThumbnailUrl(makeThumbnailURL(attachVO));
				log.warn("make ThumbnailUrl");
			}
			
			clothesList.add(vo);
		});
		return clothesList;
	}
	// 4.4 썸네일 생성
	private String makeThumbnailURL(ClothesAttachVO attachVO) {
		String url = null;
		
		try  {
			url = URLEncoder.encode(attachVO.getUploadPath() + "/s_" 
		+ attachVO.getUuid() + "_" + attachVO.getFileName(),"UTF-8");
			
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return url;
	}
}

 다른 메서드들은 일단 생략하고 getLikeListByUserid 메서드가 가장 중요하고 로직이 추가되는 부분이기 때문에

설명을 해보면

특정 사용자(admin44)가 3개의 게시물(1,2,3)을 찜했다고 했을 떄 Like 테이블 DB에는 3개의 Row가 저장돼있다.

각 row는 admin-1 , admin-2 , admin-3 이 되어있으므로 cno 칼럼의 값을 뽑아내서

 

해당 번호의 게시물의 정보와 첨부파일을 찾아내서 반환할 List 컬렉션에 추가하는 형태이다(4.4 - 4.5번 작업)

 

4. 컨트롤러 계층

 

해당 서비스계층에서 사용한 getLikeListByUserid를 통해서 반환되는 List를 화면으로 전송합니다.

이때 Model을 사용해서 데이터를 넘겨줘도 되며 

위 코드처럼 Ajax통신을 사용하기위해서 @ResponseBody를 사용해 넘겨줘도 된다.

 

5. 결과

 

 

다음 포스팅에서 화면단 구성에 대한 글을 작성.