Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 * * http://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. */ package org.codelabor.system.file.web.servlet; import static org.codelabor.system.dao.DAOConstants.AFFECTED_ROW_COUNT; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URLEncoder; import java.security.InvalidParameterException; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.anyframe.idgen.IdGenService; import org.anyframe.util.properties.PropertiesService; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.FileCleanerCleanup; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringUtils; import org.codelabor.system.file.RepositoryType; import org.codelabor.system.file.dto.FileDTO; import org.codelabor.system.file.exception.InvalidRepositoryTypeException; import org.codelabor.system.file.listener.FileUploadProgressListener; import org.codelabor.system.file.manager.FileManager; import org.codelabor.system.file.util.UploadUtils; import org.codelabor.system.web.servlet.HttpRequestHeaderConstants; import org.codelabor.system.web.servlet.HttpResponseHeaderConstants; import org.codelabor.system.web.util.RequestUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; /** * ? * * @author Shin Sang-jae * */ public class FileUploadServlet extends HttpServlet { /** * UID */ private static final long serialVersionUID = 6060491747750865553L; /** * */ private final static Logger logger = LoggerFactory.getLogger(FileUploadServlet.class); /** * */ protected ServletConfig servletConfig; /** * ? */ protected String parameterName; /** * , ? */ protected String forwardPathUpload; /** * , ? */ protected String forwardPathDownload; /** * ? , ? */ protected String forwardPathList; /** * ? ? , ? */ protected String forwardPathRead; /** * ? , ? */ protected String forwardPathDelete; /** * ? * * @author Shin Sang-jae * */ public enum Parameter { upload, download, list, read, view, delete }; /** * ? ?</br> ? UTF-8?. */ protected String characterEncoding = "UTF-8"; /** * ? ? */ protected int sizeThreshold = DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD; /** * ? ? ?</br> ? 10MB?. */ protected long fileSizeMax = 1024 * 1024 * 10; /** * ? ?</br> ? 100MB?. */ protected long requestSizeMax = 1024 * 1024 * 100; /** * ? </br> ? user.dir . */ protected String realRepositoryPath = System.getProperty("user.dir"); /** * ? </br> ? java.io.tempdir? . */ protected String tempRepositoryPath = System.getProperty("java.io.tmpdir"); /** * ? ?</br> ? FILE_SYSTEM?. */ protected RepositoryType repositoryType = RepositoryType.FILE_SYSTEM; /* * (non-Javadoc) * * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig) */ @Override public void init(ServletConfig config) throws ServletException { // get init param servletConfig = config; parameterName = config.getInitParameter("parameterName"); forwardPathUpload = config.getInitParameter("forwardPathUpload"); forwardPathDownload = config.getInitParameter("forwardPathDownload"); forwardPathList = config.getInitParameter("forwardPathList"); forwardPathRead = config.getInitParameter("forwardPathRead"); forwardPathDelete = config.getInitParameter("forwardPathDelete"); // set service WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(config.getServletContext()); PropertiesService propertiesService = (PropertiesService) ctx.getBean("propertiesService"); // overwrite configuration characterEncoding = propertiesService.getString("file.default.character.encoding", characterEncoding); sizeThreshold = propertiesService.getInt("file.default.file.size.threshold", sizeThreshold); fileSizeMax = propertiesService.getLong("file.default.file.size.max", fileSizeMax); requestSizeMax = propertiesService.getLong("file.default.request.size.max", requestSizeMax); realRepositoryPath = propertiesService.getString("file.default.real.repository.path", realRepositoryPath); tempRepositoryPath = propertiesService.getString("file.default.temp.repository.path", tempRepositoryPath); repositoryType = RepositoryType.valueOf( propertiesService.getString("file.default.real.repository.type", repositoryType.toString())); // mkdirs File file = new File(realRepositoryPath); if (!file.exists()) { try { FileUtils.forceMkdir(file); } catch (IOException e) { StringBuilder sb = new StringBuilder(); sb.append("Cannot make directory: "); sb.append(file.toString()); logger.error(sb.toString()); throw new ServletException(sb.toString()); } } file = new File(tempRepositoryPath); if (!file.exists()) { try { FileUtils.forceMkdir(file); } catch (IOException e) { StringBuilder sb = new StringBuilder(); sb.append("Cannot make directory: "); sb.append(file.toString()); logger.error(sb.toString()); throw new ServletException(sb.toString()); } } } /* * (non-Javadoc) * * @see * javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest * , javax.servlet.http.HttpServletResponse) */ @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { String parameterValue = request.getParameter(parameterName); switch (Parameter.valueOf(parameterValue)) { case upload: upload(request, response); break; case download: download(request, response); break; case view: view(request, response); break; case list: list(request, response); break; case delete: delete(request, response); break; case read: read(request, response); break; default: logger.error("Invalid parameter: {}", parameterValue); throw new InvalidParameterException(parameterValue); } } catch (IOException e) { e.printStackTrace(); logger.error(e.getMessage()); throw new IOException(e); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); throw new ServletException(e); } } /** * ? . * * @param paramMap * ? Map * @throws Exception * */ protected void processParameters(Map<String, Object> paramMap) throws Exception { logger.debug("paramMap: {}", paramMap.toString()); } /** * ? . * * @param request * * @param response * ? * @param path * * @throws Exception * */ protected void dispatch(HttpServletRequest request, HttpServletResponse response, String path) throws Exception { logger.debug("dispatch path: ", path); RequestDispatcher dispatcher = servletConfig.getServletContext().getRequestDispatcher(path); dispatcher.forward(request, response); } /** * ?? .</br> ? ? ?? ? , (: ?) ? mapId . ? * ?? ? repositoryType , ? * org.codelabor.system.file.RepositoryType . * * @param request * * @param response * ? * @throws Exception * */ @SuppressWarnings("unchecked") protected void upload(HttpServletRequest request, HttpServletResponse response) throws Exception { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(this.getServletContext()); FileManager fileManager = (FileManager) ctx.getBean("fileManager"); boolean isMultipart = ServletFileUpload.isMultipartContent(request); Map<String, Object> paramMap = RequestUtils.getParameterMap(request); logger.debug("paramMap: {}", paramMap.toString()); String mapId = (String) paramMap.get("mapId"); RepositoryType acceptedRepositoryType = repositoryType; String requestedRepositoryType = (String) paramMap.get("repositoryType"); if (StringUtils.isNotEmpty(requestedRepositoryType)) { acceptedRepositoryType = RepositoryType.valueOf(requestedRepositoryType); } if (isMultipart) { DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setSizeThreshold(sizeThreshold); factory.setRepository(new File(tempRepositoryPath)); factory.setFileCleaningTracker(FileCleanerCleanup.getFileCleaningTracker(this.getServletContext())); ServletFileUpload upload = new ServletFileUpload(factory); upload.setFileSizeMax(fileSizeMax); upload.setSizeMax(requestSizeMax); upload.setHeaderEncoding(characterEncoding); upload.setProgressListener(new FileUploadProgressListener()); try { List<FileItem> fileItemList = upload.parseRequest(request); Iterator<FileItem> iter = fileItemList.iterator(); while (iter.hasNext()) { FileItem fileItem = iter.next(); logger.debug("fileItem: {}", fileItem.toString()); FileDTO fileDTO = null; if (fileItem.isFormField()) { paramMap.put(fileItem.getFieldName(), fileItem.getString(characterEncoding)); } else { if (fileItem.getName() == null || fileItem.getName().length() == 0) continue; // set DTO fileDTO = new FileDTO(); fileDTO.setMapId(mapId); fileDTO.setRealFilename(FilenameUtils.getName(fileItem.getName())); if (acceptedRepositoryType == RepositoryType.FILE_SYSTEM) { fileDTO.setUniqueFilename(getUniqueFilename()); } fileDTO.setContentType(fileItem.getContentType()); fileDTO.setRepositoryPath(realRepositoryPath); logger.debug("fileDTO: {}", fileDTO.toString()); UploadUtils.processFile(acceptedRepositoryType, fileItem.getInputStream(), fileDTO); } if (fileDTO != null) fileManager.insertFile(fileDTO); } } catch (FileUploadException e) { e.printStackTrace(); logger.error(e.getMessage()); throw e; } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); throw e; } } else { paramMap = RequestUtils.getParameterMap(request); } try { processParameters(paramMap); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); throw e; } dispatch(request, response, forwardPathUpload); } /** * ?? . * * @return ? * @throws Exception * */ protected String getUniqueFilename() throws Exception { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(this.getServletContext()); IdGenService uniqueFilenameGenerationService = (IdGenService) ctx .getBean("uniqueFilenameGenerationService"); return uniqueFilenameGenerationService.getNextStringId(); } /** * ? ?? .</br>? ?? * org.codelabor.system.file.FileConstants.FILE_LIST_KEY? attribute? * ??. Map Id? ? Map Id * org.codelabor.system.file.FileConstants.MAP_ID? attribute? ??. * * @param request * * @param response * ? * @throws Exception * */ protected void list(HttpServletRequest request, HttpServletResponse response) throws Exception { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(this.getServletContext()); FileManager fileManager = (FileManager) ctx.getBean("fileManager"); Map<String, Object> paramMap = RequestUtils.getParameterMap(request); logger.debug("paramMap: {}", paramMap.toString()); String mapId = (String) paramMap.get("mapId"); String repositoryType = (String) paramMap.get("repositoryType"); IdGenService mapIdGenService = (IdGenService) ctx.getBean("sequenceMapIdGenService"); List<FileDTO> fileDTOList = null; try { if (StringUtils.isEmpty(repositoryType)) { if (StringUtils.isEmpty(mapId)) { fileDTOList = fileManager.selectFileAll(); } else { fileDTOList = fileManager.selectFileByMapId(mapId); } } else { switch (RepositoryType.valueOf(repositoryType)) { case DATABASE: fileDTOList = fileManager.selectFileByRepositoryType(RepositoryType.DATABASE); break; case FILE_SYSTEM: fileDTOList = fileManager.selectFileByRepositoryType(RepositoryType.FILE_SYSTEM); break; default: logger.error("Invalid repository type: {}", repositoryType); throw new InvalidRepositoryTypeException(repositoryType); } } request.setAttribute(org.codelabor.system.file.FileConstants.FILE_LIST_KEY, fileDTOList); request.setAttribute(org.codelabor.system.file.FileConstants.MAP_ID, mapIdGenService.getNextStringId()); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); } dispatch(request, response, forwardPathList); } /** * ?? ??. * * @param request * * @param response * ? * @throws Exception * */ protected void view(HttpServletRequest request, HttpServletResponse response) throws Exception { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(this.getServletContext()); FileManager fileManager = (FileManager) ctx.getBean("fileManager"); Map<String, Object> paramMap = RequestUtils.getParameterMap(request); logger.debug("paramMap: {}", paramMap.toString()); String fileId = (String) paramMap.get("fileId"); StringBuilder sb = new StringBuilder(); FileDTO fileDTO; fileDTO = fileManager.selectFileByFileId(fileId); logger.debug("fileDTO: {}", fileDTO); String repositoryPath = fileDTO.getRepositoryPath(); String uniqueFilename = fileDTO.getUniqueFilename(); String realFilename = fileDTO.getRealFilename(); InputStream inputStream = null; if (StringUtils.isNotEmpty(repositoryPath)) { // FILE_SYSTEM sb.setLength(0); sb.append(repositoryPath); if (!repositoryPath.endsWith(File.separator)) { sb.append(File.separator); } sb.append(uniqueFilename); File file = new File(sb.toString()); inputStream = new FileInputStream(file); } else { // DATABASE byte[] bytes = new byte[] {}; if (fileDTO.getFileSize() > 0) { bytes = fileDTO.getBytes(); } inputStream = new ByteArrayInputStream(bytes); } response.setContentType(fileDTO.getContentType()); // set response contenttype, header String encodedRealFilename = URLEncoder.encode(realFilename, "UTF-8"); logger.debug("realFilename: {}", realFilename); logger.debug("encodedRealFilename: {}", encodedRealFilename); logger.debug("character encoding: {}", response.getCharacterEncoding()); logger.debug("content type: {}", response.getContentType()); logger.debug("bufferSize: {}", response.getBufferSize()); logger.debug("locale: {}", response.getLocale()); BufferedInputStream bufferdInputStream = new BufferedInputStream(inputStream); ServletOutputStream servletOutputStream = response.getOutputStream(); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(servletOutputStream); int bytesRead; byte buffer[] = new byte[2048]; while ((bytesRead = bufferdInputStream.read(buffer)) != -1) { bufferedOutputStream.write(buffer, 0, bytesRead); } // flush stream bufferedOutputStream.flush(); // close stream inputStream.close(); bufferdInputStream.close(); servletOutputStream.close(); bufferedOutputStream.close(); } /** * ?? .</br> ?? ? Id ? fileId . * org.codelabor.system.daos.AFFECTED_ROW_COUNT? attribute? ??. * * @param request * * @param response * ? * @throws Exception * */ protected void delete(HttpServletRequest request, HttpServletResponse response) throws Exception { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(this.getServletContext()); FileManager fileManager = (FileManager) ctx.getBean("fileManager"); int affectedRowCount = 0; // fileId String[] fileIdList = request.getParameterValues("fileId"); if (ArrayUtils.isEmpty(fileIdList)) { logger.warn("fileIdList is empty."); } else { try { affectedRowCount += fileManager.deleteFileByFileId(fileIdList); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); throw e; } } // mapId String[] mapIdList = request.getParameterValues("mapId"); if (ArrayUtils.isEmpty(mapIdList)) { logger.warn("mapIdList is empty."); } else { try { affectedRowCount += fileManager.deleteFileByMapId(mapIdList); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); throw e; } } request.setAttribute(AFFECTED_ROW_COUNT, affectedRowCount); dispatch(request, response, forwardPathDelete); } /** * ? .</br>? ?? ? Id ? fileID ?? DTO * org.codelabor.system.file.FileConstants.FILE_KEY? attribute? ??. * * @param request * * @param response * ? * @throws Exception * */ protected void read(HttpServletRequest request, HttpServletResponse response) throws Exception { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(this.getServletContext()); FileManager fileManager = (FileManager) ctx.getBean("fileManager"); String fileId = request.getParameter("fileId"); FileDTO fileDTO = fileManager.selectFileByFileId(fileId); request.setAttribute(org.codelabor.system.file.FileConstants.FILE_KEY, fileDTO); dispatch(request, response, forwardPathRead); } /* * (non-Javadoc) * * @see javax.servlet.GenericServlet#getServletConfig() */ @Override public ServletConfig getServletConfig() { return this.servletConfig; } /* * (non-Javadoc) * * @see javax.servlet.Servlet#destroy() */ @Override public void destroy() { } /* * (non-Javadoc) * * @see javax.servlet.Servlet#getServletInfo() */ @Override public String getServletInfo() { return null; } /** * ?? . * * @param request * * @param response * ? * @throws Exception * */ protected void download(HttpServletRequest request, HttpServletResponse response) throws Exception { WebApplicationContext ctx = WebApplicationContextUtils .getRequiredWebApplicationContext(this.getServletContext()); FileManager fileManager = (FileManager) ctx.getBean("fileManager"); Map<String, Object> paramMap = RequestUtils.getParameterMap(request); logger.debug("paramMap: {}", paramMap.toString()); String fileId = (String) paramMap.get("fileId"); StringBuilder sb = new StringBuilder(); FileDTO fileDTO; fileDTO = fileManager.selectFileByFileId(fileId); logger.debug("fileDTO: {}", fileDTO); String repositoryPath = fileDTO.getRepositoryPath(); String uniqueFilename = fileDTO.getUniqueFilename(); String realFilename = fileDTO.getRealFilename(); InputStream inputStream = null; if (StringUtils.isNotEmpty(repositoryPath)) { // FILE_SYSTEM sb.setLength(0); sb.append(repositoryPath); if (!repositoryPath.endsWith(File.separator)) { sb.append(File.separator); } sb.append(uniqueFilename); File file = new File(sb.toString()); inputStream = new FileInputStream(file); } else { // DATABASE byte[] bytes = new byte[] {}; if (fileDTO.getFileSize() > 0) { bytes = fileDTO.getBytes(); } inputStream = new ByteArrayInputStream(bytes); } // set response contenttype, header String encodedRealFilename = URLEncoder.encode(realFilename, "UTF-8"); logger.debug("realFilename: {}", realFilename); logger.debug("encodedRealFilename: {}", encodedRealFilename); response.setContentType(org.codelabor.system.file.FileConstants.CONTENT_TYPE); sb.setLength(0); if (request.getHeader(HttpRequestHeaderConstants.USER_AGENT).indexOf("MSIE5.5") > -1) { sb.append("filename="); } else { sb.append("attachment; filename="); } sb.append(encodedRealFilename); response.setHeader(HttpResponseHeaderConstants.CONTENT_DISPOSITION, sb.toString()); logger.debug("header: {}", sb.toString()); logger.debug("character encoding: {}", response.getCharacterEncoding()); logger.debug("content type: {}", response.getContentType()); logger.debug("bufferSize: {}", response.getBufferSize()); logger.debug("locale: {}", response.getLocale()); BufferedInputStream bufferdInputStream = new BufferedInputStream(inputStream); ServletOutputStream servletOutputStream = response.getOutputStream(); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(servletOutputStream); int bytesRead; byte buffer[] = new byte[2048]; while ((bytesRead = bufferdInputStream.read(buffer)) != -1) { bufferedOutputStream.write(buffer, 0, bytesRead); } // flush stream bufferedOutputStream.flush(); // close stream inputStream.close(); bufferdInputStream.close(); servletOutputStream.close(); bufferedOutputStream.close(); } }