Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge: (#202) MultipartFile → File 변환 리팩토링 #203

Merged
merged 8 commits into from
Dec 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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