Open berryberrybin opened 1 year ago
application:
media-server:
base-uri: http://192.168.159.42:8888
upload-path: /images/upload
upload-many-path: /images/upload_many
download-path: /images/download/ # 추가한 코드
package com.tmax.cm.myshop.config.property;
@Getter
@ConstructorBinding
@RequiredArgsConstructor
@ConfigurationProperties(prefix = "application")
public class AppProperties {
private final MediaServer mediaServer;
@Getter
@RequiredArgsConstructor
public static class MediaServer {
private final String baseUri;
private final String uploadPath;
private final String uploadManyPath;
private final String downloadPath;
}
}
package com.tmax.cm.myshop.config;
@Configuration
@RequiredArgsConstructor
public class RestTemplateConfiguration {
private final AppProperties appProperties;
@Bean
public RestTemplate restTemplate(){
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(3000);
factory.setReadTimeout(5000);
RestTemplate restTemplate = new RestTemplate(factory);
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(appProperties.getMediaServer().getBaseUri()));
return restTemplate;
}
}
fileName
, fileId
만 응답하였으나 fileUri
도 함께 응답할 수 있도록 추가 List<FileInfo>
을 바로 리턴하였으나 fileUri 계산 로직 추가고양이.png
에서 .png만 가져옴package com.tmax.cm.myshop.service.common;
@Service
@RequiredArgsConstructor
public class MediaService {
private final RestTemplate restTemplate;
private final AppProperties appProperties;
public List<FileInfo> uploadAttachedImages(List<MultipartFile> attachedImages) {
if (attachedImages == null || attachedImages.size() == 0) {
return new ArrayList<>();
}
// return requestUpload(attachedImages); List<FileInfo> 해당 fileUri를 각각 넣어주는 코드 추가
List<FileInfo> fileInfos = requestUpload(attachedImages);
fileInfos.forEach(fileInfo -> fileInfo.setFileUri(
getImageUri(getFileExtension(fileInfo.getFileName()), fileInfo.getFileId())));
return fileInfos;
}
private String getFileExtension(String fileName) { // 파일이름에서 확장자 도출
return fileName.substring(fileName.lastIndexOf("."));
}
public List<FileInfo> requestUpload(List<MultipartFile> attachedImages) {
HttpEntity<MultiValueMap<String, Object>> requestEntity = createUploadRequestEntity(attachedImages);
if (attachedImages.size() == 1) {
ResponseEntity<MediaInfo.Single> response = restTemplate.postForEntity(
appProperties.getMediaServer().getUploadPath(),
requestEntity, MediaInfo.Single.class);
if (response.getStatusCode() != HttpStatus.OK || response.getBody().getCode() != HttpStatus.OK.value()) {
throw new BusinessException(ErrorCode.INTERNAL_SERVER_ERROR, null, null);
}
return Collections.singletonList(response.getBody().getData());
} else {
ResponseEntity<MediaInfo.Multi> response = restTemplate.postForEntity(
appProperties.getMediaServer().getUploadManyPath(), requestEntity, MediaInfo.Multi.class);
if (response.getStatusCode() != HttpStatus.OK || response.getBody().getCode() != HttpStatus.OK.value()) {
throw new BusinessException(ErrorCode.INTERNAL_SERVER_ERROR, null, null);
}
return response.getBody().getData();
}
}
private HttpEntity<MultiValueMap<String, Object>> createUploadRequestEntity(List<MultipartFile> attachedImages) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
for (MultipartFile attachedImage : attachedImages) {
body.add("file", attachedImage.getResource());
}
return new HttpEntity<>(body, headers);
}
private String getImageUri(String fileExtension, String fileId) { // 파일Uri 계산 로직
String directory = fileId.substring(0, 12).replaceAll("(.{2})(?!$)", "$1/");
String fileName = fileId.substring(12) + fileExtension;
String imageUri =
appProperties.getMediaServer().getBaseUri() + appProperties.getMediaServer().getDownloadPath() + directory
+ "/" + fileName;
return imageUri;
}
}
3e2b5dc21e2a48c0b40b5267ea10b2f1
http://192.168.159.42:8888/images/download/3e/2b/5d/c2/1e/2a/48c0b40b5267ea10b2f1.png
#!/usr/bin/env python
import os
import uuid
import shutil
from errors import NoSuchFileError, DuplicateFileError
def generate_uuid():
'''
Generate uuid for processing files uploaded from nginx module.
Returns:
randomly generated uuid
'''
return str(uuid.uuid4())
def generate_path(uuid, root_dir, path_threshold=12, path_step=2):
'''
Generate new path structure using uuid for files uploaded by nginx module.
Arguments:
- uuid {str} -- uuid used for generating directory structure
- root_dir {str} -- root directory for the uploaded file to be stored
- path_threshold {int} -- threshold index for generating path structure
- path_step {int} -- step interval for generating path structure
Returns:
- new_dir {str} -- path-like string. newly generated directory using uuid
- new_name {str} -- newly generated file name using uuid
'''
# subdirectory structure
dir = uuid[:path_threshold]
sub_dir = "/".join([
dir[i : i+path_step] for in range(0, path_threshold, path_step)
])
new_dir = os.path.join(root_dir, sub_dir)
# file name
new_name = uuid[path_threshold:]
return new_dir, new_name
def move_file(src_path, dst_path):
'''
Move file.
Arguments:
- src_path {str} -- source file path
- dst_path {str} -- destination file path
'''
shutil.move(src_path, dst_path)
def move_upload_to_storage(file, root_dir):
'''
Move uploaded files from nginx module to storage.
Arguments:
- file {list[str]} -- information of file uploaded via nginx module
- file_name -- name of uploaded file
- content_type -- HTTP content_type of uploaded file
- path -- temporary path of uploaded file
- root_dir {str} -- root directory for the uploaded file to be stored
Returns:
- file_name {str} -- name of uploaded file via nginx module
- uuid_processed {str} -- id of uploaded file via media service
'''
# uploaded file info
file_name, _, path = file
_, ext = os.path.splitext(file_name)
# generate uuid
uuid = generate_uuid()
uuid_processed = uuid.replace("-", "")
# generate directory structure for new path
new_dir, new_name = generate_path(uuid_processed, root_dir)
# make new_dir recursively if it does not exists
if not os.path.exists(new_dir):
os.makedirs(new_dir)
# move file to new path
new_path = os.path.join(new_dir, new_name + ext)
move_file(path, new_path)
return file_name, uuid_processed
def rollback_upload(paths):
'''
Delete uploaded files from nginx module when upload request is invalid.
Arguments:
- paths {list[str]} -- temporary paths of uploaded files via nginx module
'''
for path in paths:
os.remove(path)
def delete_from_storage(file_id, paths):
'''
Delete files from media service storage when user requests.
Arguments:
- file_id {str} -- id of file to be deleted
- paths {list[str]} -- file paths matched with requested file_id
'''
if not paths:
raise NoSuchFileError(file_id)
elif len(paths) >= 2:
raise DuplicateFileError(file_id)
else:
os.remove(paths[0])
Nginx를 이용한 이미지 서버 ⎻ Nginx 기본 설정 파일 작성
wapl-pay-server > MediaService > config > fastcgi.conf
wapl-pay-server > MediaService > config > mime.types
wapl-pay-server > MediaService > config > http.conf
wapl-pay-server > MediaService > config > nginx.conf
worker_processes
error_log
worker_connections
http