글 목차
728x90
목차 : https://okane-on-cliff.tistory.com/246
1. App.vue 전체
<template>
<div>
{{totalVolume}} / 1GB
<input type="file" @change="oneFileSelect"/>
<button @click="oneFileSubmit">전송</button>
<button @click="clearAll">전체 삭제</button>
<hr>
<div style="display: flex; flex-wrap: wrap;">
<div v-for="(file, idx) in loadedFile" :key="idx" style="margin: 20px">
{{file.fileName}}<br>
<img :src="`data:image/${file.ext};base64, ${file.content}`"><br>
<button @click="downloadPicture(`data:image/${file.ext};base64, ${file.content}`, file.fileName)">다운로드</button>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import downloadFile from '@/js/downloader.js'
export default {
data() {
return {
totalVolume: "",
oneFile: {},
loadedFile: []
}
},
created() {
this.getTotalVolume();
this.downloadAllPicture();
},
methods: {
async getTotalVolume() {
var totalVolume = await axios.get(process.env.VUE_APP_URL + "/getTotalVolume").then(({data}) => data)
if (totalVolume < 1024) {
this.totalVolume = totalVolume + "byte"
} else if (totalVolume < 1024 * 1024) {
this.totalVolume = (Math.round(totalVolume / 1024 * 100) / 100) + "KB"
} else if (totalVolume < 1024 * 1024 *1024) {
this.totalVolume = (Math.round(totalVolume / 1024 / 1024 * 100) / 100) + "MB"
}
},
async downloadAllPicture() {
this.loadedFile = await axios.get(process.env.VUE_APP_URL + "/downloadAllPicture").then(({data}) => data);
},
oneFileSelect(e) {
this.oneFile = e.target.files[0];
},
async oneFileSubmit() {
if (!this.oneFile["name"]) {
alert("파일을 선택해 주세요");
return;
}
alert("파일을 전송해요")
const formData = new FormData();
formData.append("file", this.oneFile);
var result = await axios.post(process.env.VUE_APP_URL + "/uploadOneFile", formData, {headers: {'Content-Type': 'multipart/form-data'}}).then(({data}) => data);
if (result == 0) {
alert("더 이상 파일을 저장할 공간이 없어요")
}
await this.getTotalVolume();
await this.downloadAllPicture();
},
downloadPicture(baseUri, fileName) {
downloadFile(baseUri, fileName);
},
async clearAll() {
// 먼저 관리자로서 로그인 되어있는지 확인해요
// 세션 스토리지에 토큰이 있다면 로그인 되어 있다고 생각할게요
// 그 토큰을 서버에 보내서 토큰이 유효한지 확인해요
// 유효하다면 삭제를 시작해요
// 유효하지 않다면 로그인을 시작해요
var token = sessionStorage.getItem("token");
// console.log("토근:", token)
if (token) {
alert("토큰이 있어요")
//이제 토큰이 유효한지 확인해야해요
var result = await axios.post(process.env.VUE_APP_URL + "/tokenConfirm", token, {headers:{'Content-Type': 'text/plain'}}).then(({data}) => data)
// 토큰이 유효하다면
if (result == 1) {
console.log("토큰이 유효해요")
this.clearAllProcess();
} else {
console.log("토큰이 유효하지 않아요")
this.login();
}
} else {
this.login();
}
},
async login() {
sessionStorage.setItem("token", "");
var adm = prompt("관리자키를 입력해 주세요")
if (!adm) return;
//관리자키와 데이터베이스에 있는 값과 비교해요
var result = await axios.post(process.env.VUE_APP_URL + "/admConfirm", adm, {headers:{'Content-Type': 'text/plain'}}).then(({data}) => data)
if (result == 1) {
//로그인에 성공했어요
//토큰을 발급 받을게요
var key = await axios.get(process.env.VUE_APP_URL + "/getToken").then(({data}) => data);
// 받은 토큰을 세션스토리지에 저장해요
sessionStorage.setItem("token", key);
await this.clearAllProcess();
}
else {
//로그인에 실패했어요
alert("관리자가 아니시네요")
}
},
async clearAllProcess() {
await axios.get(process.env.VUE_APP_URL + "/clearAllProcess")
this.getTotalVolume();
this.downloadAllPicture();
}
},
}
</script>
몇 가지 특이점
(1) 이미지 소스
<div v-for="(file, idx) in loadedFile" :key="idx" style="margin: 20px">
{{file.fileName}}<br>
<img :src="`data:image/${file.ext};base64, ${file.content}`"><br>
<button @click="downloadPicture(`data:image/${file.ext};base64, ${file.content}`, file.fileName)">다운로드</button>
</div>
src의 구성은 base64형식으로 적어 주었다
(2) 파일 인풋 형식
<input type="file" @change="oneFileSelect"/>
v-model은 통하지 않는다. @change로 data를 갱신해준다.
(3) 파일 전송 방법
formData.append("file", this.oneFile);
var result = await axios.post(process.env.VUE_APP_URL + "/uploadOneFile", formData, {headers: {'Content-Type': 'multipart/form-data'}}).then(({data}) => data);
만약 여러개의 파일을 전송한다면
formData.append("file", 다른 파일); file을 그대로 두고 다른 파일을 추가해준다. 그럼 받는 쪽에서 List형식으로 혹은 배열 형식으로 받을 수 있다.
2. downloader.js
const dataURIToBlob = (base64) => {
const binStr = atob(base64.split(',')[1]);
const len = binStr.length;
const arr = new Uint8Array(len);
const mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
for (let i = 0; i < len; i++) {
arr[i] = binStr.charCodeAt(i);
}
return new Blob([arr], {
type: mimeString,
});
};
const downloadFile = (base64, filename) => new Promise((resolve, reject) => {
try {
if (!base64 || !filename) {
throw new Error('Missing param base64 or filename.');
}
if (typeof filename !== 'string') {
throw new TypeError('Missing param base64 or filename.');
}
const blob = dataURIToBlob(base64);
const url = URL.createObjectURL(blob);
const blobAnchor = document.createElement('a');
const dataURIAnchor = document.createElement('a');
blobAnchor.download = filename;
dataURIAnchor.download = filename;
blobAnchor.href = url;
dataURIAnchor.href = base64;
blobAnchor.addEventListener('click', () => {
requestAnimationFrame(() => {
URL.revokeObjectURL(url);
resolve();
});
});
blobAnchor.click();
} catch (e) {
reject(e);
}
});
module.exports = downloadFile;
어떤 사람이 만들어 둔 모듈인데 그냥 배껴왔다. atob라는 메서드는 취소선 그어지던데 이 부분은 알아 봐야 될거 같다.
728x90