이미지 여러개 올리기 1

2024. 8. 6. 13:58Springboot-React

mysql

 

CREATE TABLE IF NOT EXISTS posts (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    content VARCHAR(255) NOT NULL,
    image_url VARCHAR(255),
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

 

Post-Mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kh.mapper.PostMapper">
	<!-- 전체 게시글 보기 -->
	<select id="findAll" resultType="com.kh.dto.Post">
		select * from posts
	</select>
	
	<!-- post 게시글 테이블에 title = 제목 content = 내용 작성 -->
	<insert id="insertPost" parameterType="com.kh.dto.Post">
		insert into posts (title, content, image_url) values (#{title}, #{content}, #{imageUrl})
	</insert>
	
</mapper>

 

PostService + PostServiceImpl

//PostService.java

package com.kh.service;

import java.util.List;

import org.springframework.web.multipart.MultipartFile;

import com.kh.dto.Post;

public interface PostService {

	List<Post> findAll();
	void insertPost(Post post);
	
	//이미지 업로드를 도와주는 기능 목록 설정
	void uploadImages(MultipartFile[] files, String title, String content);
}

//PostServiceImpl.java

package com.kh.service;

import java.io.File;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.kh.dto.Post;
import com.kh.mapper.PostMapper;

@Service
public class PostServiceImpl implements PostService{

	@Autowired
	private PostMapper mapper;
	
	@Value("${file.upload-dir}")//application.properties에서 설정 가져와서 사용
	private String uploadDir; // = C:/Users/user1/Desktop/saveImage
	
	@Override
	public List<Post> findAll(){
		return mapper.findAll();
	}
	
	@Override
	public void insertPost(Post post) {
		mapper.insertPost(post);
	}
	
	@Override
	public void uploadImages(MultipartFile[] files, String title, String content) {
		//바탕화면에 이미지를 저장하고 불러올 폴더가 존재하는지 확인
		File uploadDirFile = new File(uploadDir);
		
		// 만약에 폴더가 존재하지 않을 경우
		if(!uploadDirFile.exists()) {
			System.out.println("폴더가 없으므로 폴더 새로 생성");
			
			//mkdirs = 하위 폴더 모두 생성
			if(!uploadDirFile.mkdirs()) {
				throw new RuntimeException("폴더 생성 실패");
			}
			
		}
		//이미지 이름 중복없이 저장할 수 있도록 설정
		List<String> fileNames = null; //파일명이 여러개일 수 있기 때문에 fileNames = 파일이름들 리스트로 글자목록을 작성
		
		try {
			fileNames = List.of(files).stream().map(file -> {
				//파일을 저장 폴더에 저장할 때 이미지에 랜덤으로 이름을 부여해서 저장
				//UUID : 파일 이름이 겹치지 않도록 랜덤으로 이름 생성
				
				String fileName1 = UUID.randomUUID().toString();
				
				//랜덤으로 작성한 이름 뒤에 원본 이름을 붙이고 싶을 때 -> getOriginalFilename()
				String fileName2 = UUID.randomUUID().toString() + file.getOriginalFilename();
				
				//랜덤으로 작성한 이름과 원본 이름을 '_'로 구분짓고 싶을 때
				String fileName3 = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
				
				//폴더 안에 이미지들 저장하기
				File df = new File(uploadDir + File.separator + fileName3);
				//File.separator : 파일 경로 구분. window(\, /)랑 맥북(/) 모두 경로를 알아서 잡아줌
				
				try {
					file.transferTo(df);
				}
				catch (Exception e) {
					throw new RuntimeException("파일 업로드 실패", e);
				}
				
				return fileName3;
			}).collect(Collectors.toList());

		}
		catch(Exception e) {
			e.printStackTrace();
		}
		
		//이미지 이름, 경로 설정울 바탕으로 DB에 넣어주기
		Post post = new Post();
		post.setTitle(title);
		post.setContent(content);
		post.setImageUrl(String.join(",", fileNames));
		insertPost(post);
	}
	
}

 

 

** UUID : 파일 이름이 겹치지 않도록 랜덤으로 이름 생성

 

** List.of(files).stream().map(file -> { }).collect(Collectors.toList());

  - MultipartFile[] files : array 배열로 파일들 담기
  - List.of(files) : 파일들 배열을 리스트(목록)로 변환
  - stream() : 리스트나 배열같은 데이터를 하나씩 처리하는 기능
  - collect(Collectors.toList()) : stream으로 가져온 이미지 데이터를 리스트로 정렬

이미지들(files) 에서 이미지를 한 개씩 담아오기(map) -> 이미지를 하나씩 가져옴(stream)
-> stream을 이용해서 가져온 이미지를 리스트로 모음(collect) -> 한번 더 리스트로 목록 변환(toList())

 

PostController

package com.kh.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.kh.dto.Post;
import com.kh.service.PostService;

@RestController
public class PostController {

	@Autowired
	private PostService postService;
	
	//ResponseEntity = 데이터가 무사히 전달되는지 체크
	
	//db에 저장된 게시글 내용, 이미지 가져오기
	@GetMapping("/posts")
	public ResponseEntity<List<Post>> findAll(){
		List<Post> posts = postService.findAll();
		return ResponseEntity.ok(posts);
	}
	
	//이미지 저장
	@PostMapping("/gallery/upload")
	public ResponseEntity<String> uploadImages( 
			@RequestParam("files") MultipartFile[] files, 
			@RequestParam("title") String title, 
			@RequestParam("content") String content) {
		postService.uploadImages(files, title, content);
		return ResponseEntity.ok("이미지 db 업로드 성공");
	}
}

 

 

WebConfig

 

리액트 포트와 백엔드 포트가 제대로 연결될 수 있도록 설정
WebSocket 프론트와 백엔드가 서로 상호작용을 주기적으로 진행할 때 좀 더 안전하게 연결을 계속함을 설정

package com.kh.common.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer{

	//react가 이미지폴더 경로를 가져갈 수 있도록 허용
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/images/**")
				.addResourceLocations("C:/Users/user1/Desktop/saveImage/"); //바탕화면에 지정한 이미지 경로
	}
	
	@Override
	public void addCorsMappings(CorsRegistry registry) {
		registry
		.addMapping("/**")
		.allowedOrigins("http://localhost:3000")
		//.allowedOrigins("*")
		.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
		.allowedHeaders("*");
		
	}
}

 

.addMapping("/**")
.allowedOrigins("http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*");

.allowedOrigins("http://localhost:3000") -> 해당 주소의

.addMapping("/**") -> 뒤에 오는 url api 주소를 모두 허용

.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
    -> http://localhost:3000/**로 들어오는 모든 요청 허용

.allowedHeaders("*") <head>정보에 들어갈 모든 요청 허용

'Springboot-React' 카테고리의 다른 글

프로필 사진 올리기 1  (0) 2024.08.09
이미지 여러개 올리기 2  (0) 2024.08.06
네이버 로그인 2  (0) 2024.07.30
네이버 로그인 1  (0) 2024.07.30
mysql-react-springboot 연결하기 2  (0) 2024.07.26