[Photogram] 해시태그 기능 추가

2023. 1. 3. 15:38·🚗 Backend Toy Project/Photogram
  • 게시글 업로드 시 해시태그를 추가할 수 있도록 구현해보았습니다.
  • 추가된 해시태그는 이후 게시글 하단에 표시되게 되며 이후에 해당 태그를 이용하여 태그 검색 기능도 추가해볼 예정입니다.


📝 upload.jsp

  • 아래 코드는 이미지 파일 업로드를 위한 폼 태그를 구현한 부분으로, 기존에 사용하던 코드입니다.
<!--사진업로드 Form-->
<form class="upload-form" action="/image" method="POST" enctype="multipart/form-data">
    <input  type="file" name="file" onchange="imageChoose(this)"/>
    <div class="upload-img">
        <img src="/images/person.jpeg" alt="" id="imageUploadPreview" />
    </div>

    <!--사진설명 + 업로드버튼-->
    <div class="upload-form-detail">
        <input type="text" placeholder="사진을 설명해보세요!" name="caption">

        <!-- 해시 태그 -->
        <div class="upload-form-hashtag" align="center">
            <input type="text" placeholder="해시태그를 추가해보세요!" id="hashtag" name="hashtag">
            <button type="button" class="cta blue" onclick="addHashtag()">추가</button>
        </div>

        <!-- 추가한 해시 태그 리스트 -->
        <div class="hashtagList" id="hashtagList">
        </div>
        <!-- 해시 태그 end -->

        <button class="cta blue">업로드</button>
    </div>
    <!--사진설명end-->

</form>
<!--사진업로드 Form-->
  • 우선 위 코드를 아래와 같이 수정해주었습니다.
  • 이는 이후 추가될 해시태그 목록들을 FormData 객체에 저장하여 ajax를 통해 서버로 전송하기 위함입니다.
<!--사진업로드 Form-->
<form id="uploadForm" class="upload-form">
    <input  type="file" name="file" onchange="imageChoose(this)"/>
    <div class="upload-img">
        <img src="/images/person.jpeg" alt="" id="imageUploadPreview" />
    </div>

    <!--사진설명 + 업로드버튼-->
    <div class="upload-form-detail">
        <input type="text" placeholder="사진을 설명해보세요!" name="caption">

        <!-- 해시 태그 -->
        <div class="upload-form-hashtag" align="center">
            <input type="text" placeholder="해시태그를 추가해보세요!" id="hashtag" name="hashtag">
            <button type="button" class="cta blue" onclick="addHashtag()">추가</button>
        </div>

        <!-- 추가한 해시 태그 리스트 -->
        <div class="hashtagList" id="hashtagList">
        </div>
        <!-- 해시 태그 end -->

        <button type="button" id="uploadBtn" class="cta blue">업로드</button>
    </div>
    <!--사진설명end-->

</form>
<!--사진업로드 Form-->

📝 upload.js

  • ajax 요청과 해시태그 추가, 삭제 로직은 아래와 같이 구현하였습니다.
$(function() {
	$("#uploadBtn").on("click", function() {
		upload();
	});
});

function upload() {
	let form = $("#uploadForm")[0];
	let formData = new FormData(form);
	
	//추가된 해시태그를 모두 FormData 객체에 저장하기
	let hashtagList = document.getElementsByClassName("hashtag-value");
	for(let i = 0; i < hashtagList.length; i++) {
		formData.append("hashtagList[" + i + "]", hashtagList[i].innerText);
	}
	
	$.ajax({
		type: "POST",
		url: `/api/upload`,
		data: formData,
		contentType: false, //false 로 선언 시 content-type 헤더가 multipart/form-data로 전송되게 함
		processData: false  //false로 선언 시 formData를 string으로 변환하지 않음
	}).done(resp => {
		console.log(resp);
		
		location.href=`http://localhost:8080/user/${resp.data}`
	}).fail(error => {
		console.log(error);
	});
}

// 해시 태그 추가, 삭제 로직
function addHashtag() {
	let hashtag = $("#hashtag").val();
	let item = getHashtagItem(hashtag);
	$("#hashtagList").append(item);
}

function removeHashtag(hashtag) {
	document.getElementById(hashtag).remove();
}

function getHashtagItem(hashtag) {
	let item =
		`<div class="hashtag" id="${hashtag}">
			<span class="hashtag-value">#${hashtag}</span>
			<button type="button" onclick="removeHashtag('${hashtag}')">×</button>
		</div>`
	
	return item;
}

📝 ImageApiController

  • 이후 위 요청을 받는 컨트롤러 함수를 아래와 같이 구현해주었습니다.
package com.cos.photogram.web.api;

...

@RequiredArgsConstructor
@RestController
public class ImageApiController {

	private final ImageService imageService;
	
	/* 이미지 업로드 */
	@PostMapping("/api/upload")
	public ResponseEntity<?> imageUpload(ImageUploadDto imageUploadDto, 
			@AuthenticationPrincipal PrincipalDetails principalDetails) {
		if(imageUploadDto.getFile().isEmpty()) {
			throw new CustomValidationException("이미지가 첨부되지 않았습니다.", null);
		}

		imageService.upload(imageUploadDto, principalDetails);
		
		return new ResponseEntity<>(new CMRespDto<>(1, "이미지 업로드 성공", principalDetails.getUser().getId()), HttpStatus.OK);
	}
	
	...
}
  • FormData 객체를 전달받기 위한 DTO는 아래와 같이 구현되어 있습니다.
package com.cos.photogram.web.dto.image;

...

@Data
public class ImageUploadDto {

	private MultipartFile file;
	private String caption;
	private List<String> hashtagList;
	
	public Image toEntity(User user, String post_image_url) {
		String hashtag = "";
		for(String str : hashtagList) {
			hashtag += str + ",";
		}
		
		return Image.builder()
				.user(user)
				.post_image_url(post_image_url)
				.caption(caption)
				.hashtag(hashtag)
				.build();
	}
}

📝 ImageService

  • 서비스 로직은 아래와 같습니다.
package com.cos.photogram.service;

...

@RequiredArgsConstructor
@Service
public class ImageService {

	private final ImageRepository imageRepository;
	
	/* 이미지 업로드 */
	@Transactional
	public void upload(ImageUploadDto imageUploadDto, PrincipalDetails principalDetails) {
		UUID uuid = UUID.randomUUID();
		String imageFileName = uuid + "_" + imageUploadDto.getFile().getOriginalFilename();
		Path imageFilePath = Paths.get(uploadFolder + imageFileName);
		
		try {
			Files.write(imageFilePath, imageUploadDto.getFile().getBytes());
		} catch(Exception e) {
			e.printStackTrace();
		}
		
		Image image = imageUploadDto.toEntity(principalDetails.getUser(), imageFileName);
		imageRepository.save(image);
	}
	
	...
}

📝 Image

  • Image 개체에는 DB에 해시태그를 저장하기 위한 문자열 형 속성과 이후 이를 파싱하여 View에서 사용되어질 리스트형 필드를 추가해주었습니다.
package com.cos.photogram.domain.image;

...

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Image {

	...
	
	private String hashtag;
	
	@Transient
	private List<String> hashtagList;
	
	...
}
  • 문자열 -> 배열 파싱은 아래와 같이 구현하였습니다.
/* 스토리 페이지 */
@Transactional(readOnly = true)
public Page<Image> story(Long principalId, Pageable pageable) {
    Page<Image> images = imageRepository.story(principalId, pageable);

    images.forEach((image) -> {
        ...
        
        //해시태그 문자열 -> 해시태그 리스트
        image.setHashtagList(Arrays.asList(image.getHashtag().split(",")));
    });

    return images;
}

📝 story.js

  • 이후 View 페이지에서는 아래와 같이 해시태그 리스트를 이용하여 해시태그 목록을 출력해줍니다.
image.hashtagList.forEach((hashtag) => {
    item += `<div class="sl__item__contents__tag">${hashtag}</div>`
});

 

GitHub - Daegwon-Kim/SpringBoot-Photogram

Contribute to Daegwon-Kim/SpringBoot-Photogram development by creating an account on GitHub.

github.com

 

저작자표시 (새창열림)

'🚗 Backend Toy Project > Photogram' 카테고리의 다른 글

[Photogram] 연관 검색어  (0) 2023.03.05
[Photogram] 실시간 알림  (0) 2023.03.02
[Photogram] 로그인 실패 처리  (0) 2022.12.25
[Photogram] 검색 기능 구현  (0) 2022.12.22
[Photogram] OAuth2 페이스북 로그인  (0) 2022.07.19
'🚗 Backend Toy Project/Photogram' 카테고리의 다른 글
  • [Photogram] 연관 검색어
  • [Photogram] 실시간 알림
  • [Photogram] 로그인 실패 처리
  • [Photogram] 검색 기능 구현
Baeg-won
Baeg-won
  • Baeg-won
    좋았다면 추억이고 나빴다면 경험이다.
    Baeg-won
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 🍃 Spring, Spring Boot
        • 스프링 프레임워크 기초
        • 스프링 핵심 원리 - 기본편
        • 자바 ORM 표준 JPA 프로그래밍 - 기본편
        • 스프링 MVC
        • 실전! 스프링 부트와 JPA 활용1 - 웹 애플리..
      • 🥑 Web Technoloy
      • 🚗 Backend Toy Project
        • 스프링 부트 게시판
        • Photogram
        • Baeg-won Clothing Gallery
      • 🥇 Problem Solving
        • Breadth-First Search
        • Depth-First Search
        • Backtracking
        • Simulation
        • Two-pointer
        • Binary Search
        • Greedy
        • Dynamic Programming
        • Minimum Spanning Tree
        • Dijkstra
        • Floyd warshall
      • ☕ Java
        • 명품 자바 에센셜
        • Applications
      • 🍦 JavaScript
        • JavaScript 기초
      • 🐧 Linux
        • 이것이 리눅스다(CentOS 8)
      • 📟 Database
        • 혼자 공부하는 SQL
      • 🧬 Data Structure
      • 🎬 HTML
      • 🎤 Tech Interview
      • 📌 etc
        • Unity 2D Raising Jelly Game
        • C++
        • 영어 쉐도잉
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Baeg-won
[Photogram] 해시태그 기능 추가
상단으로

티스토리툴바