반응형
SMALL
나는 javascript 의 FormData() 를 사용하여 객체 배열을 넣고 싶었다...
성격급한 우리 한국인과 개발자분들은 시간이 없으니
우선 이런식으로 보낸다고 알려드리고 밑에서 예시를 보여드리겠습니다.
let array = [
obj1 : {
data1 : 'java',
data2 : 'javascript'
},
obj2 : {
data1 : 'spring',
data2 : 'react'
}
]
// array라는 배열안에는 2개의 obj1, obj2 객체가 존재하여
// 이것을 spring Controller 단에 객체에 바인딩을 하고 싶을 때
//javascript 진영
let formData = new FormData()
for (let i=0; i<array.length; i++) {
formData.append("formDto["+i+"].procData", array[i].procData);
}
//java 진영
public class FormDto {
List<DTO> formDto;
}
FormData를 다루기는 매우(?) 쉽습니다.
단 필드 하나일 때는 단순하게 아래처럼 입력한 값들을 가져와서 append() 메서드를 사용하여 처리할 수 있습니다.
//HTML 진영에서 이런식으로 사용을 하고 싶다면
<input class='text-area' id='dataDesc' name='dataDesc' />
// javascript 진영에서는 append() 메서드를 사용하여 쉽게 form에 넣어서 데이터를 보낼 수 있습니다.
let dataDesc = document.getElementById('dataDesc').value;
formData.append('dataDesc',dataDesc);
하지만 이 포스팅의 목적이자 머리를 아프게 했었던 formData에 객체배열을 Controller로 넘기는것 입니다.
이번에 예시를 들어볼 것은 파일 업로드를 할 때, 단순 파일만 딸랑 업로드 하는것이 아닌
파일업로드를 하며 내가 원하는 타입으로 ,원하는 이름으로, 파일의 정확한 크기를 나타내는
DataType, dataName , fileSize를 DB에 저장하는 법입니다.
또한, 내가 업로드를 한 파일을 빈 DIV 태그에 보여진 후, 바로 업로드 하는 것이 아닌 , 잘못 올려서 삭제도 가능하여 DB에 저장을 원할때 데이터들을 모아서 한번에 보내는 법입니다.
JSP로 파일업로드로 예시를 들어보겠습니다.
HTML
<div class="content-body">
<div class="create-box">
<div class="create-header">
</div>
<div class="table-create">
<table>
<colgroup>
<col width="15%">
<col width="35%">
<col width="15%">
<col width="25%">
<col width="10%">
</colgroup>
<tbody>
<form:form name="insertForm" id="insertForm" class="form-inline">
<input type="hidden" id="projectId" name="projectId" value="${projectInfo.projectId}" />
<input type="hidden" id="uploadFileDiv"></input>
<tr>
<th scope="row"><span>DataSet 명</span></th>
<td colspan="4"><input type="text" class="input" id="datasetName" name="datasetName"></td>
</tr>
<tr>
<th scope="row"><span>스토리지</span></th>
<td>
<div class="select-box">
<select id="storageType" name="storageType" style="width:100px">
<option value="Ceph">Ceph</option>
<option value="MinIO">MinIO</option>
</select>
</div>
</td>
<th scope="row"><span>도메인 유형</span></th>
<td colspan="2">
<div class="select-box">
<select id="dataDomainTypeList" name="domainType" style="width:100px">
<c:forEach items="${taskDomainTypeList}" var="item" varStatus="status">
<option value="${item.dtlCd}">${item.dtlCdName}</option>
</c:forEach>
</select>
</div>
</td>
</tr>
<tr>
<th scope="row"><span>DataSet 설명</span></th>
<td colspan="4">
<textarea id="editorContents" rows="10" cols="80"></textarea>
</td>
</tr>
<tr>
<th scope="row"><span>데이터 명</span></th>
<td colspan="3"><input type="text" class="input" id="dataName" name="dataName"></td>
<th scope="row" rowspan="3" class="th-last">
<div class="td-box"><button type="button" class="btn btn-m-defalt" id="addBtn" onclick="addData()">추가</button></div>
</th>
</tr>
<tr>
<th scope="row"><span>데이터 경로</span></th>
<td colspan="3">
<div class="td-box">
<input type="text" class="input" id="" name="">
<button type="button" class="btn-folder"><i class='bx bxs-folder-open'></i></button>
</div>
</td>
</tr>
<tr>
<th scope="row"><span>데이터 파일</span></th>
<td>
<div class="input-file-box">
<label for="uploadFile" class="btn btn-m-point">파일선택</label>
<input class="input upload_name" id="uploadFileName" value="" readonly>
<input type="file" id="uploadFile" name="uploadFile" class="a11y-hidden" />
<input type="hidden" id="addDataList" name="dataList">
</div>
</td>
<th scope="row"><span>데이터 유형</span></th>
<td>
<div class="select-box">
<select id="dataType" name="dataType">
<option value="single">Single</option>
<option value="multi">Multi</option>
</select>
</div>
</td>
</tr>
</form:form>
</tbody>
</table>
</div>
</div>
<div class="create-box">
<div class="create-header">
<h3 class="title">Data 추가 목록</h3>
</div>
<div>
<div class="table-type">
<table>
<colgroup>
<col width="6%">
<col width="18%">
<col width="10%">
<col width="10%">
<col width="auto">
<col width="10%">
</colgroup>
<thead>
<tr>
<th>No.</th>
<th>Name</th>
<th>데이터 유형</th>
<th>데이터 사이즈</th>
<th>스토리지 endpoint</th>
<th></th>
</tr>
</thead>
<tbody id="dataList" >
</tbody>
<form id="addDataForm"></form>
</table>
</div>
</div>
</div>
<div class="btn-area">
<button type="button" class="btn-m-base" onclick="goToProject()">취소</button>
<button type="button" class="btn-m-defalt" onclick="registerDataset()">저장</button>
</div>
</div>
javascript
let paramArr = [];
// 업로드를 한 후 추가 할때 버튼을 누를 때 발생하는 function 입니다.
function addData() {
if (!$('#dataName').val()) {
alert('데이터명은 필수값 입니다.');
$('#dataName').focus();
return;
}
if (!$('#uploadFile').val()) {
alert('데이터 파일이 없습니다.');
return;
}
let fileTag = document.getElementById('uploadFile');
// input type이 file이며 id가 uploadFile 인 태그를 가져옵니다.
let file = fileTag.files[0];
// 가져온 태그의 files를 통해 파일 정보를 가져옵니다.
let cloneFile = fileTag.cloneNode();
// 업로드를 하여 가져온 파일 데이터들을 임시로 cloneNode()를 통해서 복제합니다.
fileTag.value = '';
cloneFile.id = '';
// 가져온 clone파일의 Id로는 가져오지 않을것이고 겹칠 수도 있으니 공백으로 만들어줍니다.
cloneFile.name = `uploadFiles`;
// 여기가 중요합니다. name을 spring 진영에서
// @RequestParam("uploadFiles") List<MultipartFile> uploadFiles 와 바인딩 해줍니다.
cloneFile.classList.remove('ally-hidden');
// 단순 class 제거 입니다.
insertForm.appendChild(cloneFile);
// form의 id 가 insertForm 인 곳에 appnedChild()를 통해 복제한 데이터를 넣어줍니다.
let dataName = $('#dataName').val();
let fileName = file.name;
let dataType = $('#dataType').val();
// 위처럼 입력한 데이터들을 변수로 만들어 준 후 아래의 객체 param에 넣어줍니다.
let param = {
dataName : dataName,
fileName : fileName,
dataType : dataType,
fileSize : Number(file.size)
};
paramArr.push(param);
// 맨 위에서 만든 paramArr = []; 에 밀어넣어줍니다.
let html = '';
// 아래는 위의 param 에 넣었던 객체들로 업로드 했던 데이터들을 보여줄 공간입니다.
paramArr.forEach(function(v,i) {
html += `
<tr id="\${file.lastModified}">
<td data-index='\${i+1}'>\${i+1}</td>
<td>\${v.dataName}</td>
<td>\${v.dataType}</td>
<td>\${formatBytes(v.fileSize)}</td>
<td>\${v.fileName}</td>
<td>
<div class="td-box">
<button data-index='\${file.lastModified}' type="button" class="btn btn-m-base" onclick="removeFile()">삭제</button>
</div>
</td>
</tr>
`;
})
// <div id='dataList'>
// </div>
// 라는 태그를 만들어놓고 아래에 그대로 밀어넣어줍니다.
$('#dataList').html(html);
}
여기서 끝난 게 아니라 밀어넣어준 데이터들을 보내주어야겠죠.
// 최종으로 등록하는 function
function registerDataset() {
let insertForm = $('#insertForm')[0];
let formData = new FormData(insertForm);
let datasetDesc = CKEDITOR.instances.editorContents.getData();
// CK Editor 로 입력한 글을 datasetDesc 라는 변수로 넣어줍니다.
formData.append('datasetDesc',datasetDesc);
// 단건 데이터 넣어주기
let dataList = [];
// 빈 dataList라는 배열을 만들어 준 뒤, 위에서 만든 paramArr 에 들어가있는 데이터들을 아래처럼 넣어줍니다.
for (let i = 0; i < paramArr.length; i++) {
formData.append("addDataList["+i+"].dataName", paramArr[i].dataName);
formData.append("addDataList["+i+"].storageEndPoint", paramArr[i].fileName);
formData.append("addDataList["+i+"].dataPositionType", paramArr[i].dataType);
formData.append("addDataList["+i+"].dataSize", paramArr[i].fileSize);
}
confirm('저장하시겠습니까?',function() {
$.ajax({
url : '/api/v1/dataSet/register',
type: "post",
contentType : false,
//multipart로 보낼 때는 항상 contentType 은 false로 설정해주는것을 잊지 말아주세요
enctype: "multipart/form-data",
processData: false,
data : formData,
cache : false,
success : function (res) {
if (res.result) {
goToProject();
}
},
})
});
}
spring
// 클래스
public Class UploadDto {
private String boardtitle;
private String boardDesc;
private String datasetDesc;
private List<Data> addDataList;
//이 변수가 위 스크립트의 addData()에서 append()해주었던 변수와 바인딩 됩니다.
}
// addDataList 변수의 타입
public Class Data {
private String fileName;
private String fileSize;
private String storageEndPoint;
private String dataPositionType;
}
@PostMapping("/api/v1/dataset/register")
@ResponseBody
public ResponseEntity<Object> register(@RequestParam("uploadFiles") List<MultipartFile> uploadFiles,
UploadDto uploadDto) {
// 이하 생략
}
꿀팁! 숫자를 바이트 단위로 변환하는 방법
function formatBytes(bytes, decimals = 2) {
if (bytes == 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
};
// 사용법
int dataSize = 190323;
formatBytes(dataSize); //<- 요렇게!
반응형
LIST
'JAVA' 카테고리의 다른 글
[JAVA] 컬렉션(Collection)[1]- List에 대하여 (0) | 2023.07.26 |
---|---|
[JAVA] 컬렉션(Collection)[0]- Collection에 대하여 (0) | 2023.07.26 |
쿠키, 로컬 스토리지, 세션 스토리지 (0) | 2023.07.24 |
관계형 데이터베이스 설계(Schema / Entity , 1:1 / 1:M / N:M) (2) | 2023.07.23 |
트랜잭션(Transaction) (0) | 2023.07.23 |