001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package io.jboot.web.attachment; 018 019import com.jfinal.log.Log; 020import com.jfinal.render.IRenderFactory; 021import com.jfinal.render.Render; 022import com.jfinal.render.RenderManager; 023 024import javax.servlet.http.HttpServletRequest; 025import javax.servlet.http.HttpServletResponse; 026import java.io.File; 027import java.io.InputStream; 028import java.util.HashMap; 029import java.util.List; 030import java.util.Map; 031import java.util.concurrent.CopyOnWriteArrayList; 032 033/** 034 * @author michael yang (fuhai999@gmail.com) 035 */ 036public class AttachmentManager { 037 038 private static final Log LOG = Log.getLog(AttachmentManager.class); 039 040 private static Map<String, AttachmentManager> managers = new HashMap<>(); 041 042 public static AttachmentManager me() { 043 return use("default"); 044 } 045 046 public static AttachmentManager use(String name) { 047 AttachmentManager manager = managers.get(name); 048 if (manager == null) { 049 synchronized (AttachmentManager.class) { 050 manager = managers.get(name); 051 if (manager == null) { 052 manager = new AttachmentManager(name); 053 managers.put(name, manager); 054 } 055 } 056 } 057 return manager; 058 } 059 060 /** 061 * 通过这个方式可以来更改 manager 包括默认的 manager 062 * 063 * @param manager 064 */ 065 public static void setManager(AttachmentManager manager) { 066 managers.put(manager.name, manager); 067 } 068 069 070 public AttachmentManager(String name) { 071 this.name = name; 072 } 073 074 /** 075 * 默认的 附件容器 076 */ 077 protected LocalAttachmentContainer defaultContainer = new LocalAttachmentContainer(); 078 079 /** 080 * 其他附件容器 081 */ 082 protected List<AttachmentContainer> containers = new CopyOnWriteArrayList<>(); 083 084 /** 085 * 自定义文件渲染器 086 */ 087 protected IRenderFactory renderFactory = RenderManager.me().getRenderFactory(); 088 089 /** 090 * manager 的名称 091 */ 092 protected final String name; 093 094 095 public String getName() { 096 return name; 097 } 098 099 public IRenderFactory getRenderFactory() { 100 return renderFactory; 101 } 102 103 public void setRenderFactory(IRenderFactory renderFactory) { 104 this.renderFactory = renderFactory; 105 } 106 107 108 public LocalAttachmentContainer getDefaultContainer() { 109 return defaultContainer; 110 } 111 112 public void setDefaultContainer(LocalAttachmentContainer defaultContainer) { 113 this.defaultContainer = defaultContainer; 114 } 115 116 public void addContainer(AttachmentContainer container) { 117 containers.add(container); 118 } 119 120 public void setContainers(List<AttachmentContainer> containers) { 121 this.containers = containers; 122 } 123 124 125 public List<AttachmentContainer> getContainers() { 126 return containers; 127 } 128 129 130 /** 131 * 保存文件 132 * 133 * @param file 134 * @return 返回文件的相对路径 135 */ 136 public String saveFile(File file) { 137 //优先从 默认的 container 去保存文件 138 String relativePath = defaultContainer.saveFile(file); 139 File defaultContainerFile = defaultContainer.getFile(relativePath); 140 141 for (AttachmentContainer container : containers) { 142 try { 143 if (container != defaultContainer) { 144 container.saveFile(defaultContainerFile); 145 } 146 } catch (Exception ex) { 147 LOG.error("Save file error in container: " + container, ex); 148 } 149 } 150 return relativePath.replace("\\", "/"); 151 } 152 153 154 /** 155 * 保存文件 156 * 157 * @param file 158 * @return 返回文件的相对路径 159 */ 160 public String saveFile(File file, String toRelativePath) { 161 //优先从 默认的 container 去保存文件 162 String relativePath = defaultContainer.saveFile(file, toRelativePath); 163 File defaultContainerFile = defaultContainer.getFile(relativePath); 164 165 for (AttachmentContainer container : containers) { 166 try { 167 if (container != defaultContainer) { 168 container.saveFile(defaultContainerFile, toRelativePath); 169 } 170 } catch (Exception ex) { 171 LOG.error("Save file error in container: " + container, ex); 172 } 173 } 174 return relativePath.replace("\\", "/"); 175 } 176 177 /** 178 * 保存文件 179 * 180 * @param inputStream 181 * @return 182 */ 183 public String saveFile(InputStream inputStream, String toRelativePath) { 184 //优先从 默认的 container 去保存文件 185 String relativePath = defaultContainer.saveFile(inputStream, toRelativePath); 186 File defaultContainerFile = defaultContainer.getFile(relativePath); 187 188 for (AttachmentContainer container : containers) { 189 try { 190 if (container != defaultContainer) { 191 container.saveFile(defaultContainerFile, toRelativePath); 192 } 193 } catch (Exception ex) { 194 LOG.error("Save file error in container: " + container, ex); 195 } 196 } 197 return relativePath.replace("\\", "/"); 198 } 199 200 201 /** 202 * 删除文件 203 * 204 * @param relativePath 205 * @return 206 */ 207 public boolean deleteFile(String relativePath) { 208 for (AttachmentContainer container : containers) { 209 try { 210 container.deleteFile(relativePath); 211 } catch (Exception ex) { 212 LOG.error("Delete file error in container: " + container, ex); 213 } 214 } 215 return defaultContainer.deleteFile(relativePath); 216 } 217 218 /** 219 * 通过相对路径获取文件 220 * 221 * @param relativePath 222 * @return 223 */ 224 public File getFile(String relativePath) { 225 //优先从 默认的 container 去获取 226 return getFile(relativePath, true); 227 } 228 229 230 /** 231 * 通过相对路径获取文件 232 * 233 * @param relativePath 234 * @param localFirst 235 * @return 236 */ 237 public File getFile(String relativePath, boolean localFirst) { 238 //优先从 默认的 container 去获取 239 if (localFirst) { 240 File localFile = defaultContainer.getFile(relativePath); 241 if (localFile.exists()) { 242 return localFile; 243 } 244 } 245 246 for (AttachmentContainer container : containers) { 247 if (container != defaultContainer) { 248 try { 249 File file = container.getFile(relativePath); 250 if (file != null && file.exists()) { 251 return file; 252 } 253 } catch (Exception ex) { 254 LOG.error("Get file error in container: " + container, ex); 255 } 256 } 257 } 258 259 //文件不存在,也返回该文件 260 return defaultContainer.getFile(relativePath); 261 } 262 263 /** 264 * 通过一个文件,获取其相对路径 265 * 266 * @param file 267 * @return 268 */ 269 public String getRelativePath(File file) { 270 String relativePath = defaultContainer.getRelativePath(file); 271 return relativePath != null ? relativePath.replace("\\", "/") : null; 272 } 273 274 275 /** 276 * 创建一个新的文件 277 * 使用创建一般是创建一个空的文件,然后由外部逻辑进行写入 278 * 279 * @param suffix 280 * @return 281 */ 282 public File createNewFile(String suffix) { 283 return getDefaultContainer().creatNewFile(suffix); 284 } 285 286 287 /** 288 * 渲染文件到浏览器 289 * 290 * @param target 291 * @param request 292 * @param response 293 * @return true 渲染成功,false 不进行渲染 294 */ 295 public boolean renderFile(String target, HttpServletRequest request, HttpServletResponse response) { 296 if (target.startsWith(defaultContainer.getTargetPrefix()) 297 && target.lastIndexOf('.') != -1) { 298 Render render; 299 if (target.contains("..")) { 300 render = renderFactory.getErrorRender(404); 301 } else { 302 File file = getFile(target); 303 render = getFileRender(file); 304 } 305 render.setContext(request, response).render(); 306 return true; 307 } else { 308 return false; 309 } 310 } 311 312 313 protected Render getFileRender(File file) { 314 return file == null || !file.isFile() 315 ? renderFactory.getErrorRender(404) 316 : renderFactory.getFileRender(file); 317 } 318 319 320}