1. 이미지, 동영상, 파일 업로드
| Warning | ||
|---|---|---|
| ||
가이드로 제공되는 아래 코드 중 파일 업로드 부분은 샘플 코드로서 보안 관련 처리가 미흡합니다. 파일 업로드 부분은 프로젝트 내부에서 사용하시는 부분을 그대로 사용하시고 아래 코드를 참고하셔서 연동 부분을 처리해주세요. |
| title | 환경별 연동가이드 |
|---|
1. 이미지, 동영상, 파일 업로드
| Code Block | ||||||||
|---|---|---|---|---|---|---|---|---|
| ||||||||
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.*;
@Controller
public class UploadController {
static String IMAGE_UPLOAD_DIR_REL_PATH = "uploads";
@RequestMapping(value = "/uploadFile.do", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> uploadFile(HttpServletRequest request, @RequestParam("file") MultipartFile file)
throws IOException {
String ROOT_ABS_PATH = request.getSession().getServletContext().getRealPath("");
String UPLOAD_DIR_ABS_PATH = ROOT_ABS_PATH + File.separator + IMAGE_UPLOAD_DIR_REL_PATH;
makeDirectory(UPLOAD_DIR_ABS_PATH);
String fileName = file.getOriginalFilename();
String ext = "";
String contentType = file.getContentType();
if(contentType != null) {
ext = "." + contentType.substring(contentType.lastIndexOf('/') + 1);
} else if (fileName.lastIndexOf('.') > 0) {
ext = fileName.substring(fileName.lastIndexOf('.'));
}
if (ext.indexOf(".jpeg") > -1) { // jpg가 더많이쓰여서 jpeg는 jpg로 변환
ext = ".jpg";
}
String saveFileName = UUID.randomUUID().toString() + ext;
String saveFileAbsPath = UPLOAD_DIR_ABS_PATH + File.separator + saveFileName;
writeFile(saveFileAbsPath, file.getBytes());
Map<String, Object> map = new HashMap<String, Object>();
// 브라우저에서 접근가능한 경로를 uploadPath에 담아서 넘겨줍니다.
map.put("uploadPath", "uploads/" + saveFileName);
return map;
}
/**
* 파일을 씁니다.
*/
private static void writeFile(String path, byte[] bytes) throws IOException {
OutputStream os = null;
try {
os = new FileOutputStream(path);
os.write(bytes);
} finally {
if (os != null) os.close();
}
}
/**
* 디렉토리가 없는 경우 디렉토리를 생성합니다.
*/
private static void makeDirectory(String dirPath) {
File dir = new File(dirPath);
if (!dir.exists()) {
dir.mkdir();
}
}
} |
2. HWP, MS 워드, 엑셀 문서 임포트
| Warning | ||
|---|---|---|
| ||
가이드로 제공되는 아래 코드 중 파일 업로드 부분은 샘플 코드로서 보안 관련 처리가 미흡합니다. 파일 업로드 부분은 프로젝트 내부에서 사용하시는 부분을 그대로 사용하시고 아래 코드를 참고하셔서 연동 부분을 처리해주세요. |
| Code Block | ||||||||
|---|---|---|---|---|---|---|---|---|
| ||||||||
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.*;
import java.util.zip.InflaterInputStream;
@Controller
public class ImportController {
static String DOC_UPLOAD_DIR_REL_PATH = "uploads" + File.separator + "docs";
static String OUTPUT_DIR_REL_PATH = "uploads" + File.separator + "output";
@RequestMapping(value = "/importDoc.do", method = RequestMethod.POST)
@ResponseBody
public Map<String, Object> importDoc(HttpServletRequest request, @RequestParam("file") MultipartFile importFile)
throws IOException {
String ROOT_ABS_PATH = request.getSession().getServletContext().getRealPath("");
String UPLOAD_DIR_ABS_PATH = ROOT_ABS_PATH + File.separator + DOC_UPLOAD_DIR_REL_PATH;
makeDirectory(UPLOAD_DIR_ABS_PATH);
String fileName = importFile.getOriginalFilename();
String inputFileAbsPath = UPLOAD_DIR_ABS_PATH + File.separator + fileName;
writeFile(inputFileAbsPath, importFile.getBytes());
// 파일별로 변환결과를 저장할 경로 생성
Calendar cal = Calendar.getInstance();
String yearMonth = String.format("%04d%02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1);
String uuid = UUID.randomUUID().toString();
String worksDirAbsPath = ROOT_ABS_PATH + File.separator + OUTPUT_DIR_REL_PATH + File.separator + yearMonth + File.separator + uuid;
makeDirectory(worksDirAbsPath);
// 문서 변환
executeConverter(inputFileAbsPath, worksDirAbsPath);
// 변환이 끝난 원본파일은 삭제한다.
deleteFile(inputFileAbsPath);
// 변환된 pb파일을 읽어서 serialzie
// v2.3.0 부터 파일명이 document.word.pb에서 document.pb로 변경됨
String pbAbsPath = worksDirAbsPath + File.separator + "document.pb";
Integer[] serializedData = serializePbData(pbAbsPath);
// pb파일은 삭제
// v2.3.0 부터 파일명이 document.word.pb에서 document.pb로 변경됨
deleteFile(pbAbsPath);
Map<String, Object> map = new HashMap<String, Object>();
map.put("serializedData", serializedData);
// 브라우저에서 접근가능한 경로를 importPath에 담아서 넘겨줍니다.
// OUTPUT_DIR_REL_PATH 경로에 맞춰서 수정해야 합니다.
map.put("importPath", "uploads/output/" + yearMonth + "/" + uuid);
return map;
}
/**
* 문서 변환 모듈을 실행합니다.
*/
public static int executeConverter(String inputFilePath, String outputFilePath) {
String SEDOC_CONVERTER_DIR_ABS_PATH = "변환모듈이 존재하는 디렉토리의 절대경로";
String FONT_DIR_ABS_PATH = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "fonts";
String TEMP_DIR_ABS_PATH = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "temp";
String SEDOC_CONVERTER_ABS_PATH = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "sedocConverter_exe";
// String SEDOC_CONVERTER_ABS_PATH = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "sedocConverter.exe";// window server용
makeDirectory(TEMP_DIR_ABS_PATH);
makeDirectory(FONT_DIR_ABS_PATH);
// 변화 명령 구성
String[] cmd = {SEDOC_CONVERTER_ABS_PATH, "-f", FONT_DIR_ABS_PATH, inputFilePath, outputFilePath, TEMP_DIR_ABS_PATH};
try {
Timer t = new Timer();
Process proc = Runtime.getRuntime().exec(cmd);
// JDK 1.7 이상
TimerTask killer = new TimeoutProcessKiller(proc);
t.schedule(killer, 20000 ProcessBuilder builder = new ProcessBuilder(cmd);
// 20초 (변환이 20초 안에 완료되지 않으면 프로세스 종료) // 프로세스의 int출력과 exitValue에러 = proc.waitFor();
killer.cancel();
스트림을 상속하도록 설정 (부모 프로세스의 콘솔로 출력됨)
return exitValue; } catch (Exception e) {
e.printStackTrace( builder.redirectOutput(Redirect.INHERIT);
return -1; } } /** * 문서 모듈 실행 후 변환된 결과를 Serialize 합니다.
*/
public static Integer[] serializePbData(String pbFilePath) throws IOException {
builder.redirectError(Redirect.INHERIT);
List<Integer> serializedData = new ArrayList<Integer>Process proc = builder.start();
FileInputStream fis = null; InflaterInputStream ifis = null; // JDK 1.6 이하 Integer[] data =
null; try { /*
fis = new FileInputStream(pbFilePath); Process proc = fis.skip(16Runtime.getRuntime().exec(cmd);
ifis = new InflaterInputStream(fis);
// 표준 출력 처리
try (InputStream procInput = proc.getInputStream()) {
byte[] buffer = new byte[1024];
int lenbytesRead;
while ((lenbytesRead = ifisprocInput.read(buffer)) != -1) {
System.out.write(buffer, 0, bytesRead);
for (int i = 0; i < len; i++) {
}
}
// 에러 스트림 처리
try serializedData.add(buffer[i] & 0xFF);
(InputStream procError = proc.getErrorStream()) {
} byte[] buffer = new byte[1024];
} data = serializedData.toArray(new Integer[serializedData.size()]);
int bytesRead;
} finally { ifwhile (ifis(bytesRead != null) ifis.close();
procError.read(buffer)) != -1) {
if (fis != null) fis.close(); } return data;
}
/**
* 파일을 씁니다.
*/
private static void writeFile(String path, byte[] bytes) throws IOException {
OutputStream os = null;
try {
System.err.write(buffer, 0, bytesRead);
}
}
os =*/
new FileOutputStream(path);
TimerTask killer = new os.writeTimeoutProcessKiller(bytesproc);
} finally {
t.schedule(killer, 20000); // 20초 (변환이 20초 안에 완료되지 않으면 프로세스 종료)
ifint (osexitValue != null) os.closeproc.waitFor();
}killer.cancel();
}
/**
* 파일을 삭제합니다. return */exitValue;
private } staticcatch void deleteFile(String path(Exception e) {
File file = new Filee.printStackTrace(path);
if (file.exists()) {
file.delete()return -1;
}
}
/**
* 문서 모듈 실행 후 변환된 결과를 Serialize 합니다.
*/
public static Integer[] serializePbData(String pbFilePath) throws IOException {
List<Integer> serializedData = new ArrayList<Integer>();
FileInputStream fis = null;
InflaterInputStream ifis = null;
Integer[] data = null;
try {
fis = new FileInputStream(pbFilePath);
fis.skip(16);
ifis = new InflaterInputStream(fis);
byte[] buffer = new byte[1024];
int len;
while ((len = ifis.read(buffer)) != -1) {
for (int i = 0; i < len; i++) {
serializedData.add(buffer[i] & 0xFF);
}
}
data = serializedData.toArray(new Integer[serializedData.size()]);
} finally {
if (ifis != null) ifis.close();
if (fis != null) fis.close();
}
return data;
}
/**
* 파일을 씁니다.
*/
private static void writeFile(String path, byte[] bytes) throws IOException {
OutputStream os = null;
try {
os = new FileOutputStream(path);
os.write(bytes);
} finally {
if (os != null) os.close();
}
}
/**
* 파일을 삭제합니다.
*/
private static void deleteFile(String path) {
File file = new File(path);
if (file.exists()) {
file.delete();
}
}
/**
* 디렉토리가 없는 경우 디렉토리를 생성합니다.
*/
private static void makeDirectory(String dirPath) {
File dir = new File(dirPath);
if (!dir.exists()) {
dir.mkdir();
}
}
private static class TimeoutProcessKiller extends TimerTask {
private Process p;
public TimeoutProcessKiller(Process p) {
this.p = p;
}
@Override
public void run() {
p.destroy();
}
}
} |
3. wmf to png 변환
| Status | ||||
|---|---|---|---|---|
|
| Status | ||||
|---|---|---|---|---|
|
아래한글이나 MS 워드에서 복사하여 붙여넣을 때 WMF 파일이 포함되어 있으면 이를 PNG로 변환합니다.
| Warning | ||
|---|---|---|
| ||
가이드로 제공되는 아래 코드 중 파일 업로드 부분은 샘플 코드로서 보안 관련 처리가 미흡합니다. 파일 업로드 부분은 프로젝트 내부에서 사용하시는 부분을 그대로 사용하시고 아래 코드를 참고하셔서 연동 부분을 처리해주세요. |
| Code Block | ||||||||
|---|---|---|---|---|---|---|---|---|
| ||||||||
package synap.editor.server.controller; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.*; @Controller public class WmfToPngController { static String IMAGE_UPLOAD_DIR_REL_PATH = "uploads" + File.separator + "image"; static String OUTPUT_DIR_REL_PATH = "uploads" + File.separator + "output"; /** * 업로드된 WMF 이미지를 PNG로 변환한 후, 변환된 이미지의 다운로드 URL을 반환합니다. * * @param request 클라이언트의 HTTP 요청 객체 * @param wmfImageFile 변환할 WMF 이미지 파일 * @return 변환된 PNG 파일의 다운로드 URL을 포함한 JSON 응답 * @throws IOException 파일 저장 또는 변환 중 예외 발생 시 */ @PostMapping(value = "/wmfToPng", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @ResponseBody public ResponseEntity<Map<String, String>> convertWmfToPng(HttpServletRequest request, @RequestParam("file") MultipartFile wmfImageFile) throws IOException { String ROOT_ABS_PATH = request.getSession().getServletContext().getRealPath(""); String UPLOAD_DIR_ABS_PATH = ROOT_ABS_PATH + File.separator + IMAGE_UPLOAD_DIR_REL_PATH; makeDirectory(UPLOAD_DIR_ABS_PATH); String fileName = wmfImageFile.getOriginalFilename(); String inputFileAbsPath = UPLOAD_DIR_ABS_PATH + File.separator + fileName; // 업로드된 파일 저장 writeFile(inputFileAbsPath, wmfImageFile.getBytes()); // 변환을 위한 작업 디렉토리 생성 Calendar cal = Calendar.getInstance(); String yearMonth = String.format("%04d%02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1); String uuid = UUID.randomUUID().toString(); String worksDirAbsPath = ROOT_ABS_PATH + OUTPUT_DIR_REL_PATH + File.separator + yearMonth + File.separator + uuid; makeDirectory(worksDirAbsPath); // 이미지 변환 executeConverter(inputFileAbsPath, worksDirAbsPath + File.separator + "output.png"); // 변환이 끝난 원본 파일 삭제 deleteFile(inputFileAbsPath); // 다운로드 URL 생성 - 변환된 파일을 사용하는 예시입니다. String downloadUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/download?fileName=" + uuid + "/output.png"; Map<String, String> response = new HashMap<>(); response.put("uploadPath", downloadUrl); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return ResponseEntity .status(HttpStatus.OK) .headers(headers) .body(response); } /** * 변환된 PNG 파일을 클라이언트가 다운로드할 수 있도록 스트리밍합니다. * * @param fileName 다운로드할 파일의 상대 경로 * @param request HTTP 요청 객체 * @param response HTTP 응답 객체 * @throws IOException 파일이 존재하지 않거나 스트리밍 중 오류 발생 시 */ @GetMapping("/download") public void downloadFile(@RequestParam("fileName") String fileName, HttpServletRequest request, HttpServletResponse response) throws IOException { String ROOT_ABS_PATH = request.getSession().getServletContext().getRealPath(""); Calendar cal = Calendar.getInstance(); String yearMonth = String.format("%04d%02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1); String downloadDirPath = ROOT_ABS_PATH + OUTPUT_DIR_REL_PATH + File.separator + yearMonth + File.separator; File file = new File(downloadDirPath + File.separator + fileName); if (!file.exists()) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } // 파일 다운로드 처리 response.setContentType("application/octet-stream"); response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\""); response.setContentLengthLong(file.length()); try (InputStream is = new FileInputStream(file); OutputStream os = response.getOutputStream()) { byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } } } /** * 외부 이미지 변환 도구(sedocConverter)를 호출하여 WMF 파일을 PNG로 변환합니다. * * @param inputFilePath 변환할 WMF 파일의 절대 경로 * @param outputFilePath 결과 PNG 파일의 저장 경로 * @return 프로세스 종료 코드 (0: 성공, 그 외: 실패) */ public static int executeConverter(String inputFilePath, String outputFilePath) { String SEDOC_CONVERTER_DIR_ABS_PATH = "변환모듈이 존재하는 디렉토리의 절대경로"; String TEMP_DIR_ABS_PATH = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "temp"; String SEDOC_CONVERTER_ABS_PATH = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "sedocConverter_exe"; // String SEDOC_CONVERTER_ABS_PATH = SEDOC_CONVERTER_DIR_ABS_PATH + File.separator + "sedocConverter.exe";// window server용 makeDirectory(TEMP_DIR_ABS_PATH); // 변환 명령 구성 String[] cmd = {SEDOC_CONVERTER_ABS_PATH, inputFilePath, outputFilePath, TEMP_DIR_ABS_PATH}; try { Timer t = new Timer(); // JDK 1.7 이상 ProcessBuilder builder = new ProcessBuilder(cmd); // 프로세스의 출력과 에러 스트림을 상속하도록 설정 (부모 프로세스의 콘솔로 출력됨) builder.redirectOutput(Redirect.INHERIT); builder.redirectError(Redirect.INHERIT); Process proc = builder.start(); // JDK 1.6 이하 /* Process proc = Runtime.getRuntime().exec(cmd); // 표준 출력 처리 try (InputStream procInput = proc.getInputStream()) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = procInput.read(buffer)) != -1) { System.out.write(buffer, 0, bytesRead); } } // 에러 스트림 처리 try (InputStream procError = proc.getErrorStream()) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = procError.read(buffer)) != -1) { System.err.write(buffer, 0, bytesRead); } } */ TimerTask killer = new TimeoutProcessKiller(proc); t.schedule(killer, 20000); int exitValue = proc.waitFor(); killer.cancel(); return exitValue; } catch (Exception e) { e.printStackTrace(); return -1; } } /** * 파일 경로로부터 바이트 배열을 읽어 반환합니다. * * @param filePath 읽을 파일의 경로 * @return 파일 내용의 바이트 배열 * @throws IOException 파일 읽기 중 예외 발생 시 */ private static byte[] readFileToByteArray(String filePath) throws IOException { File file = new File(filePath); try (FileInputStream fis = new FileInputStream(file)) { return fis.readAllBytes(); } } /** * 지정한 경로에 바이트 배열을 파일로 저장합니다. * * @param path 저장할 경로 * @param bytes 저장할 데이터 * @throws IOException 파일 쓰기 중 예외 발생 시 */ private static void writeFile(String path, byte[] bytes) throws IOException { try (OutputStream os = new FileOutputStream(path)) { os.write(bytes); } } /** * 지정한 경로의 파일을 삭제합니다. * * @param path 삭제할 파일 경로 */ private static void deleteFile(String path) { File file = new File(path); if (file.exists()) { file.delete(); } } /** * 지정한 경로의 디렉토리가 없는 경우 디렉토리를 생성합니다. */ 존재하지 않으면 생성합니다. * * @param dirPath 생성할 디렉토리 경로 */ private static void makeDirectory(String dirPath) { File dir = new File(dirPath); if (!dir.exists()) { dir.mkdir(); } } )) { dir.mkdirs(); } } /** * 주어진 프로세스를 일정 시간 후 강제 종료하는 TimerTask */ private static class TimeoutProcessKiller extends TimerTask { private Process p; public TimeoutProcessKiller(Process p) { this.p = p; } @Override public void run() { p.destroy(); } } } |
관련정보
| Children Display | ||
|---|---|---|
|