본문 바로가기
프로젝트/Kimstagram

[내멋대로 만드는 Kimstagram] 4. 글쓰기 구현하기

by kim-dev 2024. 1. 16.
반응형

대망의 글쓰기를 구현할 시간이 다가왔다.
사실 프로필 화면을 먼저 작성하긴 했는데, 이건 프론트엔드에 가깝기도 하고...
또 글쓰기가 먼저 구현 되어야 프로필을 얼추 만들 수 있을 것 같아서 도중에 그만두고 글쓰기를 먼저 구현했다.


우선 게시물 작성 화면은 위와 같다.
뭐... 보면 알 수 있겠지만 굉장히 간단하게 만들었다.
사진 업로드는 <input type=file>을 이용해서 MultipartFile로 업로드되게 만들었다. 물론 이미지만 올릴 수 있게 해야 하는데 그거까지는 로직을 짜기 귀찮아서(...) 생략했다. 물론 이미지는 최대 10개 까지 올릴 수 있다.

 

function previewImages(event) {
    var preview = document.getElementById('imageBox');
    var files = event.target.files;

    if (files.length + images.length > 10) {
        alert('이미지는 최대 10개까지 업로드 가능합니다.');
        event.target.value = '';
        return;
    }

    // 업로드될 때마다 비우기
    preview.innerHTML = '';

    for(var i = 0; i < files.length; i++) {
        var file = files[i];
        oriImages.push(file);

        var reader = new FileReader();

        reader.onload = function (e) {
            var image = new Image();
            image.src = e.target.result;
            image.className = 'uploadedImage';
            images.push(image);

            // 이미지 개수 업데이트
            document.getElementById('totalImages').innerText = images.length;

            showImage(currentIndex);
        };
        reader.readAsDataURL(file);
    }
}

이미지 미리보기 로직은 대략 이렇게 되어있는데, showImage()나 showNext(), showPrev() 등은 생략한다.

여하튼 이렇게 이미지를 업로드하고 커멘트를 작성한 후 업로드 버튼을 누르면, ajax 요청을 통해 서버로 데이터가 전송된다.
여기서 막혔던 점은, 단순히 이미지와 커멘트를 data라는 변수에 담아 JSON으로 전송하면, 서버에서는 이미지를 제대로 받을 수 없다는 것이었다. JSON은 텍스트 기반 데이터 전송 양식이라서, 이미지와 같은 이진 데이터는 전송할 수 없다는 것이다.
그래서 찾아본 끝에, FormData()를 활용하여 이미지를 보내면 HTTP의 multipart/form-data 형식으로 전송되어 이미지를 온전히 전송할 수 있다는 것이었다. 그래서 결국 내가 작성한 업로드 로직은 아래와 같다.

function postUpload() {
    let data = new FormData();
    data.append('userId', principal.id);
    data.append('comment', document.getElementById('contentBox').value);

    for (let i=0; i<oriImages.length; i++) {
        data.append('pictures', oriImages[i], 'image'+i);
    }

    $.ajax({
        type: "POST",
        url: "/upload",
        data: data,
        contentType: false,
        processData: false
    }).done(function (resp){
        alert("글이 작성되었습니다.");
        location.href = "/index";
    }).fail(function(error){
        alert(JSON.stringify(error));
    });
}

 

이렇게 POST 요청이 ajax를 통해 날아오면, 컨트롤러에서는 변수들을 받아서 업로드 로직을 실행한다.

@PostMapping("/upload")
public int upload(@RequestParam("userId") int userId,
                  @RequestParam("comment") String comment,
                  @RequestPart("pictures") List<MultipartFile> pictures) throws IOException {
    int result = homeService.upload(userId, comment, pictures);
    return 1;
}
public int upload(int userId, String comment, List<MultipartFile> pictures) throws IOException {
    Account user = accountRepository.findById(userId).get(); // 유저
    System.out.println("sadfasdfasdfasdf " + user.getId());
    int pic_size = pictures.size();

    Post post = new Post();
    post.setComment(comment);
    post.setLikecount(0);
    post.setAccount(user);
    post.setPic_size(pic_size);

    for (int i=0; i<pic_size; i++) {
        MultipartFile picture = pictures.get(i);
            
        // posts 폴더에 postId 폴더를 만든 후 그 안에 사진 저장 
        File path = new File("C:/Users/kimdev/Desktop/Java/kimstagram/src/main/resources/static/posts/" + Integer.toString(post.getId()) + "/");

        // 경로 생성
        if (!path.exists()) {
            path.mkdirs();
        }

        File file = new File(path, i+".jpg");
        picture.transferTo(file);
    }
    postRepository.save(post);

    return 0;
}

아 참고로 여기서 사용되는 @RequestPart는 'multipart/form-data'형식 데이터를 받기 위한 어노테이션이라고 한다!


여하튼 이런 로직으로 작성하면, 글이 업로드되면서 DB에 post가 insert된다.


https://ssdragon.tistory.com/99

 

스프링에서 파일저장하기

https://ssdragon.tistory.com/82 [Spring] IntelliJ 파일 업로드 주의사항 @PostMapping("/filetest") public String addImage2(@RequestParam("Photo") MultipartFile uploadFile, HttpServletRequest request) { String fileName = uploadFile.getOriginalFilenam

ssdragon.tistory.com

https://helloinyong.tistory.com/275

 

input type="file" 커스터마이징 하는 방법

Input File 태그의 기본적인 사용 File 필드를 사용하기 위해선 일반적으로 input type="file" 태그를 사용하게 된다. #Input File 태그 코드 # 각 브라우저 상에 나타나는 file 필드 해당 필드를 선언하면 각

helloinyong.tistory.com

https://velog.io/@gun_123/java-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C-%EC%B2%98%EB%A6%AC

 

[SpringBoot] 파일 업로드 처리

업로드 결과 반환과 화면 처리 브라우저에서 이미지를 전송받고 결과 데이터를 JSON으로 전송할 것임. 따라서 어떤 구조의 데이터를 전송할 것인지 결정해야 함. 브라우저에 필요한 정보를 정리

velog.io