-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 0dce1a5
Showing
45 changed files
with
19,314 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
HELP.md | ||
target/ | ||
!.mvn/wrapper/maven-wrapper.jar | ||
!**/src/main/**/target/ | ||
!**/src/test/**/target/ | ||
|
||
### STS ### | ||
.apt_generated | ||
.classpath | ||
.factorypath | ||
.project | ||
.settings | ||
.springBeans | ||
.sts4-cache | ||
|
||
### IntelliJ IDEA ### | ||
.idea | ||
*.iws | ||
*.iml | ||
*.ipr | ||
|
||
### NetBeans ### | ||
/nbproject/private/ | ||
/nbbuild/ | ||
/dist/ | ||
/nbdist/ | ||
/.nb-gradle/ | ||
build/ | ||
!**/src/main/**/build/ | ||
!**/src/test/**/build/ | ||
|
||
### VS Code ### | ||
.vscode/ | ||
|
||
###local config file### | ||
!**/src/main/java/com/sean/csvproject/config/WebConfig.java |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* Copyright 2007-present the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
import java.net.*; | ||
import java.io.*; | ||
import java.nio.channels.*; | ||
import java.util.Properties; | ||
|
||
public class MavenWrapperDownloader { | ||
|
||
private static final String WRAPPER_VERSION = "0.5.6"; | ||
/** | ||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. | ||
*/ | ||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" | ||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; | ||
|
||
/** | ||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to | ||
* use instead of the default one. | ||
*/ | ||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH = | ||
".mvn/wrapper/maven-wrapper.properties"; | ||
|
||
/** | ||
* Path where the maven-wrapper.jar will be saved to. | ||
*/ | ||
private static final String MAVEN_WRAPPER_JAR_PATH = | ||
".mvn/wrapper/maven-wrapper.jar"; | ||
|
||
/** | ||
* Name of the property which should be used to override the default download url for the wrapper. | ||
*/ | ||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; | ||
|
||
public static void main(String args[]) { | ||
System.out.println("- Downloader started"); | ||
File baseDirectory = new File(args[0]); | ||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); | ||
|
||
// If the maven-wrapper.properties exists, read it and check if it contains a custom | ||
// wrapperUrl parameter. | ||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); | ||
String url = DEFAULT_DOWNLOAD_URL; | ||
if(mavenWrapperPropertyFile.exists()) { | ||
FileInputStream mavenWrapperPropertyFileInputStream = null; | ||
try { | ||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); | ||
Properties mavenWrapperProperties = new Properties(); | ||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); | ||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); | ||
} catch (IOException e) { | ||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); | ||
} finally { | ||
try { | ||
if(mavenWrapperPropertyFileInputStream != null) { | ||
mavenWrapperPropertyFileInputStream.close(); | ||
} | ||
} catch (IOException e) { | ||
// Ignore ... | ||
} | ||
} | ||
} | ||
System.out.println("- Downloading from: " + url); | ||
|
||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); | ||
if(!outputFile.getParentFile().exists()) { | ||
if(!outputFile.getParentFile().mkdirs()) { | ||
System.out.println( | ||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); | ||
} | ||
} | ||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); | ||
try { | ||
downloadFileFromURL(url, outputFile); | ||
System.out.println("Done"); | ||
System.exit(0); | ||
} catch (Throwable e) { | ||
System.out.println("- Error downloading"); | ||
e.printStackTrace(); | ||
System.exit(1); | ||
} | ||
} | ||
|
||
private static void downloadFileFromURL(String urlString, File destination) throws Exception { | ||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { | ||
String username = System.getenv("MVNW_USERNAME"); | ||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); | ||
Authenticator.setDefault(new Authenticator() { | ||
@Override | ||
protected PasswordAuthentication getPasswordAuthentication() { | ||
return new PasswordAuthentication(username, password); | ||
} | ||
}); | ||
} | ||
URL website = new URL(urlString); | ||
ReadableByteChannel rbc; | ||
rbc = Channels.newChannel(website.openStream()); | ||
FileOutputStream fos = new FileOutputStream(destination); | ||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); | ||
fos.close(); | ||
rbc.close(); | ||
} | ||
|
||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip | ||
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
# 웹(풀스택) 개발 프로젝트 | ||
|
||
## 주요 구현 기능 | ||
|
||
- 대량 파일 (CSV 10만건 이상) 업로드를 통한 Data 저장 기능. | ||
- drag & drop 파일 업로드 기능. | ||
- 업로드된 파일 데이터베이스에 insert 기능. | ||
- 업로드 진행 상태 progress bar 로 표시 기능. | ||
|
||
------------ | ||
|
||
### 개발 환경 | ||
|
||
- IntelliJ IDEA Ultimate 2020.03 | ||
- macOS Mojave 10.14.6 | ||
|
||
------------ | ||
|
||
### 개발 스택 | ||
|
||
- ReactJS 17.0.1 | ||
- Spring Boot 2.4.3 | ||
- Java 11 | ||
- MySQL 8.0.23 | ||
|
||
------------ | ||
|
||
### 빌드전 application.properties 주요 설정 확인 | ||
|
||
- 프로젝트 사용 포트 8090 | ||
``` | ||
server.port = 8090 | ||
``` | ||
- database 명 testdb 사용. 사용자 root password 설정 필요. | ||
``` | ||
spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=Asia/Seoul&cachePrepStmts=true&useServerPrepStmts=true&rewriteBatchedStatements=true | ||
spring.datasource.username=root | ||
spring.datasource.password={YOUR_PASSWORD} | ||
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver | ||
``` | ||
- 필요한 table은 자동으로 생성 되도록 설정됨. | ||
``` | ||
spring.jpa.hibernate.ddl-auto= update | ||
``` | ||
- 100MB 이상 파일 업로드 테스트시 max file size 수정 | ||
``` | ||
spring.servlet.multipart.max-file-size=100MB | ||
spring.servlet.multipart.max-request-size=100MB | ||
``` | ||
------------ | ||
|
||
### 빌드 및 실행 | ||
|
||
1. 프로젝트 clone | ||
|
||
``` | ||
> git clone https://github.com/prksean/csvproject.git | ||
> cd csvproject | ||
``` | ||
|
||
2. deploy.sh 실행 (윈도우의 경우 실행 전 수동으로 8090 포트 사용 확인 및 kill) | ||
|
||
###### MAC/Linux | ||
|
||
``` | ||
> sh deploy.sh | ||
``` | ||
|
||
###### Windows | ||
|
||
``` | ||
> netstat -ano | findstr 8090 | ||
> taskill /pid 5944 /f | ||
> sh deploy.sh | ||
``` | ||
|
||
------------ | ||
|
||
### API | ||
|
||
- CSV파일을 받아 repository를 사용하여 db table에 레코드 저장. | ||
|
||
``` | ||
REQUEST | ||
POST /csv/upload | ||
Content-Type: multipart/form-data | ||
RESPONSE | ||
Header Content-Type: application/json | ||
{ | ||
"message":"File uploaded successfully: 데이터셋.csv", | ||
"cnt":100000, | ||
"time":33.711325992 | ||
} | ||
``` | ||
|
||
- CsvController | ||
- `/upload` 요청 처리. | ||
- `csvUploader`가 `@RequestPart("file") MultipartFile file`을 input으로 받아 처리. | ||
- `CsvUtil`의 `isCsvType` 메소드를 사용하여 CSV 포멧 여부 확인. | ||
- `CsvService`의 `persistPeople` 메소드를 사용하여 CSV 파일 DB Insert. | ||
- `ResponseEntity<ResponseMessage>`를 return. | ||
|
||
- PeopleEntity | ||
- `long id` (PK), `String firstname`, `String lastname`, `String email` | ||
|
||
- CsvService | ||
- persistPeopleData | ||
- JPA `saveAll()` 사용 DB에 데이터 삽입. | ||
- `@Value("${spring.jpa.properties.hibernate.jdbc.batch_size}")`로 지정된 `batch_size`를 사용하여 분할 `saveAll()` 진행 | ||
- `StopWatch`를 사용하여 데이터 삽입 시간 측정. | ||
- persistPeople | ||
- `CsvUtil`의 `parseCsvToPeople` 메소드를 사용하여 CSV를 `PeopleEntity` 리스트로 파싱. | ||
- 파싱된 리스트를 `persistPeopleData` 메소드를 사용하여 DB에 데이터 삽입. | ||
|
||
- CsvUtil | ||
- isCsvType | ||
- input으로 받은 파일의 type이 `text/csv` 인지 확인. | ||
- parseCsvToPeople | ||
- `opencsv`의 `CSVReader`를 사용하여 input으로 받은 CSV 파일을 `PeopleEntity` 리스트로 파싱. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
echo "프로젝트 packaging 시작" | ||
|
||
mvn clean install | ||
|
||
echo "jar 생성 완료" | ||
echo "8090 포트 사용중 PID 확인" | ||
|
||
USING_PID=$(lsof -t -i:8090) | ||
|
||
echo "8090 포트 사용중 PID: $USING_PID" | ||
|
||
if [ -z $USING_PID ]; then | ||
echo "8090 포트 사용중 PID 없음" | ||
else | ||
echo "$USING_PID 프로세스 죽이기" | ||
kill -9 $USING_PID | ||
fi | ||
|
||
echo "10초 후 Deploy 시작" | ||
sleep 10 | ||
echo "Deploy 시작" | ||
nohup java -Dfile.encoding=UTF-8 -jar target/*.jar & |
Oops, something went wrong.