Skip to content

Commit

Permalink
merge: (#202) MultipartFile → File 변환 리팩토링 (#203)
Browse files Browse the repository at this point in the history
  • Loading branch information
khcho0125 authored Dec 10, 2022
2 parents 30dff4c + a80ba42 commit 4235884
Show file tree
Hide file tree
Showing 15 changed files with 236 additions and 101 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package team.comit.simtong.domain.file.usecase

import team.comit.simtong.domain.file.FileExtensionUtils.isImageExtension
import team.comit.simtong.domain.file.exception.FileInvalidExtensionException
import team.comit.simtong.domain.file.spi.UploadFilePort
import team.comit.simtong.global.annotation.UseCase
import java.io.File
Expand All @@ -20,25 +18,11 @@ class UploadImageUseCase(
) {

fun execute(file: File): String {
if (!isImageExtension(file)) {
file.delete()
throw FileInvalidExtensionException.EXCEPTION
}

return uploadFilePort.upload(file)
}

fun execute(files: List<File>): List<String> {
files.forEach {
if (!isImageExtension(it)) {
files.deleteAll()
throw FileInvalidExtensionException.EXCEPTION
}
}

return uploadFilePort.upload(files)
}

private fun List<File>.deleteAll() = this.forEach(File::delete)

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ package team.comit.simtong.domain.file.usecase
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.mockito.BDDMockito.given
import org.springframework.boot.test.mock.mockito.MockBean
import team.comit.simtong.domain.file.exception.FileInvalidExtensionException
import team.comit.simtong.domain.file.spi.UploadFilePort
import team.comit.simtong.global.annotation.SimtongTest
import java.io.File
Expand All @@ -21,15 +19,13 @@ class UploadImageUseCaseTests {

private val filePathStub = "test path"

private val filePathListStub = listOf(filePathStub)

private val jpgFileStub by lazy { File("test.jpg") }

private val jpegFileStub by lazy { File("test.jpeg") }

private val pngFileStub by lazy { File("test.png") }
private val fileStub: File by lazy {
File("test.jpg")
}

private val svgFileStub by lazy { File("test.svg") }
private val filesStub: List<File> by lazy {
listOf(fileStub)
}

@BeforeEach
fun setUp() {
Expand All @@ -39,50 +35,29 @@ class UploadImageUseCaseTests {
@Test
fun `단일 이미지 업로드`() {
// given
given(managerFilePort.upload(jpgFileStub))
given(managerFilePort.upload(fileStub))
.willReturn(filePathStub)

given(managerFilePort.upload(jpegFileStub))
.willReturn(filePathStub)
// when
val response = uploadImageUseCase.execute(fileStub)

given(managerFilePort.upload(pngFileStub))
.willReturn(filePathStub)
// then
assertEquals(response, filePathStub)

// when & then
assertEquals(uploadImageUseCase.execute(jpgFileStub), filePathStub)
assertEquals(uploadImageUseCase.execute(jpegFileStub), filePathStub)
assertEquals(uploadImageUseCase.execute(pngFileStub), filePathStub)
}

@Test
fun `다중 이미지 업로드`() {
// given
val filesStub = listOf(jpgFileStub, jpegFileStub, pngFileStub)
val filePathListStub = listOf(filePathStub)

given(managerFilePort.upload(filesStub))
.willReturn(filePathListStub)

// when & then
assertEquals(uploadImageUseCase.execute(filesStub), filePathListStub)
}

@Test
fun `단일 파일 확장자 오류`() {
// when & then
assertThrows<FileInvalidExtensionException> {
uploadImageUseCase.execute(svgFileStub)
}
}

@Test
fun `다중 파일 확장자 오류`() {
// given
val files = listOf(jpgFileStub, jpegFileStub, pngFileStub, svgFileStub)
// when
val response = uploadImageUseCase.execute(filesStub)

// when & then
assertThrows<FileInvalidExtensionException> {
uploadImageUseCase.execute(files)
}
assertEquals(response, filePathListStub)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ enum class FileErrorCode(
private val message: String
) : ErrorProperty {

INVALID_EXTENSION(400, "제한된 확장자"),

NOT_VALID_CONTENT(400, "파일의 내용이 올바르지 않음"),

INVALID_EMPLOYEE(401, "일치하는 사원 정보가 존재하지 않음"),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.springframework.web.bind.MissingServletRequestParameterException
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException
import team.comit.simtong.global.error.ErrorProperty
import team.comit.simtong.global.error.GlobalErrorCode
import team.comit.simtong.global.error.WebErrorProperty
import javax.validation.ConstraintViolationException

/**
Expand All @@ -29,6 +30,12 @@ class ErrorResponse(
fieldErrors = emptyList()
)

fun of(exception: WebErrorProperty) = ErrorResponse(
status = exception.status(),
message = exception.message(),
fieldErrors = emptyList()
)

fun of(bindingResult: BindingResult): ErrorResponse = of(
exception = GlobalErrorCode.BAD_REQUEST,
fieldErrors = CustomFieldError.of(bindingResult)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import org.springframework.http.MediaType
import org.springframework.web.filter.OncePerRequestFilter
import team.comit.simtong.global.error.BusinessException
import team.comit.simtong.global.error.ErrorProperty
import team.comit.simtong.global.error.WebErrorProperty
import team.comit.simtong.global.error.WebException
import team.comit.simtong.global.error.dto.ErrorResponse
import team.comit.simtong.global.exception.InternalServerErrorException
import java.nio.charset.StandardCharsets
Expand Down Expand Up @@ -36,6 +38,7 @@ class ExceptionFilter(
} catch (e: Exception) {
when (e.cause) {
is BusinessException -> writeErrorCode((e.cause as BusinessException).exceptionProperty, response)
is WebException -> writeErrorCode((e.cause as WebException).exceptionProperty, response)
else -> {
e.printStackTrace()
writeErrorCode(InternalServerErrorException.EXCEPTION.exceptionProperty, response)
Expand All @@ -45,13 +48,28 @@ class ExceptionFilter(
}

private fun writeErrorCode(exception: ErrorProperty, response: HttpServletResponse) {
response.characterEncoding = StandardCharsets.UTF_8.name()
response.status = exception.status()
response.contentType = MediaType.APPLICATION_JSON_VALUE
response.writer.write(
objectMapper.writeValueAsString(
ErrorResponse.of(exception)
response.run {
characterEncoding = StandardCharsets.UTF_8.name()
status = exception.status()
contentType = MediaType.APPLICATION_JSON_VALUE
writer.write(
objectMapper.writeValueAsString(
ErrorResponse.of(exception)
)
)
)
}
}

private fun writeErrorCode(exception: WebErrorProperty, response: HttpServletResponse) {
response.run {
characterEncoding = StandardCharsets.UTF_8.name()
status = exception.status()
contentType = MediaType.APPLICATION_JSON_VALUE
writer.write(
objectMapper.writeValueAsString(
ErrorResponse.of(exception)
)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,10 @@ import org.springframework.web.bind.annotation.RestController
import org.springframework.web.multipart.MultipartFile
import team.comit.simtong.domain.file.dto.response.UploadImageListWebResponse
import team.comit.simtong.domain.file.dto.response.UploadImageWebResponse
import team.comit.simtong.domain.file.transfer.ExcelFileConvertor
import team.comit.simtong.domain.file.transfer.ImageFileConvertor
import team.comit.simtong.domain.file.usecase.RegisterEmployeeCertificateUseCase
import team.comit.simtong.domain.file.usecase.UploadImageUseCase
import java.io.File
import java.io.FileOutputStream
import java.util.UUID

/**
*
Expand All @@ -33,31 +32,28 @@ class WebFileAdapter(
@ResponseStatus(HttpStatus.CREATED)
fun uploadSingleImage(file: MultipartFile): UploadImageWebResponse {
return UploadImageWebResponse(
uploadImageUseCase.execute(file.let(transferFile))
uploadImageUseCase.execute(
file.let(ImageFileConvertor::transferTo)
)
)
}

@PostMapping("/list")
@ResponseStatus(HttpStatus.CREATED)
fun uploadMultipleImage(files: List<MultipartFile>): UploadImageListWebResponse {
return UploadImageListWebResponse(
uploadImageUseCase.execute(files.map(transferFile))
uploadImageUseCase.execute(
files.let(ImageFileConvertor::transferToList)
)
)
}

@PostMapping("/employee")
@ResponseStatus(HttpStatus.CREATED)
fun importEmployeeCertificate(file: MultipartFile) {
registerEmployeeCertificateUseCase.execute(file.let(transferFile))
}

private val transferFile = { multipartFile: MultipartFile ->
File("${UUID.randomUUID()}_${multipartFile.originalFilename}").apply {
FileOutputStream(this).run {
write(multipartFile.bytes)
close()
}
}
registerEmployeeCertificateUseCase.execute(
file.let(ExcelFileConvertor::transferTo)
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package team.comit.simtong.domain.file.error

import team.comit.simtong.global.error.WebErrorProperty

/**
*
* 표현 계층의 File Error를 관리하는 WebFileErrorCode
*
* @author Chokyunghyeon
* @date 2022/12/09
* @version 1.0.0
**/
enum class WebFileErrorCode(
private val status: Int,
private val message: String
) : WebErrorProperty {

INVALID_EXTENSION(400, "제한된 확장자");

override fun status(): Int = status

override fun message(): String = message

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package team.comit.simtong.domain.file.exception

import team.comit.simtong.domain.file.error.WebFileErrorCode
import team.comit.simtong.global.error.WebException

/**
*
* 파일 확장자 제한 에러를 발생시키는 FileInvalidExtensionException
*
* @author Chokyunghyeon
* @date 2022/12/09
* @version 1.0.0
**/
class FileInvalidExtensionException private constructor() : WebException(WebFileErrorCode.INVALID_EXTENSION) {

companion object {
@JvmField
val EXCEPTION = FileInvalidExtensionException()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package team.comit.simtong.domain.file.transfer

import org.springframework.web.multipart.MultipartFile
import team.comit.simtong.domain.file.FileExtensionUtils.XLS
import team.comit.simtong.domain.file.FileExtensionUtils.XLSX

/**
*
* Excel File의 변환을 담당하는 ExcelFileConvertor
*
* @author Chokyunghyeon
* @date 2022/12/09
* @version 1.0.0
**/
object ExcelFileConvertor : FileConvertor {

override fun isCorrectExtension(multipartFile: MultipartFile): Boolean {
return when (multipartFile.extension) {
XLS, XLSX -> true
else -> false
}
}

}
Loading

0 comments on commit 4235884

Please sign in to comment.