首页 > 其他分享 >021-管理后台附件功能开发

021-管理后台附件功能开发

时间:2023-09-09 14:35:01浏览次数:33  
标签:return String private 后台 021 附件 上传 public

1.功能分析

1.1. 查询列表

1.1.1. 页面效果

021-管理后台附件功能开发_附件上传

1.1.2. 功能要求

  • 分页查询默认查询10条每页从第1页开始查询
  • 附件提供查询,删除操作
  • 点击上传按钮弹出上传附件页面
  • 搜索条件
  • 附件名称:支持模糊搜索
  • 点击搜索按钮是按照录入的搜索条件进行查询数据并渲染
  • 点击重置按钮的时候清空搜索条件,并重新渲染数据

1.2. 上传附件

1.2.1. 页面效果

021-管理后台附件功能开发_fileinput_02

1.2.2. 功能要求

  • 存储位置必填项
  • 上传文件可自行指定类型,如不指定文件类型则可上传所有类型的文件信息
  • 开放本地文件上传
  • 成功添加数据后列表页进行刷新

1.3. 删除文件

1.3.1. 功能要求

  • 点击删除按钮需给出提示框进行二次确认,当二次确认后可进行删除操作
  • 成功删除数据后列表页进行刷新
  • 删除操作时需同时删除已上传的附件信息

2.功能实现

2.1. 初期准备

2.1.1. 创建数据库 zh_attachment_info

CREATE TABLE `zh_attachment_info` (
 `id` bigint NOT NULL AUTO_INCREMENT,
 `attachment_name` varchar(255) DEFAULT NULL COMMENT '附件名称',
 `attachment_url` varchar(255)  DEFAULT NULL COMMENT '附件地址',
 `attachment_type` varchar(255) DEFAULT NULL COMMENT '附件类型 1.图片 2.音乐 3.视频',
 `attachment_size` varchar(255) DEFAULT NULL COMMENT '长度',
 `attachment_post` varchar(255) DEFAULT NULL COMMENT '附件位置 local:本地',
 `original_name` varchar(255)  DEFAULT NULL COMMENT '附件原始名称',
 `thumbnail_url` varchar(255)  DEFAULT NULL COMMENT '缩略图地址',
 `content_type` varchar(255)   DEFAULT NULL COMMENT '内容类型',
 `create_time` datetime DEFAULT NULL COMMENT '创建时间',
 `create_user_code` varchar(255)  DEFAULT NULL COMMENT '创建人编号',
 `create_user_name` varchar(255)  DEFAULT NULL COMMENT '创建时间',
 `update_time` datetime DEFAULT NULL COMMENT '修改时间',
 `update_user_code` varchar(255)  DEFAULT NULL COMMENT '修改人编号',
 `update_user_name` varchar(255)  DEFAULT NULL COMMENT '修改人名称',
 PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 COMMENT='附件表';

2.1.2. 创建控制层AttachmentInfoController

package com.zhuhuo.modual.controller.manager;

import com.zhuhuo.modual.service.AttachmentInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping(value = "/m/attachmentInfo")
public class CategoryController {

   @Autowired
   private AttachmentInfoService attachmentInfoService;

}

2.1.3. 创建实体映射AttachmentInfo

package com.zhuhuo.modual.entity;

import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Id;


@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "zh_attachment_info")
public class AttachmentInfo implements Serializable {

   private static final long serialVersionUID = 1L;
    /**
    *
    */
   @Id
   private Long id;
   /**
    * 附件名称
    */
   private String attachmentName;
   /**
    * 附件地址
    */
   private String attachmentUrl;
   /**
    * 附件类型 1.图片 2.音乐 3.视频
    */
   private String attachmentType;
   /**
    * 长度
    */
   private String attachmentSize;
   /**
    * 附件位置 local:本地 minio:minio qiniu:七牛云 oss:阿里云 cos:腾讯云 hwyun:华为云
    */
   private String attachmentPost;

   /**
    * 附件原始名称
    */
   private String originalName;
   /**
    * 缩略图地址
    */
   private String thumbnailUrl;
   /**
    * 内容类型
    */
   private String contentType;
   /**
    * 创建时间
    */
   private Date createTime;
   /**
    * 创建人编号
    */
   private String createUserCode;
   /**
    * 创建时间
    */
   private String createUserName;
   /**
    * 修改时间
    */
   private Date updateTime;
   /**
    * 修改人编号
    */
   private String updateUserCode;
   /**
    * 修改人名称
    */
   private String updateUserName;
}

2.1.4. 创建AttachmentInfoMapper, AttachmentInfoMapper.xml

package com.zhuhuo.modual.mapper;

import com.zhuhuo.core.frame.mapper.BasicsMapper;
import com.zhuhuo.modual.entity.AttachmentInfo;

public interface AttachmentInfoMapper extends BasicsMapper<AttachmentInfo>{

}
<?xml versinotallow="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.zhuhuo.modual.mapper.AttachmentInfoMapper">
   <resultMap id="BaseResultMap" type="com.zhuhuo.modual.entity.AttachmentInfo">
       <id column="id" property="id" jdbcType="BIGINT"/>
       <result column="attachment_name" property="attachmentName" jdbcType="VARCHAR"/>
       <result column="attachment_url" property="attachmentUrl" jdbcType="VARCHAR"/>
       <result column="attachment_type" property="attachmentType" jdbcType="VARCHAR"/>
       <result column="attachment_size" property="attachmentSize" jdbcType="VARCHAR"/>
       <result column="attachment_post" property="attachmentPost" jdbcType="VARCHAR"/>
       <result column="original_name" property="originalName" jdbcType="VARCHAR"/>
       <result column="thumbnail_url" property="thumbnailUrl" jdbcType="VARCHAR"/>
       <result column="content_type" property="contentType" jdbcType="VARCHAR"/>
       <result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
       <result column="create_user_code" property="createUserCode" jdbcType="VARCHAR"/>
       <result column="create_user_name" property="createUserName" jdbcType="VARCHAR"/>
       <result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
       <result column="update_user_code" property="updateUserCode" jdbcType="VARCHAR"/>
       <result column="update_user_name" property="updateUserName" jdbcType="VARCHAR"/>
   </resultMap>

   <sql id="base_column_list">
      id, attachment_name, attachment_url, attachment_type, attachment_size, attachment_post, original_name,
      thumbnail_url, content_type, create_time, create_user_code, create_user_name, update_time, 
      update_user_code, update_user_name    
   </sql>
</mapper>

2.1.5. 创建AttachmentInfoService ,AttachmentInfoServiceImpl

package com.zhuhuo.modual.service;


public interface AttachmentInfoService {

}
package com.zhuhuo.modual.service.impl;

import com.zhuhuo.modual.mapper.AttachmentInfoMapper;
import com.zhuhuo.modual.service.AttachmentInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("attachmentInfoService")
public class AttachmentInfoServiceImpl implements AttachmentInfoService {

    @Autowired
    private AttachmentInfoMapper attachmentInfoMapper;

}

2.2. 查询附件列表

2.2.1. 静态页面

2.2.1.1. 页面布局

<!DOCTYPE html>
<html lang="en">
<head>
    <div th:replace="/manager/common/common :: core-head('附件列表','','')"></div>
    <div th:replace="/manager/common/common :: core-css"></div>
    <div th:replace="/manager/common/common :: lib-bootstrap-table-css"></div>
</head>
<body class="gray-bg">
<div class="wrapper wrapper-content">
    <div class="panel">
        <div class="panel-body">
            <form role="search-form" class="form-inline" id="search-form">
                <div class="form-group">
                    <label class="control-label">附件名称</label>
                    <input type="text" placeholder="请输附件名称" id="attachmentName" 
                           name="attachmentName" class="form-control">
                </div>
                <a class="btn btn-primary" notallow="$.bstable.search()">
                  <i class="fa fa-search"></i> 搜索
              	</a>
                <a class="btn btn-warning" notallow="$.bstable.reset()">
                  <i class="fa fa-refresh"></i> 重置
              	</a>
            </form>
        </div>
    </div>

    <div class="panel">
        <div class="panel-body">
            <div class="btn-group-sm" id="toolbar" role="group">
                <a class="btn btn-success" notallow="$.action.addPage()">
                    <i class="fa fa-plus"></i> 上传
                </a>
            </div>

            <div class="select-table table-striped">
                <table id="bootstrap-table-list"></table>
            </div>
        </div>
    </div>

</div>
<div th:replace="/manager/common/common :: core-js"></div>
<div th:replace="/manager/common/common :: lib-bootstrap-table-js"></div>
<script th:src="@{/local/js/zhuhuo.js}"></script>
</body>
</html>

2.2.1.2. 初始化表格js

var options = {
        url: "/m/attachmentInfo/findAttachmentInfoList",
        modualName: "附件",
        columns: [
            {
                checkbox: true
            },
            {
                field: 'attachmentName',
                title: '附件名称'
            },
            {
                field: 'attachmentUrl',
                title: '附件地址'
            },
            {
                field: 'attachmentType',
                title: '附件类型',
                formatter: function (value, item, index) {
                    if (item.attachmentType == '1') {
                        return '图片';
                    } else  if (item.attachmentType == '2') {
                        return '音乐';
                    } else if(item.attachmentType == '3'){
                        return '视频';
                    }else {
                        return "未知";
                    }
                }
            },
            {
                field: 'attachmentPost',
                title: '附件位置',
                formatter: function (value, item, index) {
                    if (item.attachmentPost == 'local') {
                        return '本地';
                    } else  {
                        return 'OSS';
                    }
                }
            },
            {
                field: 'thumbnailUrl',
                title: '缩略图地址',
                formatter: function (value, item, index) {
                    return '<img src="'+item.thumbnailUrl+'"  
                     						 alt="'+item.attachmentName+'" 
                  						   title="'+item.attachmentName+'" 
                 								 width="80" height="80"/>';
                }
            },
            {
                field: 'contentType',
                title: '内容类型'
            },

            {
                title: '操作',
                align: 'center',
                width: '150px',
                formatter: function actionFormatter(value, item) {
                    let btnArr = [];
                    btnArr.push('<button type="button" class="btn btn-sm btn-secondary" 
                                data-toggle="tooltip" title="查看明细"  
                                notallow="$.action.viewPage(' + item.id + ')">
                                <i class="fa fa-search"></i></button>');
                    btnArr.push('<button type="button" class="btn btn-sm btn-secondary" 
                                data-toggle="tooltip" title="删除" 
                                notallow="$.action.remove(' + item.id + ')">
                                <i class="fa fa-times"></i></button>');
                    return btnArr.join(" ");
                },
            }
        ],
    }
    $.bstable.init(options)

2.3.1.3. sidebar修改

<li>
  <a class="zh-menu-item" th:href="@{/m/attachmentInfo/findAttachmentInfoPage}">
    <i class="fa fa-file-o"></i>附件管理
  </a>
</li>

2.2.2. 列表功能

2.2.2.1. 创建查询列表页面方法

@ActionLog(modual = "附件管理" ,methodDesc = "查询附件列表页面",source = LogSource.MANAGER,logtype = LogType.VIEW)
@GetMapping(value = "findAttachmentInfoPage")
public String findAttachmentInfoPage(){
    return "/manager/attachmentInfo/list";
}

2.2.2.2.创建请求对象和响应对象

2.2.2.2.1. 请求对象 AttachmentInfoListBO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AttachmentInfoListBO {

    /**
     * 主键id 
     */
    private Long id;
    /**
     * 附件名称
     */
    private String attachmentName;

    /**
     * 分页数量
     */
    private Integer pageNum;

    /**
     * 分页条数
     */
    private Integer pageSize;

}
2.2.2.2.2. 响应对象 AttachmentInfoListDTO
@Data
@NoArgsConstructor
@AllArgsConstructor
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AttachmentInfoListDTO {

    /**
     *
     */
    private Long id;
    /**
     * 附件名称
     */
    private String attachmentName;
    /**
     * 附件地址
     */
    private String attachmentUrl;
    /**
     * 附件类型  1.图片 2.音乐 3.视频
     */
    private String attachmentType;
    /**
     * 附件大小
     */
    private String attachmentSize;
  
    /**
     * 附件位置 local.本地 2.OSS
     */
    private String attachmentPost;

    /**
     * 缩略图地址
     */
    private String thumbnailUrl;
    /**
     * 内容类型
     */
    private String contentType;

}

2.2.2.3. 创建查询列表明细方法

2.2.2.3.1. controller
@ActionLog(modual = "附件管理" ,methodDesc = "查询附件列表方法",source = LogSource.MANAGER,logtype = LogType.VIEW)
  @ResponseBody
  @GetMapping(value = "/findAttachmentInfoList")
  public RespJsonPageData<AttachmentInfoListDTO> findAttachmentInfoList(
         AttachmentInfoListBO attachmentInfoListBO){
      return attachmentInfoService.findAttachmentInfoList(attachmentInfoListBO);
  }
2.2.2.3.2. service
RespJsonPageData<AttachmentInfoListDTO> findAttachmentInfoList(AttachmentInfoListBO attachmentInfoListBO);
2.2.2.3.3. serviceImpl
public RespJsonPageData<AttachmentInfoListDTO> findAttachmentInfoList(AttachmentInfoListBO attachmentInfoListBO) {
    PageQuery query = new PageQuery(attachmentInfoListBO);
    Page<Object> result = PageHelper.startPage(query.getPageNum(), query.getPageSize());
    List<AttachmentInfo> attachmentInfoList = 
      attachmentInfoMapper.findAttachmentInfoList(MapUtils.objToMap(attachmentInfoListBO));
    List<AttachmentInfoListDTO> attachmentInfoListDTOList = 
      JacksonUtil.transformList(JacksonUtil.transformJSONCompact(attachmentInfoList),
                                AttachmentInfoListDTO.class);
    return RespJsonPageData.success(attachmentInfoListDTOList, result.getTotal());
}
2.2.2.3.4. mapper
List<AttachmentInfo> findAttachmentInfoList(Map<String, Object> params);
2.2.2.3.5. xml
<select id="findAttachmentInfoList" parameterType="java.util.Map" resultMap="BaseResultMap">
    select
    <include refid="base_column_list"/>
    from zh_attachment_info
    <include refid="search_list_condition"/>
</select>

<sql id="search_list_condition">
    <where>
        <if test="attachmentName != null and attachmentName != '' ">
            and attachment_name like concat('%',#{attachmentName},'%')
        </if>
    </where>
</sql>

2.2.2.4. 添加本地资源映射

2.2.2.4.1. 修改WebConfiguration添加资源映射
@Autowired
private LocalProperties localProperties;


registry.addResourceHandler(localProperties.getProfile()+"/**")
			  .addResourceLocations("file:"+localProperties.getLocation()+"/");

2.2.2.5. 测试查询列表

021-管理后台附件功能开发_附件上传_03

2.3. 上传附件

2.3.1. 静态页面

2.3.1.1. 资源引入

1.引入文件上传插件fileinput的 css和 js文件

2.引入zhfileupload.js (针对fileinput相关方法的封装类似zhuhuo.js,具体封装内容可参考文件上传系列)

2.3.1.2. 修改common.html

<!-- fileinput css-->
<div th:fragment="lib-fileinput-css">
  <link rel="stylesheet"  href="../../../static/lib/fileinput/css/fileinput.min.css" 
        th:href="@{/lib/fileinput/css/fileinput.min.css}">
</div>

<!-- fileinput js-->
<div th:fragment="lib-fileinput-js">
  <!-- 
       piexif.min.js文件是hMatoba的Piexiffjs插件的来源。
       如果使用bootstrap-fileinput插件的图像调整大小功能,则需要在fileinput.min.js之前加载
  -->
  <script src="../../../static/lib/fileinput/js/plugins/piexif.min.js" 
          th:src="@{/lib/fileinput/js/plugins/piexif.min.js}"></script>

  <!-- 
			 sortable.min.js文件是ruvaxa的Sortable插件的来源。
       如果希望在初始预览中对缩略图进行排序,则需要在fileinput.min.js之前加载 
  -->
  <script src="../../../static/lib/fileinput/js/plugins/sortable.min.js" 
          th:src="@{/lib/fileinput/js/plugins/sortable.min.js}"></script>

  <!--
       purify.min.js文件是curre53的DomPurify插件的来源。
       如果您想为HTML内容预览净化HTML,则需要在fileinput.min.js之前加载 
   -->
  <script src="../../../static/lib/fileinput/js/plugins/purify.min.js" 
          th:src="@{/lib/fileinput/js/plugins/purify.min.js}"></script>
	<!-- fileinput js实现 -->
  <script src="../../../static/lib/fileinput/js/fileinput.min.js" 
          th:src="@{/lib/fileinput/js/fileinput.min.js}"></script>
  <!-- 主题文件themes/fa/theme.js,用于字体很棒的图标样式 -->
  <script src="../../../static/lib/fileinput/themes/fa/theme.min.js" 
          th:src="@{/lib/fileinput/themes/fa/theme.min.js}"></script>
  <!-- 包含区域设置文件<xx>.js,用于翻译展示的语言 -->
  <script src="../../../static/lib/fileinput/js/locales/zh.js" th:src="@{/lib/fileinput/js/locales/zh.js}"></script>
</div>

2.3.1.3. 页面布局

<!DOCTYPE html>
<html lang="en">
<head>
    <div th:replace="/manager/common/common :: core-head('新增','','')"></div>
    <div th:replace="/manager/common/common :: core-css"></div>
    <div th:replace="/manager/common/common :: lib-bootstrap-table-css"></div>
    <div th:replace="/manager/common/common :: lib-fileinput-css"></div>
</head>
<body class="gray-bg">
<div class="wrapper wrapper-content">
    <div class="panel">
        <div class="panel-body">

            <form  class="form-horizontal m" id="add-form" enctype="multipart/form-data" 
                   style="padding-left: 20px;padding-right: 20px">

                <!-- 导航名称 -->
                <div class="form-group">
                    <div class="col-md-12">
                        <div class="input-group m-b">
                            <span class="input-group-addon">存储位置</span>
                            <select class="form-control m-b" name="attachmentPost" id="attachmentPost">
                                <option value="local">本地</option>
                                <option value="minio">minio</option>
                                <option value="qiniu">七牛云</option>
                                <option value="cos">腾讯云</option>
                                <option value="oss">阿里云</option>
                            </select>
                        </div>
                    </div>
                </div>

                <div class="form-group">
                    <div class="col-md-12">
                        <input id="bootstrap-file-upload" type="file" multiple>
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>
</div>
<div th:replace="/manager/common/common :: core-js"></div>
<div th:replace="/manager/common/common :: lib-bootstrap-table-js"></div>
<div th:replace="/manager/common/common :: lib-jquery-validate-js"></div>
<div th:replace="/manager/common/common :: lib-fileinput-js"></div>
<script th:src="@{/local/js/zhfileupload.js}"></script>
<script th:src="@{/local/js/zhuhuo.js}"></script>
</body>
</html>

2.3.1.4. 初始化文件上传js

let options = {
    uploadUrl:'/m/attachmentInfo/addAttachmentInfo',
    allowedFileExtensions : ['jpg', 'png','gif'],//接收的文件后缀,
    maxFileCount: 100,
    enctype: 'multipart/form-data',
    showUpload: false, //是否显示上传按钮 上传操作通过layer的确认按钮进行操作
    showCaption: false,//是否显示标题
    showCancel: false, //是否显示文件上传取消按钮 只有在AJAX上传过程中,才会启用和显示
    browseClass: "btn btn-primary", //按钮样式
    previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",
    fileActionSettings:{
        showUpload:false,//是否在缩略图中显示上传按钮
        showRemove:true,//是否在缩略图中显示删除按钮
    }
}
$.fileuploads.init(options)

2.3.1.5. 表单提交js

function submitHandler(index){
    if($("#add-form").validate().form()) {
        var files = $("#bootstrap-file-upload").prop("files")
        var attachmentPost = $("#attachmentPost").val();
        var formData = new FormData();
        formData.append('attachmentPost',attachmentPost)
        for(var i = 0 ; i< files.length;i++){
            formData.append('files',files[i])
        }
        let url = '/m/attachmentInfo/addAttachmentInfo';
        $.action.postFile(url,formData)
    }
}

2.3.2. 文件上传功能

2.3.2.1. 创建上传请求对象UploadFileRequest

@Data
public class UploadFileRequest {

    /**
     * 上传文件参数 不同的云存储上传方式不同,有byte[],有inputStream的因此在上传文件的时候直接传递原始文件
     * 在不同的上传提供方处进行转换上传
     */
    private MultipartFile uploadFile;

    /**
     * 上传云存储空间类型
     */
    private String uploadType;

    /**
     * 允许上传的文件类型 如果客户端未传递则默认使用系统自带的范围
     */
    private List<String> allowUploadExtension;
}

2.3.2.2. 创建上传响应对象UploadFileResponse

@Data
public class UploadFileResponse {

    /**
     * 上传结果 true 成功 false失败
     */
    private Boolean uploadResult;

    /**
     * 上传失败原因 只有当uploadResult为失败的时候必填
     */
    private String errorMessage;


    /**
     * 文件名称 全称+后缀
     */
    private String fileName;

    /**
     * 文件后缀
     */
    private String fileSuffix;

    /**
     * 文件存储路径
     */
    private String fileStorgePath;

    /**
     * 文件类型
     */
    private String fileType;

    /**
     * 文件大小
     */
    private String fileSize;


    /**
     * 文件缩略图地址
     */
    private String thumbnailUrl;

}

2.3.2.3. 创建上传规则类型ObjectStorageRules

@Getter
@AllArgsConstructor
public enum ObjectStorageRules {

    /**
     * 本地存储
     */
    STORAGE_LOCAL("local","本地"),
    ;

    /**
     * 对象存储标识
     */
    private String code;

    /**
     * 对象存储描述
     */
    private String desc;


    public static ObjectStorageRules of(String code){
        Objects.requireNonNull(code);
        return Stream.of(values())
                .filter(bean -> bean.code.equals(code))
                .findAny()
                .orElseThrow(() -> new IllegalArgumentException(code +"not exists"));
    }

}

2.3.2.4. 创建上传执行接口ObjectStorageRulesExecutor

public interface ObjectStorageRulesExecutor {

    /**
     * 规则类型标记
     * @return {@link ObjectStorageRules}
     */
    ObjectStorageRules ruleConfig();

    /**
     * 上传文件
     * @return
     */
    UploadFileResponse upload(UploadFileRequest uploadFile) throws IOException;

}

2.3.2.5. 创建上传抽象类AbstractObjectStorageExecutor

public abstract class AbstractObjectStorageExecutor {

  public final String[] video = {".mp4",".avi",".wmv",".mpg",".mpeg",".mov",".rm",".ram",".swf",".flv"};

	public final String[] images = {".png",".jpg",".jpeg",".bmp",".gif"};

	public final String[] documents ={".doc",".docx",".ppt",".pptx",".xls",".txt",".vsd",".pdf",
     ".rtf",".wps",".wpt",".xml",".json",".html"};


  private String converFileType(String suffix){

      //视频格式
      if(Arrays.asList(video).contains(suffix)){
          return "video";
      }

      //图片格式
      if(Arrays.asList(images).contains(suffix)){
          return "images";
      }

      //文本格式
      if(Arrays.asList(documents).contains(suffix)){
          return "documents";
      }

      return "undefined";
  }
  
  
    /**
     * 根据文件后缀名 获取文件类型
     * @param suffix
     * @return
     */
    public String converContentType(String suffix){
        if(".bmp".equalsIgnoreCase(suffix)) {
            return "image/bmp";
        }
        if(".gif".equalsIgnoreCase(suffix)) {
            return "image/gif";
        }
        if(".jpeg".equalsIgnoreCase(suffix) || ".jpg".equalsIgnoreCase(suffix) 
           || ".png".equalsIgnoreCase(suffix) ) {
            return "image/jpeg";
        }
        if(".html".equalsIgnoreCase(suffix)) {
            return "text/html";
        }
        if(".txt".equalsIgnoreCase(suffix)) {
            return "text/plain";
        }
        if(".vsd".equalsIgnoreCase(suffix)) {
            return "application/vnd.visio";
        }
        if(".ppt".equalsIgnoreCase(suffix) || "pptx".equalsIgnoreCase(suffix)) {
            return "application/vnd.ms-powerpoint";
        }
        if(".doc".equalsIgnoreCase(suffix) || "docx".equalsIgnoreCase(suffix)) {
            return "application/msword";
        }
        if(".xml".equalsIgnoreCase(suffix)) {
            return "text/xml";
        }
        //如果为空 依旧想展示对应的则可以在获取返回结果后自行拓展
        return null;
    }


    /**
     * 转换文件大小
     * @param size
     * @return
     */
    public String converFileSize(long size){
        String[] units = new String[]{"B","KB","MB","GB","TB","PB","EB","ZB","YB"};
        int unit = 1024;
        int exp = (int)(Math.log(size)/Math.log(unit));
        double pre = 0 ;
        if(size > 1024){
            pre = size / Math.pow(unit,exp);
        }else {
            pre = (double)size / (double)unit;
        }
        return String.format(Locale.ENGLISH,"%.1f%s",pre,units[(int)exp]);
    }

}

2.3.2.6. 创建上传执行管理器ObjectStorageExecuteManager

@Slf4j
@Component("objectStorageExecuteManager")
public class ObjectStorageExecuteManager implements BeanPostProcessor {

    /**
     * 定义规则执行器映射
     */
    private Map<ObjectStorageRules, ObjectStorageRulesExecutor> executorIndex = new HashMap<>(ObjectStorageRules.values().length);


    /**
     * 文件上传策略
     * @param uploadFileRequest               要上传的文件信息
     * @return
     */
    public UploadFileResponse uploadStrategy(UploadFileRequest uploadFileRequest) throws IOException {
        UploadFileResponse uploadFileResponse;
        ObjectStorageRules ossRuleFlag = ObjectStorageRules.of(uploadFileRequest.getUploadType());
        switch (ossRuleFlag){
            case STORAGE_LOCAL:
                uploadFileResponse = 
                  executorIndex.get(ObjectStorageRules.STORAGE_LOCAL).upload(uploadFileRequest);
                break;
            default:
                uploadFileResponse =
                  executorIndex.get(ObjectStorageRules.STORAGE_LOCAL).upload(uploadFileRequest);
                break;
        }
        return uploadFileResponse;
    }

    /**
     * 在bean初始化之前进行执行(before)
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Nullable
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //如果当前bean不是ObjectStorageRulesExecutor的实现则直接返回bean
        if(!(bean instanceof ObjectStorageRulesExecutor)){
            return bean;
        }
        //把bean强转为RuleExecutor
        ObjectStorageRulesExecutor objectStorageRulesExecutor = (ObjectStorageRulesExecutor) bean;
        ObjectStorageRules objectStorageRules = objectStorageRulesExecutor.ruleConfig();
        //如果ruleFlag已经注册了则抛出异常
        if(executorIndex.containsKey(objectStorageRules)){
            throw new IllegalStateException("There is already an executor fro rule flag" + objectStorageRules);
        }
        log.info("Load executor {} for rule flag {}",objectStorageRulesExecutor.getClass(),objectStorageRules);
        executorIndex.put(objectStorageRules,objectStorageRulesExecutor);
        return null;
    }

    /**
     * 在bean初始化之后进行执行(after)
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Nullable
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

}

2.3.2.7. 创建本地上传配置LocalProperties

@Data
@AllArgsConstructor
@NoArgsConstructor
public class LocalProperties {

    /**
     * 前缀  cy.storage 是 文件存储通用前缀
     */
    public static final String PREFIX = "cy.storage.local";

    /**
     * 本地存储是否启用 true 为启用 false 为禁用
     */
    private Boolean enabled;

    /**
     * 存储类别 本地为 local
     */
    private String storageType;

    /**
     * 域名信息 本地一般为 http://localhost:8080 如果放到生产可配置生产域名
     */
    private String domain;

    /**
     * 文件存放地址
     */
    private String location;

    /**
     * 资源映射路径 前缀 用于项目中使用
     */
    private String profile;

}

2.3.2.8. 创建本地上传实现LocalStorage

public class LocalStorage extends AbstractObjectStorageExecutor implements ObjectStorageRulesExecutor {

    private final LocalProperties localProperties;

    public LocalStorage(LocalProperties localProperties) {
        this.localProperties = localProperties;
    }

    /**
     * 规则类型标记
     * @return {@link ObjectStorageRules}
     */
    @Override
    public ObjectStorageRules ruleConfig() {
        return ObjectStorageRules.STORAGE_LOCAL;
    }

    /**
     * 文件上传操作
     * @param uploadFile 要上传的文件
     * @return
     */
    @Override
    public UploadFileResponse upload(UploadFileRequest uploadFile) throws IOException {
        //获取文件后缀名
        String suffix = uploadFile.getUploadFile().getOriginalFilename()
          .substring(uploadFile.getUploadFile().getOriginalFilename().lastIndexOf("."));
        //获取文件原始名称
        String name = uploadFile.getUploadFile().getOriginalFilename()
          .substring(0,uploadFile.getUploadFile().getOriginalFilename().lastIndexOf("."));
        //组装文件名称
        String fileName = name  +suffix;
        String absPath = getAbsoluteFile(fileName).getAbsolutePath();
        uploadFile.getUploadFile().transferTo(Paths.get(absPath));
        int dirLastIndex = localProperties.getLocation().length() + 1;
        String currenDir = StringUtil.substring(absPath,dirLastIndex);
        String pathFileName = localProperties.getProfile()+"/"+currenDir;
        String resultUrl = localProperties.getDomain() + pathFileName;

        UploadFileResponse uploadFileResponse = new UploadFileResponse();
        uploadFileResponse.setFileName(fileName);
        uploadFileResponse.setFileSuffix(suffix);
        uploadFileResponse.setFileStorgePath(currenDir);
        uploadFileResponse.setFileSize(converFileSize(uploadFile.getUploadFile().getSize()));
        uploadFileResponse.setFileType(converFileType(suffix));
        uploadFileResponse.setThumbnailUrl(resultUrl);
        uploadFileResponse.setUploadResult(true);
        return uploadFileResponse;
    }

    private  File getAbsoluteFile(String fileName) {

        String basiDir = localProperties.getLocation()+File.separator+ 
          DateUtil.BasicDateData.stringDateRule(DateUtil.Format.YEAR_MONTH_DAY_UN);

        File directory=new File(basiDir+File.separator+fileName);

        if (!directory.exists()){
            if(!directory.getParentFile().exists()){
                directory.getParentFile().mkdirs();
            }
        }
        return directory;
    }
}

2.3.3. 新增功能

2.3.3.1. 创建上传页面方法

2.3.3.1.1. controller
@ActionLog(modual = "附件管理" ,methodDesc = "上传附件页面",source = LogSource.MANAGER,logtype = LogType.INSERT)
@GetMapping(value = "/addAttachmentInfoPage")
public String addAttachmentInfoPage(){
    return "/manager/attachmentInfo/add";
}

@ActionLog(modual = "附件管理" ,methodDesc = "上传附件方法",source = LogSource.MANAGER,logtype = LogType.INSERT)
@ResponseBody
@PostMapping(value = "/addAttachmentInfo")
public RespJsonData<String> addAttachmentInfo(MultipartFile[] files,String attachmentPost) throws IOException {
    return attachmentInfoService.addAttachmentInfo(files,attachmentPost);
}
2.3.3.1.2. service,serviceImpl
RespJsonData<String> addAttachmentInfo(MultipartFile[] files, String attachmentPost) throws IOException;
@Override
public RespJsonData<String> addAttachmentInfo(MultipartFile[] files, String attachmentPost) throws IOException {
    //返回给客户端的
    List<String> filePath = new ArrayList<String>();
    for(MultipartFile file:files){
        //组装要上传的文件信息
        UploadFileRequest uploadFileRequest = new UploadFileRequest();
        uploadFileRequest.setUploadFile(file);
        uploadFileRequest.setUploadType(attachmentPost);
        //获取上传文件响应结果
        UploadFileResponse uploadFileResponse = objectStorageExecuteManager.uploadStrategy(uploadFileRequest);
        if(uploadFileResponse.getUploadResult()){
            //上传成功后保存文件信息
            AttachmentInfo attachmentInfo = new AttachmentInfo();
            attachmentInfo.setAttachmentPost(attachmentPost);
            attachmentInfo.setAttachmentUrl(uploadFileResponse.getFileStorgePath());
            attachmentInfo.setAttachmentName(uploadFileResponse.getFileName());
            attachmentInfo.setAttachmentSize(uploadFileResponse.getFileSize());
            attachmentInfo.setAttachmentType(uploadFileResponse.getFileType());
            attachmentInfo.setContentType(uploadFileResponse.getFileType());
            attachmentInfo.setThumbnailUrl(uploadFileResponse.getThumbnailUrl());
            attachmentInfoMapper.insertSelective(attachmentInfo);
            //上传成功后拼装显示路径信息
            filePath.add(uploadFileResponse.getThumbnailUrl());
        }else {
            return RespJsonData.fail(uploadFileResponse.getErrorMessage(),
                              BaseResponseCode.FAIL.getResponseCode(),uploadFileResponse.getErrorMessage());
        }
    }
    String resultFilePathList = String.join(",",filePath);
    return RespJsonData.success(resultFilePathList);
}

2.3.3. 添加配置文件

cy:
  storage:
    local:
      # 是否启用本地上传
      enabled: true
      # 本地上传存储标识
      storageType: local
      # 本地上传域名 如果有则填写映射 如果没有 默认获取当前服务的ip+port
      domain: http://localhost:8080
      # 本地上传存储位置 文件实际存储位置
      location: /Users/jiuling/Documents/postmanfile/upload
      #资源映射路径 前缀 用于项目中使用
      profile: /profile

2.3.4. postmant测试上传

021-管理后台附件功能开发_附件上传_04


2.4. 删除文件

2.4.1. 文件删除功能

2.4.1.1. 创建删除请求对象RemoveFileRequest

@Data
public class RemoveFileRequest {

    /**
     * 存储类别
     */
    private String storageType;

}

2.4.1.2. 创建删除响应对象RemoveFileResponse

@Data
public class RemoveFileResponse {

    /**
     * 移除结果
     */
    private Boolean removeResult;
}

2.4.1.3. 创建删除执行接口remove

RemoveFileResponse remove(RemoveFileRequest removeFileRequest);

2.4.1.4. 在ObjectStorageExecuteManager中添加移除策略

public RemoveFileResponse removeStrategy(RemoveFileRequest removeFileRequest) throws IOException {
    RemoveFileResponse removeFileResponse;
    ObjectStorageRules objectStorageRules = ObjectStorageRules.of(removeFileRequest.getStorageType());
    switch (objectStorageRules){
        case STORAGE_LOCAL:
            removeFileResponse = executorIndex.get(ObjectStorageRules.STORAGE_LOCAL).remove(removeFileRequest);
            break;
        default:
            removeFileResponse = executorIndex.get(ObjectStorageRules.STORAGE_LOCAL).remove(removeFileRequest);
            break;
    }
    return removeFileResponse;
}

2.4.1.5. 在LocalStorage中添加移除方法

@Override
public RemoveFileResponse remove(RemoveFileRequest removeFileRequest) {
    String deleteFile = localProperties.getLocation()+File.separator+removeFileRequest.getFileUrl();
    File file = new File(deleteFile);
    RemoveFileResponse removeFileResponse = new RemoveFileResponse();
    if(file.exists()){
        if(file.delete()){
            removeFileResponse.setRemoveResult(true);
        }else {
            removeFileResponse.setRemoveResult(false);
            removeFileResponse.setErrorMessage("文件删除失败");
        }
    }else {
        removeFileResponse.setRemoveResult(false);
        removeFileResponse.setErrorMessage("文件不存在");
    }
    return removeFileResponse;
}

2.4.2. 删除功能

2.4.2.1. 创建删除方法

2.4.2.1.1. controller
@ActionLog(modual = "附件管理" ,methodDesc = "删除附件",source = LogSource.MANAGER,logtype = LogType.DELETE)
@ResponseBody
@PostMapping(value = "/deleteAttachmentInfo")
public RespJson deleteAttachmentInfo(@RequestBody AttachmentInfoBO attachmentInfoBO) throws IOException {
    return attachmentInfoService.deleteAttachmentInfo(attachmentInfoBO);
}
2.4.2.1.2. service,serviceImpl
RespJson deleteAttachmentInfo(AttachmentInfoBO attachmentInfoBO) throws IOException;
@Override
public RespJson deleteAttachmentInfo(AttachmentInfoBO attachmentInfoBO) throws IOException {
    if (ObjectUtil.isEmpty(attachmentInfoBO.getId())) {
        return RespJson.fail(BizResponseCode.ATTACHMENT_ID_NOT_EXIST.getResponseCode(),
                             BizResponseCode.ATTACHMENT_ID_NOT_EXIST.getResponseMessage());
    }
    //获取附件基础信息
    AttachmentInfo attachmentInfo = attachmentInfoMapper.selectByPrimaryKey(attachmentInfoBO.getId());
    RemoveFileRequest removeFileRequest = new RemoveFileRequest();
    removeFileRequest.setStorageType(attachmentInfo.getAttachmentPost());
    removeFileRequest.setFileUrl(attachmentInfo.getAttachmentUrl());
    removeFileRequest.setFileName(attachmentInfo.getAttachmentName());
    RemoveFileResponse removeFileResponse = objectStorageExecuteManager.removeStrategy(removeFileRequest);
    if(removeFileResponse.getRemoveResult()){
        attachmentInfoMapper.delete(attachmentInfo);
        //返回结果
        return RespJson.success();
    }else {
        return RespJson.fail(BaseResponseCode.FAIL.getResponseCode(),removeFileResponse.getErrorMessage());
    }
}
2.4.2.1.3. BizResponseCode
ATTACHMENT_ID_NOT_EXIST("102006","附件id不存在,请检查"),

2.4.2.2. postman删除测试

021-管理后台附件功能开发_fileinput_05


标签:return,String,private,后台,021,附件,上传,public
From: https://blog.51cto.com/cykj20210317/7419442

相关文章

  • 20211325 2023-2024-1 《信息安全系统设计与实现(上)》第一周学习笔记
    202113252023-2024-1《信息安全系统设计与实现(上)》第一周学习笔记一、任务要求任务详情自学教材第1,2章,提交学习笔记(10分),评分标准如下1.知识点归纳以及自己最有收获的内容,选择至少2个知识点利用chatgpt等工具进行苏格拉底挑战,并提交过程截图,提示过程参考下面内容(4分)......
  • openwrt修改后台访问端口及开启https
    修改后台访问端口:需要修改openwrt的配置文件,文件路径/etc/config/uhttpduhttpd文件内容如下configuhttpd'main'listlisten_http'0.0.0.0:80'listlisten_http'[::]:80'listlisten_https'0.0.0.0:443'listlis......
  • java 支持 超大上G,多附件上传技术
    ​ 之前仿造uploadify写了一个HTML5版的文件上传插件,没看过的朋友可以点此先看一下~得到了不少朋友的好评,我自己也用在了项目中,不论是用户头像上传,还是各种媒体文件的上传,以及各种个性的业务需求,都能得到满足。小小开心了一把。  但无论插件再怎么灵活,也难以应付所有的需求,比......
  • java 支持 超大上G,多附件上传示例解析
    ​ 在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现。先说下要求:PC端全平台支持,要求支持Windows,Mac,Linux支持所有浏览器。支持文件批量上传支持文件夹上传,且要求在服务端保留层级结构。文件夹数量要求支持到10W......
  • 骑手端后台管理系统app源码
      骑手端app管理软件是基于外卖平台的其中一个端的软件,骑手端的功能从从订单接收、派送分配、路线规划、到订单完成的整个过程。本文主要解析该App源码的关键技术和实现方式。  骑手端的APP软件端,是接当地所有的外卖订单的系统,用户下单后的订单编号,所有的骑手都可以抢单子......
  • java 支持 超大上G,多附件上传实例
    ​ 这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数下面直接贴代码吧,一些难懂的我大部分都加上注释了:上传文件实体类:看得出来,实体类中已经有很多我们需要的功能了,还有实用的属性。如MD5秒传的信息。pub......
  • NAS 后台安装 Docker 后配置 PostgreSQL
    群晖(Synology)NAS的后台在新版本对Docker不再称为Docker,现在改称为ContainerManager了。  单击进入后运行ContainerManager。PostgreSQL容器针对PostgreSQL的容器,我们选择容器后,如果你已经安装了PostgreSQL的话,应该就能看到运行的容器了。  然后选择设置。在Post......
  • 群晖(Synology)NAS 后台安装 Docker 后配置 PostgreSQL
    群晖(Synology)NAS的后台在新版本对Docker不再称为Docker,现在改称为ContainerManager了。  单击进入后运行ContainerManager。PostgreSQL容器针对PostgreSQL的容器,我们选择容器后,如果你已经安装了PostgreSQL的话,应该就能看到运行的容器了。  然后选择设......
  • java 支持 超大上G,多附件上传源代码
    ​ javaweb上传文件上传文件的jsp中的部分上传文件同样可以使用form表单向后端发请求,也可以使用ajax向后端发请求    1.通过form表单向后端发送请求         <formid="postForm"action="${pageContext.request.contextPath}/UploadServlet"method="post"e......
  • 题解 P8165 [eJOI2021] AddK
    不知道为什么这道题还没有题解。Solution对于操作\(1\),由于\(K\le10\),直接暴力单点修改即可。而操作\(2\)的询问,不难发现,最后结果的呈现形式是\[1\timesA_l+2\timesA_{l+1}+3\timesA_{l+2}+...+3\timesA_{r-2}+2\timesA_{r-1}+1\timesA_r\]其中中间可能有一段系数......