From ae7d1d90cffa0693f1059cb2d16bcdcb5d5dc5fa Mon Sep 17 00:00:00 2001 From: Yawn Date: Tue, 4 Dec 2018 21:25:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=83=E7=89=9B=E5=92=8C?= =?UTF-8?q?=E5=8F=88=E6=8B=8D=E7=9A=84=E4=BA=91=E5=AD=98=E5=82=A8=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ryanc/halo/model/domain/Attachment.java | 5 + .../cc/ryanc/halo/model/dto/QiNiuPutSet.java | 19 ++ .../halo/model/enums/AttachLocationEnum.java | 43 +++ .../ryanc/halo/service/AttachmentService.java | 49 ++++ .../service/impl/AttachmentServiceImpl.java | 272 +++++++++++++++++- .../java/cc/ryanc/halo/utils/Md5Util.java | 58 ++++ .../admin/AttachmentController.java | 103 ++++--- src/main/resources/i18n/messages.properties | 2 + .../resources/i18n/messages_en_US.properties | 2 + .../resources/i18n/messages_zh_CN.properties | 2 + .../templates/admin/admin_option.ftl | 32 ++- .../admin/widget/_attachment-detail.ftl | 2 +- 12 files changed, 533 insertions(+), 56 deletions(-) create mode 100644 src/main/java/cc/ryanc/halo/model/dto/QiNiuPutSet.java create mode 100644 src/main/java/cc/ryanc/halo/model/enums/AttachLocationEnum.java create mode 100644 src/main/java/cc/ryanc/halo/utils/Md5Util.java diff --git a/src/main/java/cc/ryanc/halo/model/domain/Attachment.java b/src/main/java/cc/ryanc/halo/model/domain/Attachment.java index f49b84465..b9a6f4a78 100644 --- a/src/main/java/cc/ryanc/halo/model/domain/Attachment.java +++ b/src/main/java/cc/ryanc/halo/model/domain/Attachment.java @@ -70,4 +70,9 @@ public class Attachment implements Serializable { * 附件长宽 */ private String attachWh; + + /** + * 附件存储地址 + */ + private String attachLocation; } diff --git a/src/main/java/cc/ryanc/halo/model/dto/QiNiuPutSet.java b/src/main/java/cc/ryanc/halo/model/dto/QiNiuPutSet.java new file mode 100644 index 000000000..666f03ae3 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/model/dto/QiNiuPutSet.java @@ -0,0 +1,19 @@ +package cc.ryanc.halo.model.dto; + +import lombok.Data; + +/** + *
+ *     七牛上传自定义凭证回调解析
+ * 
+ * + * @author : Yawn + * @date : 2018/12/3 + */ +@Data +public class QiNiuPutSet { + + private Long size; + private Integer w; + private Integer h; +} diff --git a/src/main/java/cc/ryanc/halo/model/enums/AttachLocationEnum.java b/src/main/java/cc/ryanc/halo/model/enums/AttachLocationEnum.java new file mode 100644 index 000000000..e4bca1ec0 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/model/enums/AttachLocationEnum.java @@ -0,0 +1,43 @@ +package cc.ryanc.halo.model.enums; + +/** + *
+ *     附件存储地址enum
+ * 
+ * + * @author : Yawn + * @date : 2018/12/4 + */ +public enum AttachLocationEnum { + + /** + * 服务器 + */ + SERVER(0,"SERVER"), + + /** + * 七牛 + */ + QINIU(1,"QINIU"), + + /** + * 又拍云 + */ + UPYUN(2,"UPYUN"); + + private Integer code; + private String desc; + + AttachLocationEnum(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + + public Integer getCode() { + return code; + } + + public String getDesc() { + return desc; + } +} diff --git a/src/main/java/cc/ryanc/halo/service/AttachmentService.java b/src/main/java/cc/ryanc/halo/service/AttachmentService.java index a59ed44fb..a34e20cd5 100644 --- a/src/main/java/cc/ryanc/halo/service/AttachmentService.java +++ b/src/main/java/cc/ryanc/halo/service/AttachmentService.java @@ -3,8 +3,11 @@ package cc.ryanc.halo.service; import cc.ryanc.halo.model.domain.Attachment; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.web.multipart.MultipartFile; +import javax.servlet.http.HttpServletRequest; import java.util.List; +import java.util.Map; import java.util.Optional; /** @@ -55,4 +58,50 @@ public interface AttachmentService { * @return Attachment */ Attachment removeByAttachId(Long attachId); + + /** + * 上传转发 + * @param file + * @param request + * @return + */ + Map upload(MultipartFile file, HttpServletRequest request); + + /** + * 原生上传 + * @param file + * @param request + * @return + */ + Map attachUpload(MultipartFile file, HttpServletRequest request); + + /** + * 七牛云上传 + * @param file + * @param request + * @return + */ + Map attachQiNiuUpload(MultipartFile file, HttpServletRequest request); + + /** + * 又拍云上传 + * @param file + * @param request + * @return + */ + Map attachUpYunUpload(MultipartFile file, HttpServletRequest request); + + /** + * 七牛云删除附件 + * @param key + * @return + */ + boolean deleteQiNiuAttachment(String key); + + /** + * 又拍云删除附件 + * @param fileName + * @return + */ + boolean deleteUpYunAttachment(String fileName); } diff --git a/src/main/java/cc/ryanc/halo/service/impl/AttachmentServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/AttachmentServiceImpl.java index 2eee54a03..9aa489b9d 100644 --- a/src/main/java/cc/ryanc/halo/service/impl/AttachmentServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/AttachmentServiceImpl.java @@ -1,17 +1,45 @@ package cc.ryanc.halo.service.impl; import cc.ryanc.halo.model.domain.Attachment; +import cc.ryanc.halo.model.domain.Options; +import cc.ryanc.halo.model.dto.QiNiuPutSet; +import cc.ryanc.halo.model.enums.AttachLocationEnum; import cc.ryanc.halo.repository.AttachmentRepository; +import cc.ryanc.halo.repository.OptionsRepository; import cc.ryanc.halo.service.AttachmentService; +import cc.ryanc.halo.utils.HaloUtils; +import cc.ryanc.halo.utils.Md5Util; +import cn.hutool.core.date.DateUtil; +import com.UpYun; +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import com.qiniu.common.QiniuException; +import com.qiniu.common.Zone; +import com.qiniu.http.Response; +import com.qiniu.storage.BucketManager; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.UploadManager; +import com.qiniu.storage.persistent.FileRecorder; +import com.qiniu.util.Auth; +import com.qiniu.util.StringMap; +import com.upyun.UpException; +import net.coobird.thumbnailator.Thumbnails; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; -import java.util.List; -import java.util.Optional; +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletRequest; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.*; /** *
@@ -29,6 +57,9 @@ public class AttachmentServiceImpl implements AttachmentService {
     @Autowired
     private AttachmentRepository attachmentRepository;
 
+    @Autowired
+    private OptionsRepository optionsRepository;
+
     /**
      * 新增附件信息
      *
@@ -87,4 +118,241 @@ public class AttachmentServiceImpl implements AttachmentService {
         attachmentRepository.delete(attachment.get());
         return attachment.get();
     }
+
+    /**
+     * 上传转发
+     * @param file
+     * @param request
+     * @return
+     */
+    @Override
+    public Map upload(MultipartFile file, HttpServletRequest request) {
+        Map resultMap;
+        Options options = optionsRepository.findOptionsByOptionName("attach_loc");
+        if(options == null){
+            return null;
+        }
+        switch (options.getOptionValue()){
+            case "server":
+                resultMap = this.attachUpload(file,request);
+                break;
+            case "qiniu":
+                resultMap = this.attachQiNiuUpload(file,request);
+                break;
+            case "upyun":
+                resultMap = this.attachUpYunUpload(file,request);
+                break;
+            default:
+                resultMap = this.attachUpload(file,request);
+                break;
+        }
+        return resultMap;
+    }
+
+    /**
+     * 原生服务器上传
+     * @param file
+     * @param request
+     * @return
+     */
+    @Override
+    public Map attachUpload(MultipartFile file, HttpServletRequest request) {
+        Map resultMap = new HashMap<>(6);
+        try {
+            //用户目录
+            String userPath = System.getProperties().getProperty("user.home") + "/halo";
+            //upload的路径
+            StringBuffer sbMedia = new StringBuffer("upload/");
+            //获取当前年月以创建目录,如果没有该目录则创建
+            sbMedia.append(DateUtil.thisYear()).append("/").append(DateUtil.thisMonth()).append("/");
+            File mediaPath = new File(userPath, sbMedia.toString());
+            if (!mediaPath.exists()) {
+                mediaPath.mkdirs();
+            }
+            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+            String nameWithOutSuffix = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf('.')).replaceAll(" ", "_").replaceAll(",", "") + dateFormat.format(DateUtil.date()) + new Random().nextInt(1000);
+            String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.') + 1);
+            String fileName = nameWithOutSuffix + "." + fileSuffix;
+            file.transferTo(new File(mediaPath.getAbsoluteFile(), fileName));
+            //压缩图片
+            Thumbnails.of(new StringBuffer(mediaPath.getAbsolutePath()).append("/").append(fileName).toString()).size(256, 256).keepAspectRatio(false).toFile(new StringBuffer(mediaPath.getAbsolutePath()).append("/").append(nameWithOutSuffix).append("_small.").append(fileSuffix).toString());
+            String filePath = new StringBuffer("/upload/").append(DateUtil.thisYear()).append("/").append(DateUtil.thisMonth()).append("/").append(fileName).toString();
+            String smallPath = new StringBuffer("/upload/").append(DateUtil.thisYear()).append("/").append(DateUtil.thisMonth()).append("/").append(nameWithOutSuffix).append("_small.").append(fileSuffix).toString();
+            String suffix = new StringBuffer(".").append(fileSuffix).toString();
+            String size = HaloUtils.parseSize(new File(mediaPath, fileName).length());
+            String wh = HaloUtils.getImageWh(new File(mediaPath, fileName));
+            resultMap.put("fileName",fileName);
+            resultMap.put("filePath",filePath);
+            resultMap.put("smallPath",smallPath);
+            resultMap.put("suffix",suffix);
+            resultMap.put("size",size);
+            resultMap.put("wh",wh);
+            resultMap.put("location", AttachLocationEnum.SERVER.getDesc());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return resultMap;
+    }
+
+    /**
+     * 七牛云上传
+     * @param file
+     * @param request
+     * @return
+     */
+    @Override
+    public Map attachQiNiuUpload(MultipartFile file, HttpServletRequest request) {
+        Map resultMap = new HashMap<>(6);
+        try {
+            Configuration cfg = new Configuration(Zone.zone0());
+            String key = Md5Util.getMD5Checksum(file);
+            Options accessKey = optionsRepository.findOptionsByOptionName("qiniu_access_key");
+            Options secretKey = optionsRepository.findOptionsByOptionName("qiniu_secret_key");
+            Options domain = optionsRepository.findOptionsByOptionName("qiniu_domain");
+            Options bucket = optionsRepository.findOptionsByOptionName("qiniu_bucket");
+            Options smallUrl = optionsRepository.findOptionsByOptionName("qiniu_small_url");
+            if(accessKey == null || secretKey == null || domain == null || bucket == null){
+                return resultMap;
+            }
+            Auth auth = Auth.create(accessKey.getOptionValue(),secretKey.getOptionValue());
+            StringMap putPolicy = new StringMap();
+            putPolicy.put("returnBody", "{\"size\":$(fsize),\"w\":$(imageInfo.width),\"h\":$(imageInfo.height)}");
+            String upToken = auth.uploadToken(bucket.getOptionValue(),null,3600,putPolicy);
+            String localTempDir = Paths.get(System.getenv("java.io.tmpdir"),bucket.getOptionValue()).toString();
+            QiNiuPutSet putSet = new QiNiuPutSet();
+            try {
+                FileRecorder fileRecorder = new FileRecorder(localTempDir);
+                UploadManager uploadManager = new UploadManager(cfg,fileRecorder);
+                Response response = uploadManager.put(file.getInputStream(),key,upToken,null,null);
+                //解析上传成功的结果
+                putSet = new Gson().fromJson(response.bodyString(), QiNiuPutSet.class);
+            } catch (QiniuException e) {
+                Response r = e.response;
+                System.err.println(r.toString());
+                try {
+                    System.err.println(r.bodyString());
+                } catch (QiniuException ex2) {
+                    //ignore
+                }
+            } catch (JsonSyntaxException e) {
+                e.printStackTrace();
+            }catch (IOException e){
+                e.printStackTrace();
+            }
+            String filePath = domain.getOptionValue().contains("http://")?domain.getOptionValue().trim():("http://"+domain.getOptionValue().trim()) + "/" + key;
+            resultMap.put("fileName",file.getOriginalFilename());
+            resultMap.put("filePath",filePath.trim());
+            resultMap.put("smallPath",smallUrl == null ? filePath.trim():(filePath+smallUrl.getOptionValue()).trim());
+            resultMap.put("suffix",file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.')));
+            resultMap.put("size",HaloUtils.parseSize(file.getSize()));
+            resultMap.put("wh",putSet.getW() + "x" + putSet.getH());
+            resultMap.put("location", AttachLocationEnum.QINIU.getDesc());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return resultMap;
+    }
+
+    /**
+     * 又拍云上传
+     * @param file
+     * @param request
+     * @return
+     */
+    @Override
+    public Map attachUpYunUpload(MultipartFile file, HttpServletRequest request) {
+        Map resultMap = new HashMap<>(6);
+        try {
+            String key = Md5Util.getMD5Checksum(file);
+            Options ossSrc = optionsRepository.findOptionsByOptionName("upyun_oss_src");
+            Options ossPwd = optionsRepository.findOptionsByOptionName("upyun_oss_pwd");
+            Options bucket = optionsRepository.findOptionsByOptionName("upyun_oss_bucket");
+            Options domain = optionsRepository.findOptionsByOptionName("upyun_oss_domain");
+            Options operator = optionsRepository.findOptionsByOptionName("upyun_oss_operator");
+            Options smallUrl = optionsRepository.findOptionsByOptionName("upyun_oss_small");
+            if(ossSrc == null || ossPwd == null || domain == null || bucket == null || operator == null){
+                return resultMap;
+            }
+            String fileName = file.getOriginalFilename();
+            String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));
+            UpYun upYun = new UpYun(bucket.getOptionValue(),operator.getOptionValue(),ossPwd.getOptionValue());
+            upYun.setTimeout(60);
+            upYun.setApiDomain(UpYun.ED_AUTO);
+            upYun.setDebug(true);
+            upYun.writeFile(ossSrc.getOptionValue()+key+"."+fileSuffix,file.getBytes(),true,null);
+            String filePath = domain.getOptionValue().contains("http://")?domain.getOptionValue().trim():("http://"+domain.getOptionValue().trim() +ossSrc.getOptionValue() + key + "." + fileSuffix);
+            String smallPath = filePath;
+            if(smallUrl != null){
+                smallPath += smallUrl.getOptionValue();
+            }
+            BufferedImage image = ImageIO.read(file.getInputStream());
+            if (image != null) {
+                resultMap.put("wh",image.getWidth()+"x"+image.getHeight());
+            }
+            resultMap.put("fileName",fileName);
+            resultMap.put("filePath",filePath.trim());
+            resultMap.put("smallPath",smallPath.trim());
+            resultMap.put("suffix",fileSuffix);
+            resultMap.put("size",HaloUtils.parseSize(file.getSize()));
+            resultMap.put("location", AttachLocationEnum.UPYUN.getDesc());
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return resultMap;
+    }
+
+    /**
+     * 七牛云删除附件
+     * @param key
+     * @return
+     */
+    @Override
+    public boolean deleteQiNiuAttachment(String key) {
+        boolean flag = true;
+        Configuration cfg = new Configuration(Zone.zone0());
+        Options accessKey = optionsRepository.findOptionsByOptionName("qiniu_access_key");
+        Options secretKey = optionsRepository.findOptionsByOptionName("qiniu_secret_key");
+        Options bucket = optionsRepository.findOptionsByOptionName("qiniu_bucket");
+        if(accessKey == null || secretKey == null || bucket == null){
+            return false;
+        }
+        Auth auth = Auth.create(accessKey.getOptionValue(), secretKey.getOptionValue());
+        BucketManager bucketManager = new BucketManager(auth, cfg);
+        try {
+            bucketManager.delete(bucket.getOptionValue(), key);
+        } catch (QiniuException ex) {
+            System.err.println(ex.code());
+            System.err.println(ex.response.toString());
+            flag = false;
+        }
+        return flag;
+    }
+
+    /**
+     * 又拍云删除附件
+     * @param fileName
+     * @return
+     */
+    @Override
+    public boolean deleteUpYunAttachment(String fileName) {
+        boolean flag = true;
+        Options ossSrc = optionsRepository.findOptionsByOptionName("upyun_oss_src");
+        Options ossPwd = optionsRepository.findOptionsByOptionName("upyun_oss_pwd");
+        Options bucket = optionsRepository.findOptionsByOptionName("upyun_oss_bucket");
+        Options operator = optionsRepository.findOptionsByOptionName("upyun_oss_operator");
+        if(ossSrc == null || ossPwd == null || bucket == null || operator == null){
+            return false;
+        }
+        UpYun upYun = new UpYun(bucket.getOptionValue(),operator.getOptionValue(),ossPwd.getOptionValue());
+        upYun.setApiDomain(UpYun.ED_AUTO);
+        try {
+            flag = upYun.deleteFile(ossSrc.getOptionValue()+fileName);
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (UpException e) {
+            e.printStackTrace();
+        }
+        return flag;
+    }
 }
diff --git a/src/main/java/cc/ryanc/halo/utils/Md5Util.java b/src/main/java/cc/ryanc/halo/utils/Md5Util.java
new file mode 100644
index 000000000..f1c5fd31d
--- /dev/null
+++ b/src/main/java/cc/ryanc/halo/utils/Md5Util.java
@@ -0,0 +1,58 @@
+package cc.ryanc.halo.utils;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.InputStream;
+import java.security.MessageDigest;
+
+/**
+ * 
+ *      获取文件hash
+ * 
+ * + * @author : Yawn + * @date : 2018/12/04 + */ +public class Md5Util { + + /** + * 计算文件MD5编码 + * @param file + * @return + * @throws Exception + */ + public static byte[] createChecksum(MultipartFile file) throws Exception { + InputStream fis = file.getInputStream(); + + byte[] buffer = new byte[1024]; + MessageDigest complete = MessageDigest.getInstance("MD5"); + int numRead; + + do { + numRead = fis.read(buffer); + if (numRead > 0) { + complete.update(buffer, 0, numRead); + } + } while (numRead != -1); + + fis.close(); + return complete.digest(); + } + + /** + * 生成文件hash值 + * @param file + * @return + * @throws Exception + */ + public static String getMD5Checksum(MultipartFile file) throws Exception { + byte[] b = createChecksum(file); + String result = ""; + + for (int i=0; i < b.length; i++) { + result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 ); + } + return result; + } + +} diff --git a/src/main/java/cc/ryanc/halo/web/controller/admin/AttachmentController.java b/src/main/java/cc/ryanc/halo/web/controller/admin/AttachmentController.java index 22c707960..78115c907 100755 --- a/src/main/java/cc/ryanc/halo/web/controller/admin/AttachmentController.java +++ b/src/main/java/cc/ryanc/halo/web/controller/admin/AttachmentController.java @@ -33,6 +33,10 @@ import java.util.Map; import java.util.Optional; import java.util.Random; +import static cc.ryanc.halo.model.enums.AttachLocationEnum.QINIU; +import static cc.ryanc.halo.model.enums.AttachLocationEnum.SERVER; +import static cc.ryanc.halo.model.enums.AttachLocationEnum.UPYUN; + /** *
  *     后台附件控制器
@@ -118,47 +122,36 @@ public class AttachmentController {
     public Map upload(@RequestParam("file") MultipartFile file,
                                       HttpServletRequest request) {
         Map result = new HashMap<>(3);
+        System.out.println("源地址"+file.getOriginalFilename()+"类型"+file.getContentType()+"文件名"+file.getName()+"文件大小"+file.getSize());
         if (!file.isEmpty()) {
             try {
-                //用户目录
-                String userPath = System.getProperties().getProperty("user.home") + "/halo";
-                //upload的路径
-                StringBuffer sbMedia = new StringBuffer("upload/");
-                //获取当前年月以创建目录,如果没有该目录则创建
-                sbMedia.append(DateUtil.thisYear()).append("/").append(DateUtil.thisMonth()).append("/");
-                File mediaPath = new File(userPath, sbMedia.toString());
-                if (!mediaPath.exists()) {
-                    mediaPath.mkdirs();
+                Map resultMap = attachmentService.upload(file,request);
+                if(resultMap == null || resultMap.isEmpty()){
+                    log.error("文件上传失败");
+                    result.put("success", 0);
+                    result.put("message", localeMessageUtil.getMessage("code.admin.attachment.upload-failed"));
+                    return result;
                 }
-                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
-                String nameWithOutSuffix = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf('.')).replaceAll(" ", "_").replaceAll(",", "") + dateFormat.format(DateUtil.date()) + new Random().nextInt(1000);
-                String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.') + 1);
-                String fileName = nameWithOutSuffix + "." + fileSuffix;
-                file.transferTo(new File(mediaPath.getAbsoluteFile(), fileName));
-
-                //压缩图片
-                Thumbnails.of(new StringBuffer(mediaPath.getAbsolutePath()).append("/").append(fileName).toString()).size(256, 256).keepAspectRatio(false).toFile(new StringBuffer(mediaPath.getAbsolutePath()).append("/").append(nameWithOutSuffix).append("_small.").append(fileSuffix).toString());
-                String filePath = new StringBuffer("/upload/").append(DateUtil.thisYear()).append("/").append(DateUtil.thisMonth()).append("/").append(fileName).toString();
                 //保存在数据库
                 Attachment attachment = new Attachment();
-                attachment.setAttachName(fileName);
-                attachment.setAttachPath(filePath);
-                attachment.setAttachSmallPath(new StringBuffer("/upload/").append(DateUtil.thisYear()).append("/").append(DateUtil.thisMonth()).append("/").append(nameWithOutSuffix).append("_small.").append(fileSuffix).toString());
+                attachment.setAttachName(resultMap.get("fileName"));
+                attachment.setAttachPath(resultMap.get("filePath"));
+                attachment.setAttachSmallPath(resultMap.get("smallPath"));
                 attachment.setAttachType(file.getContentType());
-                attachment.setAttachSuffix(new StringBuffer(".").append(fileSuffix).toString());
+                attachment.setAttachSuffix(resultMap.get("suffix"));
                 attachment.setAttachCreated(DateUtil.date());
-                attachment.setAttachSize(HaloUtils.parseSize(new File(mediaPath, fileName).length()));
-                attachment.setAttachWh(HaloUtils.getImageWh(new File(mediaPath, fileName)));
+                attachment.setAttachSize(resultMap.get("size"));
+                attachment.setAttachWh(resultMap.get("wh"));
+                attachment.setAttachLocation(resultMap.get("location"));
                 attachmentService.saveByAttachment(attachment);
-                log.info("Upload file {} to {} successfully", fileName, mediaPath.getAbsolutePath());
+                log.info("Upload file {} to {} successfully", resultMap.get("fileName"), resultMap.get("filePath"));
                 logsService.saveByLogs(
-                        new Logs(LogsRecord.UPLOAD_FILE, fileName, ServletUtil.getClientIP(request), DateUtil.date())
+                        new Logs(LogsRecord.UPLOAD_FILE, resultMap.get("fileName"), ServletUtil.getClientIP(request), DateUtil.date())
                 );
-
                 result.put("success", 1);
                 result.put("message", localeMessageUtil.getMessage("code.admin.attachment.upload-success"));
                 result.put("url", attachment.getAttachPath());
-                result.put("filename", filePath);
+                result.put("filename", resultMap.get("filePath"));
             } catch (Exception e) {
                 log.error("Upload file failed:{}", e.getMessage());
                 result.put("success", 0);
@@ -196,28 +189,52 @@ public class AttachmentController {
     public JsonResult removeAttachment(@RequestParam("attachId") Long attachId,
                                        HttpServletRequest request) {
         Optional attachment = attachmentService.findByAttachId(attachId);
+        String attachLocation = attachment.get().getAttachLocation();
         String delFileName = attachment.get().getAttachName();
-        String delSmallFileName = delFileName.substring(0, delFileName.lastIndexOf('.')) + "_small" + attachment.get().getAttachSuffix();
+        boolean flag = true;
         try {
             //删除数据库中的内容
             attachmentService.removeByAttachId(attachId);
-            //删除文件
-            String userPath = System.getProperties().getProperty("user.home") + "/halo";
-            File mediaPath = new File(userPath, attachment.get().getAttachPath().substring(0, attachment.get().getAttachPath().lastIndexOf('/')));
-            File delFile = new File(new StringBuffer(mediaPath.getAbsolutePath()).append("/").append(delFileName).toString());
-            File delSmallFile = new File(new StringBuffer(mediaPath.getAbsolutePath()).append("/").append(delSmallFileName).toString());
-            if (delFile.exists() && delFile.isFile()) {
-                if (delFile.delete() && delSmallFile.delete()) {
-                    log.info("Delete file {} successfully!", delFileName);
-                    logsService.saveByLogs(
-                            new Logs(LogsRecord.REMOVE_FILE, delFileName, ServletUtil.getClientIP(request), DateUtil.date())
-                    );
-                } else {
-                    log.error("Deleting attachment {} failed!", delFileName);
-                    return new JsonResult(ResultCodeEnum.FAIL.getCode(), localeMessageUtil.getMessage("code.admin.common.delete-failed"));
+            if(attachLocation!=null){
+                if(attachLocation.equals(SERVER.getDesc())){
+                    String delSmallFileName = delFileName.substring(0, delFileName.lastIndexOf('.')) + "_small" + attachment.get().getAttachSuffix();
+                    //删除文件
+                    String userPath = System.getProperties().getProperty("user.home") + "/halo";
+                    File mediaPath = new File(userPath, attachment.get().getAttachPath().substring(0, attachment.get().getAttachPath().lastIndexOf('/')));
+                    File delFile = new File(new StringBuffer(mediaPath.getAbsolutePath()).append("/").append(delFileName).toString());
+                    File delSmallFile = new File(new StringBuffer(mediaPath.getAbsolutePath()).append("/").append(delSmallFileName).toString());
+                    if (delFile.exists() && delFile.isFile()) {
+                        if (delFile.delete() && delSmallFile.delete()) {
+                            flag = true;
+                        } else {
+                            flag = false;
+                        }
+                    }
+                }else if(attachLocation.equals(QINIU.getDesc())){
+                    //七牛删除
+                    String attachPath = attachment.get().getAttachPath();
+                    String key =attachPath.substring(attachPath.lastIndexOf("/")+1);
+                    flag = attachmentService.deleteQiNiuAttachment(key);
+                }else if(attachLocation.equals(UPYUN.getDesc())){
+                    //又拍删除
+                    String attachPath = attachment.get().getAttachPath();
+                    String fileName =attachPath.substring(attachPath.lastIndexOf("/")+1);
+                    flag = attachmentService.deleteUpYunAttachment(fileName);
+                }else{
+                    //..
                 }
             }
+            if(flag){
+                log.info("Delete file {} successfully!", delFileName);
+                logsService.saveByLogs(
+                        new Logs(LogsRecord.REMOVE_FILE, delFileName, ServletUtil.getClientIP(request), DateUtil.date())
+                );
+            }else{
+                log.error("Deleting attachment {} failed!", delFileName);
+                return new JsonResult(ResultCodeEnum.FAIL.getCode(), localeMessageUtil.getMessage("code.admin.common.delete-failed"));
+            }
         } catch (Exception e) {
+            e.printStackTrace();
             log.error("Deleting attachment {} failed: {}", delFileName, e.getMessage());
             return new JsonResult(ResultCodeEnum.FAIL.getCode(), localeMessageUtil.getMessage("code.admin.common.delete-failed"));
         }
diff --git a/src/main/resources/i18n/messages.properties b/src/main/resources/i18n/messages.properties
index 118f1076c..716971953 100644
--- a/src/main/resources/i18n/messages.properties
+++ b/src/main/resources/i18n/messages.properties
@@ -217,7 +217,9 @@ admin.setting.form.upyun-oss-bucket = 空间名称:
 admin.setting.form.upyun-oss-operator = 操作员名称:
 admin.setting.form.upyun-oss-pwd = 操作员密码:
 admin.setting.form.upyun-oss-src = 文件目录:
+admin.setting.form.upyun-oss-small = 处理策略:
 admin.setting.form.qiniu-domain = 域名:
+admin.setting.form.qiniu-small-url = 处理策略:
 admin.setting.form.admin-pjax = 启用 pjax:
 admin.setting.form.admin-loading = 后台加载动画:
 admin.setting.form.admin-layout = 后台布局:
diff --git a/src/main/resources/i18n/messages_en_US.properties b/src/main/resources/i18n/messages_en_US.properties
index f1fce6e20..e5b028d3d 100644
--- a/src/main/resources/i18n/messages_en_US.properties
+++ b/src/main/resources/i18n/messages_en_US.properties
@@ -217,7 +217,9 @@ admin.setting.form.upyun-oss-bucket = Bucket name:
 admin.setting.form.upyun-oss-operator = Operator
 admin.setting.form.upyun-oss-pwd = Password
 admin.setting.form.upyun-oss-src = File Directory:
+admin.setting.form.upyun-oss-small = Strategy:
 admin.setting.form.qiniu-domain = Domain:
+admin.setting.form.qiniu-small-url = Strategy:
 admin.setting.form.admin-pjax = Pjax:
 admin.setting.form.admin-loading = Load animation:
 admin.setting.form.admin-layout = Layout:
diff --git a/src/main/resources/i18n/messages_zh_CN.properties b/src/main/resources/i18n/messages_zh_CN.properties
index 118f1076c..716971953 100644
--- a/src/main/resources/i18n/messages_zh_CN.properties
+++ b/src/main/resources/i18n/messages_zh_CN.properties
@@ -217,7 +217,9 @@ admin.setting.form.upyun-oss-bucket = 空间名称:
 admin.setting.form.upyun-oss-operator = 操作员名称:
 admin.setting.form.upyun-oss-pwd = 操作员密码:
 admin.setting.form.upyun-oss-src = 文件目录:
+admin.setting.form.upyun-oss-small = 处理策略:
 admin.setting.form.qiniu-domain = 域名:
+admin.setting.form.qiniu-small-url = 处理策略:
 admin.setting.form.admin-pjax = 启用 pjax:
 admin.setting.form.admin-loading = 后台加载动画:
 admin.setting.form.admin-layout = 后台布局:
diff --git a/src/main/resources/templates/admin/admin_option.ftl b/src/main/resources/templates/admin/admin_option.ftl
index ee48453f6..d82f591ce 100755
--- a/src/main/resources/templates/admin/admin_option.ftl
+++ b/src/main/resources/templates/admin/admin_option.ftl
@@ -361,20 +361,20 @@
                                     
- <#--
--> - <#----> - <#--
--> - <#----> - <#--
--> - <#--
-->
- + +
+ +
+
+
+
- +
@@ -383,9 +383,9 @@
- <#--
+
+ +
+ +
+
@@ -447,6 +453,12 @@ +
+ +
+ +
+