forked from gzzfw/backEnd/gz-dyh

liyj
2024-08-31 67bc268ffdc203fd0f3081261c8778bd61a23541
1、新增附件管理模块
9 files added
9 files modified
1501 ■■■■■ changed files
dyh-service/dyh-base/src/main/java/cn/huge/module/sys/constant/FileBaseConsts.java 44 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-base/src/main/java/cn/huge/module/sys/constant/FileOwnerTypeBaseEnum.java 24 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-base/src/main/java/cn/huge/module/sys/dto/FileInfoBaseDTO.java 33 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/pom.xml 10 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/client/api/CustClient.java 74 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/client/api/impl/CustClientImpl.java 188 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/config/FtpFileConfig.java 108 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/controller/web/FileInfoWebController.java 140 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/controller/wechat/FileInfoWechatController.java 173 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/domain/dto/UploaderDTO.java 37 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/domain/po/FileInfo.java 49 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/domain/po/FileRelate.java 2 ●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/service/FileInfoService.java 86 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/service/FileRelateService.java 42 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/utils/FileUtils.java 40 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/utils/FtpMultipartFileWrapper.java 184 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/utils/FtpUtils.java 256 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-sys/src/main/resources/config/application.yml 11 ●●●●● patch | view | raw | blame | history
dyh-service/dyh-base/src/main/java/cn/huge/module/sys/constant/FileBaseConsts.java
New file
@@ -0,0 +1,44 @@
package cn.huge.module.sys.constant;
/**
 * @title: 附件相关常量类
 * @description: 附件相关常量类
 * @company: hugeinfo
 * @author: liyj
 * @time: 2021-11-05 16:51:48
 * @version: 1.0.0
 */
public class FileBaseConsts {
    /**
     * 上传人类型,1:工作人员,2:申请方当事人,3:申请方代理人,4:被申请方当事人,5:被申请方代理人
     */
    public static final int UPLOADER_TYPE_1 = 1;
    public static final int UPLOADER_TYPE_2 = 2;
    public static final int UPLOADER_TYPE_3 = 3;
    public static final int UPLOADER_TYPE_4 = 4;
    public static final int UPLOADER_TYPE_5 = 5;
}
/**
 * -------------------_ooOoo_-------------------
 * ------------------o8888888o------------------
 * ------------------88" . "88------------------
 * ------------------(| -_- |)------------------
 * ------------------O\  =  /O------------------
 * ---------------____/`---'\____---------------
 * -------------.'  \\|     |//  `.-------------
 * ------------/  \\|||  :  |||//  \------------
 * -----------/  _||||| -:- |||||-  \-----------
 * -----------|   | \\\  -  /// |   |-----------
 * -----------| \_|  ''\---/''  |   |-----------
 * -----------\  .-\__  `-`  ___/-. /-----------
 * ---------___`. .'  /--.--\  `. . __----------
 * ------."" '<  `.___\_<|>_/___.'  >'"".-------
 * -----| | :  `- \`.;`\ _ /`;.`/ - ` : | |-----
 * -----\  \ `-.   \_ __\ /__ _/   .-` /  /-----
 * ======`-.____`-.___\_____/___.-`____.-'======
 * -------------------`=---='
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * ---------佛祖保佑---hugeinfo---永无BUG----------
 */
dyh-service/dyh-base/src/main/java/cn/huge/module/sys/constant/FileOwnerTypeBaseEnum.java
@@ -228,6 +228,10 @@
            case "22_00018-501":
                return OWNER_CAT_7.getIndex();
            case "22_00018-506":
                return OWNER_CAT_7.getIndex();
            case "22_00018-507":
                return OWNER_CAT_7.getIndex();
            case "22_00018-502":
                return OWNER_CAT_9.getIndex();
@@ -247,7 +251,7 @@
            case "22_00018-604":
                return OWNER_CAT_8.getIndex();
            case "22_00018-605":
                return OWNER_CAT_9.getIndex();
                return OWNER_CAT_8.getIndex();
            default:
                return OWNER_CAT_4.getIndex();
@@ -273,6 +277,13 @@
                return OWNER_CAT_5;
            case "22_00014-6":
                return OWNER_CAT_6;
            case "22_00014-7":
                return OWNER_CAT_7;
            case "22_00014-8":
                return OWNER_CAT_8;
            case "22_00014-9":
                return OWNER_CAT_9;
            case "22_00018-101":
                return OWNER_TYPE_101;
            case "22_00018-102":
@@ -327,6 +338,8 @@
                return OWNER_TYPE_305;
            case "22_00018-306":
                return OWNER_TYPE_306;
            case "22_00018-307":
                return OWNER_TYPE_307;
            case "22_00018-401":
                return OWNER_TYPE_401;
@@ -334,6 +347,8 @@
                return OWNER_TYPE_402;
            case "22_00018-403":
                return OWNER_TYPE_403;
            case "22_00018-405":
                return OWNER_TYPE_405;
            case "22_00018-406":
                return OWNER_TYPE_406;
            case "22_00018-407":
@@ -345,12 +360,19 @@
            case "22_00018-501":
                return OWNER_TYPE_501;
            case "22_00018-506":
                return OWNER_TYPE_506;
            case "22_00018-507":
                return OWNER_TYPE_507;
            case "22_00018-502":
                return OWNER_TYPE_502;
            case "22_00018-503":
                return OWNER_TYPE_503;
            case "22_00018-504":
                return OWNER_TYPE_504;
            case "22_00018-505":
                return OWNER_TYPE_505;
            case "22_00018-601":
                return OWNER_TYPE_601;
dyh-service/dyh-base/src/main/java/cn/huge/module/sys/dto/FileInfoBaseDTO.java
@@ -1,5 +1,6 @@
package cn.huge.module.sys.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.util.Date;
@@ -41,18 +42,18 @@
    private String suffix;
    /**
    * 附件分类,音频|视频|图片等
    */
     * 附件分类,音频|视频|图片等
     */
    private String cat;
    /**
    * 附件大小
    */
     * 附件大小
     */
    private Double size;
    /**
    * 单位
    */
     * 单位
     */
    private String unit;
    /**
@@ -91,9 +92,14 @@
    private String zipUrl;
    /**
     * 文件上传时间
     * 删除状态,0:已删除,1:未删除
     */
    private Date createTime;
    private Integer deleteStatus;
    /**
     * 顾客编号
     */
    private String custId;
    /**
     * 状态时间
@@ -101,9 +107,9 @@
    private Date updateTime;
    /**
    * 顾客编号
    */
    private String custId;
     * 创建时间
     */
    private Date createTime;
    /**
     * 所属业务编号
@@ -141,6 +147,11 @@
    private String uploaderName;
    /**
     * 上传人类型,1:工作人员,2:申请方当事人,3:申请方代理人,4:被申请方当事人,5:被申请方代理人
     */
    private Integer uploaderType;
    /**
     * 前端固定参数,值为:done
     */
    private String status;
dyh-service/dyh-sys/pom.xml
@@ -18,7 +18,7 @@
    </parent>
    <properties>
        <commons-net.version>3.1</commons-net.version>
    </properties>
    <dependencies>
@@ -59,6 +59,14 @@
            <scope>test</scope>
        </dependency>
        <!-- junit end -->
        <!-- net -->
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>${commons-net.version}</version>
        </dependency>
        <!-- net end -->
    </dependencies>
    <build>
dyh-service/dyh-sys/src/main/java/cn/huge/module/client/api/CustClient.java
New file
@@ -0,0 +1,74 @@
package cn.huge.module.client.api;
import cn.huge.base.common.bo.ReturnBO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
 * @title: 客户用户中心微服务调用接口
 * @description: 客户用户中心微服务调用接口
 * @company: hugeinfo
 * @author: liyj
 * @time: 2021-11-05 16:51:48
 * @version: 1.0.0
 */
@FeignClient(name = "dyh-cust")
public interface CustClient {
    /**
     * 内部用户-获取登录用户
     * @url {ctx}/api/v1/ctUser/clientGetUser?userId=
     * @param userId 登录用户编号
     * @return ReturnBO
     */
    @GetMapping("/api/v1/ctUser/clientGetUser")
    ReturnBO clientGetUser(@RequestParam("userId") String userId);
    /**
     * 内部用户-获取登录用户
     * @url {ctx}/api/v1/ctUser/clientGetUserAll?userId=
     * @param userId 登录用户编号
     * @return
     */
    @GetMapping("/api/v1/ctUser/clientGetUserAll")
    ReturnBO clientGetUserAll(@RequestParam("userId") String userId);
    /**
     * 当事人-获取登录用户
     * @url {ctx}/api/v1/paUser/clientGetUserAll?userId=
     * @param userId 登录用户编号
     * @return ReturnBO
     */
    @GetMapping("/api/v1/paUser/clientGetUserAll")
    ReturnBO paclientGetUser(@RequestParam("userId") String userId);
    /**
     * 根据组织和角色查询
     * @url {ctx}/api/v1/ctUser/listUserByUnitRole
     * @return unitId 组织编号
     * @return roleCode 角色代码
     * @return ReturnBO
     */
    @GetMapping("/api/v1/ctUser/listUserByUnitRole")
    ReturnBO listUserByUnitRole(@RequestParam(value = "unitId") String unitId, @RequestParam(value = "roleCode") String roleCode);
    /**
     * 根据部门和角色查询
     * @url {ctx}/api/v1/ctUser/listUserByDeptRole
     * @return deptId 部门编号
     * @return roleCode 角色代码
     * @return ReturnBO
     */
    @GetMapping("/api/v1/ctUser/listUserByDeptRole")
    ReturnBO listUserByDeptRole(@RequestParam(value = "deptId") String deptId, @RequestParam(value = "roleCode") String roleCode);
    /**
     * 查询客户下的法院
     * @url {ctx}/api/v1/ctUnit/listCourt1
     * @param userId 用户编号
     * @return ReturnBO
     */
    @GetMapping("/api/v1/ctUnit/listCourt1")
    ReturnBO listCourt1(@RequestParam(value = "userId") String userId);
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/client/api/impl/CustClientImpl.java
New file
@@ -0,0 +1,188 @@
package cn.huge.module.client.api.impl;
import cn.huge.base.common.bo.ReturnBO;
import cn.huge.base.common.constant.ReturnConsts;
import cn.huge.base.common.dto.SelectTermDTO;
import cn.huge.base.common.exception.ClientException;
import cn.huge.base.common.exception.ServiceException;
import cn.huge.module.client.api.CustClient;
import cn.huge.module.cust.dto.CtUserDTO;
import cn.huge.module.cust.dto.PaUserDTO;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
 * @title: 客户用户中心微服务调用接口实现
 * @description: 客户用户中心微服务调用接口实现
 * @company: hugeinfo
 * @author: liyj
 * @time: 2021-11-05 16:51:48
 * @version: 1.0.0
 */
@Slf4j
@Component
public class CustClientImpl {
    private CustClient custClient;
    @Autowired
    public CustClientImpl(CustClient custClient) {
        this.custClient = custClient;
    }
    /**
     * ObjectMapper工具类
     */
    private ObjectMapper objectMapper = new ObjectMapper();
    /**
     * 内部用户-获取登录用户
     * @param userId 用户编号
     * @return CtUserDTO
     */
    public CtUserDTO clientGetUser(String userId){
        try{
            ReturnBO returnBo = custClient.clientGetUser(userId);
            if (ReturnConsts.OK == returnBo.getCode()){
                CtUserDTO loginUser = objectMapper.convertValue(returnBo.getData(), CtUserDTO.class);
                return loginUser;
            }else{
                log.error("Client外服务接口[CustClientImpl.clientGetUser]请求异常:" + returnBo.getMsg(), returnBo.getMsg());
                throw new ClientException("CustClientImpl.clientGetUser", returnBo.getMsg());
            }
        }catch (Exception e){
            log.error("service方法[CustClientImpl.clientGetUser]调用异常:"+e, e);
            throw new ServiceException("CustClientImpl.clientGetUser", e);
        }
    }
    /**
     * 内部用户-获取登录用户
     * @param userId
     * @return
     */
    public CtUserDTO clientGetUserAll(String userId){
        try{
            ReturnBO returnBo = custClient.clientGetUserAll(userId);
            if (ReturnConsts.OK == returnBo.getCode()){
                CtUserDTO loginUser = objectMapper.convertValue(returnBo.getData(), CtUserDTO.class);
                return loginUser;
            }else{
                log.error("Client外服务接口[CustClientImpl.clientGetUserAll]请求异常:" + returnBo.getMsg(), returnBo.getMsg());
                throw new ClientException("CustClientImpl.clientGetUserAll", returnBo.getMsg());
            }
        }catch (Exception e){
            log.error("service方法[CustClientImpl.clientGetUserAll]调用异常:"+e, e);
            throw new ServiceException("CustClientImpl.clientGetUserAll", e);
        }
    }
    /**
     * 当事人-获取登录用户
     * @param userId 用户编号
     * @return
     */
    public PaUserDTO paclientGetUser(String userId){
        try{
            ReturnBO returnBo = custClient.paclientGetUser(userId);
            if (ReturnConsts.OK == returnBo.getCode()){
                PaUserDTO loginUser = objectMapper.convertValue(returnBo.getData(), PaUserDTO.class);
                return loginUser;
            }else{
                log.error("Client外服务接口[CustClientImpl.paclientGetUser]请求异常:" + returnBo.getMsg(), returnBo.getMsg());
                throw new ClientException("CustClientImpl.paclientGetUser", returnBo.getMsg());
            }
        }catch (Exception e){
            log.error("service方法[CustClientImpl.paclientGetUser]调用异常:"+e, e);
            throw new ServiceException("CustClientImpl.paclientGetUser", e);
        }
    }
    /**
     * 根据组织和角色查询
     * @return unitId 组织编号
     * @return roleCode 角色代码
     * @return Object
     */
    public List<CtUserDTO> listUserByUnitRole(@RequestParam(value = "unitId") String unitId, @RequestParam(value = "roleCode") String roleCode) {
        List<CtUserDTO> ctUserDTOList = new ArrayList<>();
        try{
            ReturnBO returnBo = custClient.listUserByUnitRole(unitId, roleCode);
            if (ReturnConsts.OK == returnBo.getCode()){
                List<LinkedHashMap> list = (List<LinkedHashMap>) returnBo.getData();
                for (LinkedHashMap map : list) {
                    CtUserDTO ctUserDTO = JSON.parseObject(JSON.toJSONString(map), CtUserDTO.class);
                    ctUserDTOList.add(ctUserDTO);
                }
                return ctUserDTOList;
            }else{
                log.error("Client外服务接口[CustClientImpl.listUserByUnitRole]请求异常:" + returnBo.getMsg(), returnBo.getMsg());
                throw new ClientException("CustClientImpl.listUserByUnitRole", returnBo.getMsg());
            }
        }catch (Exception e){
            log.error("service方法[CustClientImpl.listUserByUnitRole]调用异常:"+e, e);
            throw new ServiceException("CustClientImpl.listUserByUnitRole", e);
        }
    }
    /**
     * 根据部门和角色查询
     * @return deptId 部门编号
     * @return roleCode 角色代码
     * @return Object
     */
    public List<CtUserDTO> listUserByDeptRole(@RequestParam(value = "deptId") String deptId, @RequestParam(value = "roleCode") String roleCode) {
        List<CtUserDTO> ctUserDTOList = new ArrayList<>();
        try{
            ReturnBO returnBo = custClient.listUserByDeptRole(deptId, roleCode);
            if (ReturnConsts.OK == returnBo.getCode()){
                List<LinkedHashMap> list = (List<LinkedHashMap>) returnBo.getData();
                for (LinkedHashMap map : list) {
                    CtUserDTO ctUserDTO = JSON.parseObject(JSON.toJSONString(map), CtUserDTO.class);
                    ctUserDTOList.add(ctUserDTO);
                }
                return ctUserDTOList;
            }else{
                log.error("Client外服务接口[CustClientImpl.listUserByDeptRole]请求异常:" + returnBo.getMsg(), returnBo.getMsg());
                throw new ClientException("CustClientImpl.listUserByDeptRole", returnBo.getMsg());
            }
        }catch (Exception e){
            log.error("service方法[CustClientImpl.listUserByDeptRole]调用异常:"+e, e);
            throw new ServiceException("CustClientImpl.listUserByDeptRole", e);
        }
    }
    /**
     * 查询客户下的法院
     * @param userId
     * @return
     */
    public List<SelectTermDTO> listCourt1(String userId){
        List<SelectTermDTO> selectTermDTOList = new ArrayList<>();
        try{
            ReturnBO returnBo = custClient.listCourt1(userId);
            if (ReturnConsts.OK == returnBo.getCode()){
                List<LinkedHashMap> list = (List<LinkedHashMap>) returnBo.getData();
                for (LinkedHashMap map : list) {
                    SelectTermDTO selectTermDTO = JSON.parseObject(JSON.toJSONString(map), SelectTermDTO.class);
                    selectTermDTOList.add(selectTermDTO);
                }
                return selectTermDTOList;
            }else{
                log.error("Client外服务接口[CustClientImpl.listCourt1]请求异常:" + returnBo.getMsg(), returnBo.getMsg());
                throw new ClientException("CustClientImpl.listCourt1", returnBo.getMsg());
            }
        }catch (Exception e){
            log.error("service方法[CustClientImpl.listCourt1]调用异常:"+e, e);
            throw new ServiceException("CustClientImpl.listCourt1", e);
        }
    }
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/config/FtpFileConfig.java
New file
@@ -0,0 +1,108 @@
package cn.huge.module.file.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 * @title: JSON工具类
 * @description: JSON工具类
 * @company: hugeinfo
 * @author: liyj
 * @time: 2021-11-05 16:51:48
 * @version: 1.0.0
 */
@Component
public class FtpFileConfig {
    /**
     * 服务器ip地址
     */
    public static String hostname;
    /**
     * 端口
     */
    public static int port;
    /**
     * 用户名
     */
    public static String username;
    /**
     * 密码
     */
    public static String password;
    /**
     * 附件存储根目录
     */
    public static String rootdir;
    @Value("${ftp.hostname}")
    public void setHostname(String hostname) {
        this.hostname = hostname;
    }
    @Value("${ftp.port}")
    public void setPort(int port) {
        this.port = port;
    }
    @Value("${ftp.username}")
    public void setUsername(String username) {
        this.username = username;
    }
    @Value("${ftp.password}")
    public void setPassword(String password) {
        this.password = password;
    }
    @Value("${ftp.rootdir}")
    public void setRootdir(String rootdir) {
        this.rootdir = rootdir;
    }
    public static String getHostname() {
        return hostname;
    }
    public static int getPort() {
        return port;
    }
    public static String getUsername() {
        return username;
    }
    public static String getPassword() {
        return password;
    }
    public static String getRootdir() {
        return rootdir;
    }
}
/**
 * -------------------_ooOoo_-------------------
 * ------------------o8888888o------------------
 * ------------------88" . "88------------------
 * ------------------(| -_- |)------------------
 * ------------------O\  =  /O------------------
 * ---------------____/`---'\____---------------
 * -------------.'  \\|     |//  `.-------------
 * ------------/  \\|||  :  |||//  \------------
 * -----------/  _||||| -:- |||||-  \-----------
 * -----------|   | \\\  -  /// |   |-----------
 * -----------| \_|  ''\---/''  |   |-----------
 * -----------\  .-\__  `-`  ___/-. /-----------
 * ---------___`. .'  /--.--\  `. . __----------
 * ------."" '<  `.___\_<|>_/___.'  >'"".-------
 * -----| | :  `- \`.;`\ _ /`;.`/ - ` : | |-----
 * -----\  \ `-.   \_ __\ /__ _/   .-` /  /-----
 * ======`-.____`-.___\_____/___.-`____.-'======
 * -------------------`=---='
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * ---------佛祖保佑---hugeinfo---永无BUG----------
 */
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/controller/web/FileInfoWebController.java
@@ -1,19 +1,42 @@
package cn.huge.module.file.controller.web;
import cn.huge.base.common.exception.ClientException;
import cn.huge.base.common.utils.ContentTypeUtils;
import cn.huge.base.common.utils.ReturnFailUtils;
import cn.huge.base.common.utils.ReturnSucUtils;
import cn.huge.base.config.CurrentUser;
import cn.huge.module.client.api.impl.CustClientImpl;
import cn.huge.module.constant.BaseConsts;
import cn.huge.module.cust.dto.CtUserDTO;
import cn.huge.module.file.domain.dto.UploaderDTO;
import cn.huge.module.file.domain.po.FileInfo;
import cn.huge.module.file.service.FileInfoService;
import cn.huge.module.file.service.FileRelateService;
import cn.huge.module.file.utils.FileUtils;
import cn.huge.module.file.utils.FtpUtils;
import cn.huge.module.sys.constant.FileOwnerTypeBaseEnum;
import cn.huge.module.sys.dto.FileInfoBaseDTO;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -36,5 +59,122 @@
    @Autowired
    private FileInfoService service;
    @Autowired
    private FileRelateService fileRelateService;
    @Autowired
    private CustClientImpl custClient;
    /**
     * 页面附件上传-文件流方式
     * @url {ctx}/api/web/fileInfo/upload/{ownerId}/{ownerType}
     * @param ownerId 所属业务编号
     * @param ownerType 所属业务类型
     * @param request 请求头
     * @return Object
     */
    @PostMapping("/upload/{ownerId}/{ownerType}")
    public Object upload(@PathVariable(value = "ownerId") String ownerId, @PathVariable(value = "ownerType") String ownerType,
                         @CurrentUser String userId, MultipartHttpServletRequest request) {
        try{
            CtUserDTO loginUser = custClient.clientGetUser(userId);
            UploaderDTO uploaderDTO = new UploaderDTO();
            BeanUtils.copyProperties(loginUser, uploaderDTO);
            List<FileInfoBaseDTO> files = new ArrayList<>();
            Iterator<String> itr = request.getFileNames();
            int fileCount = fileRelateService.countByOwnerIdAndType(ownerId, ownerType)+1;
            while (itr.hasNext()) {
                MultipartFile file = request.getFile(itr.next());
                if(file.getSize() > 30000000){
                    return ReturnFailUtils.getRepInfo("您上传的文件已超过30M大小限制!");
                }else {
                    String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
                    if (FileUtils.checkFileSuffix(fileSuffix)) {
                        if (StringUtils.isEmpty(ownerType)) {
                            ownerType = FileOwnerTypeBaseEnum.OWNER_TYPE_000.getIndex();
                        }
                        FileInfo fileInfo = service.webPploadFile(file, ownerId, ownerType, fileCount, uploaderDTO);
                        FileInfoBaseDTO fileInfoBaseDTO = new FileInfoBaseDTO();
                        BeanUtils.copyProperties(fileInfo, fileInfoBaseDTO);
                        files.add(fileInfoBaseDTO);
                        fileCount++;
                    } else {
                        return ReturnFailUtils.getRepInfo("您上传的文件格式不正确!");
                    }
                }
            }
            return ReturnSucUtils.getRepInfo( "上传成功!", files);
        } catch (Exception e) {
            return ReturnFailUtils.getRepInfo();
        }
    }
    /**
     * 在线查附件
     * @url {ctx}/api/web/fileInfo/show/{id}
     * @param id 附件编号
     * @param response 响应头
     * @throws Exception
     */
    @GetMapping("/show/{id}")
    public void show(@PathVariable(value = "id") String id, HttpServletResponse response){
        try {
            FileInfo fileInfo = service.getById(id);
            response.reset();
            String contentType = ContentTypeUtils.getContentType(fileInfo.getSuffix());
            response.setContentType(contentType);
            OutputStream outputStream = response.getOutputStream();
            FtpUtils ftpUtil = new FtpUtils();
            InputStream inputStream = ftpUtil.retrieveFileStream(fileInfo.getFullPath());
//            double fileSize = fileInfo.getSize(); // 文件大小
            int chunkSize = 512 * 1024; // 分块大小( KB)
            byte[] buffer = new byte[chunkSize];
            int bytesRead;
            // 循环读取和发送文件的各个部分
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
                outputStream.flush();
            }
//            IOUtils.copy(inputStream, outputStream, chunkSize);
            //关闭流
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(outputStream);
        } catch (Exception e) {
            log.error("controller接口[FileInfoWebController.show]请求异常:"+e, e);
            throw new ClientException("FileInfoWebController.show", e);
        }
    }
    /**
     * 在线下载附件-文件流方式
     * @url {ctx}/api/web/fileInfo/down/{id}
     * @param id 附件编号
     * @param response 响应头
     */
    @GetMapping("/down/{id}")
    public void down(@PathVariable(value = "id") String id, HttpServletResponse response){
        try {
            FileInfo fileInfo = service.getById(id);
            String contentType = ContentTypeUtils.getContentType(fileInfo.getSuffix());
            response.setContentType(contentType);
            String fileName = URLEncoder.encode(fileInfo.getName() + BaseConsts.DOT + fileInfo.getSuffix(), "UTF-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            OutputStream outputStream = response.getOutputStream();
            FtpUtils ftpUtil = new FtpUtils();
            InputStream inputStream = ftpUtil.retrieveFileStream(fileInfo.getFullPath());
            IOUtils.copy(inputStream, outputStream);
            //关闭流
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(outputStream);
        } catch (Exception e) {
            log.error("controller接口[FileInfoWebController.down]请求异常:"+e, e);
            throw new ClientException("FileInfoWebController.down", e);
        }
    }
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/controller/wechat/FileInfoWechatController.java
New file
@@ -0,0 +1,173 @@
package cn.huge.module.file.controller.wechat;
import cn.huge.base.common.exception.ClientException;
import cn.huge.base.common.utils.ContentTypeUtils;
import cn.huge.base.common.utils.ReturnFailUtils;
import cn.huge.base.common.utils.ReturnSucUtils;
import cn.huge.base.config.CurrentUser;
import cn.huge.module.client.api.impl.CustClientImpl;
import cn.huge.module.constant.BaseConsts;
import cn.huge.module.cust.dto.CtUserDTO;
import cn.huge.module.file.domain.dto.UploaderDTO;
import cn.huge.module.file.domain.po.FileInfo;
import cn.huge.module.file.service.FileInfoService;
import cn.huge.module.file.service.FileRelateService;
import cn.huge.module.file.utils.FileUtils;
import cn.huge.module.file.utils.FtpUtils;
import cn.huge.module.sys.constant.FileOwnerTypeBaseEnum;
import cn.huge.module.sys.dto.FileInfoBaseDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
 * @title: 附件信息表接口api-wechat端
 * @description: 附件信息表接口api-wechat端
 * @company: hugeinfo
 * @author: liyj
 * @time: 2024-08-28 20:06:18
 * @version: 1.0.0
 */
@Slf4j
@RestController
@RequestMapping("/api/wechat/fileInfo")
public class FileInfoWechatController {
    @Autowired(required = false)
    private HttpServletRequest request;
    @Autowired
    private FileInfoService service;
    @Autowired
    private FileRelateService fileRelateService;
    @Autowired
    private CustClientImpl custClient;
    /**
     * 页面附件上传-文件流方式
     * @url {ctx}/api/wechat/fileInfo/upload/{ownerId}/{ownerType}
     * @param ownerId 所属业务编号
     * @param ownerType 所属业务类型
     * @param request 请求头
     * @return Object
     */
    @PostMapping("/upload/{ownerId}/{ownerType}")
    public Object upload(@PathVariable(value = "ownerId") String ownerId, @PathVariable(value = "ownerType") String ownerType,
                         @CurrentUser String userId, MultipartHttpServletRequest request) {
        try{
            CtUserDTO loginUser = custClient.clientGetUser(userId);
            UploaderDTO uploaderDTO = new UploaderDTO();
            BeanUtils.copyProperties(loginUser, uploaderDTO);
            List<FileInfoBaseDTO> files = new ArrayList<>();
            Iterator<String> itr = request.getFileNames();
            int fileCount = fileRelateService.countByOwnerIdAndType(ownerId, ownerType)+1;
            while (itr.hasNext()) {
                MultipartFile file = request.getFile(itr.next());
                if(file.getSize() > 30000000){
                    return ReturnFailUtils.getRepInfo("您上传的文件已超过30M大小限制!");
                }else {
                    String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
                    if (FileUtils.checkFileSuffix(fileSuffix)) {
                        if (StringUtils.isEmpty(ownerType)) {
                            ownerType = FileOwnerTypeBaseEnum.OWNER_TYPE_000.getIndex();
                        }
                        FileInfo fileInfo = service.webPploadFile(file, ownerId, ownerType, fileCount, uploaderDTO);
                        FileInfoBaseDTO fileInfoBaseDTO = new FileInfoBaseDTO();
                        BeanUtils.copyProperties(fileInfo, fileInfoBaseDTO);
                        files.add(fileInfoBaseDTO);
                        fileCount++;
                    } else {
                        return ReturnFailUtils.getRepInfo("您上传的文件格式不正确!");
                    }
                }
            }
            return ReturnSucUtils.getRepInfo( "上传成功!", files);
        } catch (Exception e) {
            return ReturnFailUtils.getRepInfo();
        }
    }
    /**
     * 在线查附件
     * @url {ctx}/api/wechat/fileInfo/show/{id}
     * @param id 附件编号
     * @param response 响应头
     * @throws Exception
     */
    @GetMapping("/show/{id}")
    public void show(@PathVariable(value = "id") String id, HttpServletResponse response){
        try {
            FileInfo fileInfo = service.getById(id);
            response.reset();
            String contentType = ContentTypeUtils.getContentType(fileInfo.getSuffix());
            response.setContentType(contentType);
            OutputStream outputStream = response.getOutputStream();
            FtpUtils ftpUtil = new FtpUtils();
            InputStream inputStream = ftpUtil.retrieveFileStream(fileInfo.getFullPath());
//            double fileSize = fileInfo.getSize(); // 文件大小
            int chunkSize = 512 * 1024; // 分块大小( KB)
            byte[] buffer = new byte[chunkSize];
            int bytesRead;
            // 循环读取和发送文件的各个部分
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
                outputStream.flush();
            }
//            IOUtils.copy(inputStream, outputStream, chunkSize);
            //关闭流
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(outputStream);
        } catch (Exception e) {
            log.error("controller接口[FileInfoWechatController.show]请求异常:"+e, e);
            throw new ClientException("FileInfoWechatController.show", e);
        }
    }
    /**
     * 在线下载附件-文件流方式
     * @url {ctx}/api/wechat/fileInfo/down/{id}
     * @param id 附件编号
     * @param response 响应头
     */
    @GetMapping("/down/{id}")
    public void down(@PathVariable(value = "id") String id, HttpServletResponse response){
        try {
            FileInfo fileInfo = service.getById(id);
            String contentType = ContentTypeUtils.getContentType(fileInfo.getSuffix());
            response.setContentType(contentType);
            String fileName = URLEncoder.encode(fileInfo.getName() + BaseConsts.DOT + fileInfo.getSuffix(), "UTF-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
            OutputStream outputStream = response.getOutputStream();
            FtpUtils ftpUtil = new FtpUtils();
            InputStream inputStream = ftpUtil.retrieveFileStream(fileInfo.getFullPath());
            IOUtils.copy(inputStream, outputStream);
            //关闭流
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(outputStream);
        } catch (Exception e) {
            log.error("controller接口[FileInfoWechatController.down]请求异常:"+e, e);
            throw new ClientException("FileInfoWechatController.down", e);
        }
    }
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/domain/dto/UploaderDTO.java
New file
@@ -0,0 +1,37 @@
package cn.huge.module.file.domain.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
/**
 * @title: 附件上传人信息
 * @description: DTO数据传输对象。
 * @company:hugeinfo
 * @author: chenx
 * @time: 2022-02-22 14:19:43
 * @version 1.0.0
 */
@Data
public class UploaderDTO {
    /**
     * 上传人编号
     */
    private String uploaderId;
    /**
     * 上传人姓名
     */
    private String uploaderName;
    /**
     * 上传人类型,1:工作人员,2:申请方当事人,3:申请方代理人,4:被申请方当事人,5:被申请方代理人
     */
    private Integer uploaderType;
    /**
     * 顾客编号
     */
    private String custId;
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/domain/po/FileInfo.java
@@ -33,7 +33,7 @@
    private String name;
    /**
    * 附件原本名称(不带后缀)
    * 附件原本名称(带后缀)
    */
    @TableField(value = "true_name")
    private String trueName;
@@ -134,5 +134,52 @@
    */
    @TableField(value = "create_time")
    private Date createTime;
    /**
     * 所属业务编号
     */
    @TableField(exist = false)
    private String ownerId;
    /**
     * 所属业务大类
     */
    @TableField(exist = false)
    private String ownerCat;
    /**
     * 所属业务大类名称
     */
    @TableField(exist = false)
    private String ownerCatName;
    /**
     * 所属业务类型W
     */
    @TableField(exist = false)
    private String ownerType;
    /**
     * 所属业务类型名称
     */
    @TableField(exist = false)
    private String ownerTypeName;
    /**
     * 上传人编号
     */
    @TableField(exist = false)
    private String uploaderId;
    /**
     * 上传人姓名
     */
    @TableField(exist = false)
    private String uploaderName;
    /**
     * 上传人类型,1:工作人员,2:申请方当事人,3:申请方代理人,4:被申请方当事人,5:被申请方代理人
     */
    @TableField(exist = false)
    private Integer uploaderType;
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/domain/po/FileRelate.java
@@ -63,7 +63,7 @@
    private String uploaderName;
    /**
    * 上传人类型,1:工作人员,2:申请方,3:被申请方
    * 上传人类型,1:工作人员,2:申请方当事人,3:申请方代理人,4:被申请方当事人,5:被申请方代理人
    */
    @TableField(value = "uploader_type")
    private Integer uploaderType;
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/service/FileInfoService.java
@@ -4,19 +4,23 @@
import cn.huge.base.common.utils.DateUtils;
import cn.huge.base.common.utils.IdUtils;
import cn.huge.module.client.api.impl.UtilsClientImpl;
import cn.huge.module.constant.BaseConsts;
import cn.huge.module.file.dao.mapper.FileInfoMapper;
import cn.huge.module.file.domain.dto.UploaderDTO;
import cn.huge.module.file.domain.po.FileInfo;
import cn.huge.module.file.utils.FtpUtils;
import cn.huge.module.file.utils.FtpMultipartFileWrapper;
import cn.huge.module.sys.constant.FileOwnerTypeBaseEnum;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -36,6 +40,8 @@
    @Autowired
    private FileInfoMapper mapper;
    @Autowired
    private FileRelateService fileRelateService;
    @Autowired
    private UtilsClientImpl utilsClient;
@@ -130,4 +136,80 @@
        }
    }
    /**
     * web端上传附件,保存附件信息和业务关系
     * @param file 附件
     * @param ownerId 所属业务编号
     * @param ownerType 所属业务名称
     * @param fileCount 第几份附件
     * @param uploaderDTO 上传人信息
     * @return
     */
    public FileInfo webPploadFile(MultipartFile file, String ownerId, String ownerType, int fileCount, UploaderDTO uploaderDTO) {
        try {
            String fileId = utilsClient.getNewTimeId();
            // 创建附件信息
            FileInfo fileInfo = new FtpMultipartFileWrapper(file).toWebFileInfo(fileId);
            // 上传到ftp服务器
            FtpUtils ftpUtils = new FtpUtils();
            ftpUtils.upload(fileInfo.getPath(), fileInfo.getFileName(), file.getInputStream());
            // 保存附件信息
            fileInfo.setName(FileOwnerTypeBaseEnum.getDes(ownerType) + BaseConsts.UNDER + fileCount);
            fileInfo.setOwnerId(ownerId);
            fileInfo.setOwnerCat(FileOwnerTypeBaseEnum.getCat(ownerType));
            fileInfo.setOwnerCatName(FileOwnerTypeBaseEnum.getDes(fileInfo.getOwnerCat()));
            fileInfo.setOwnerType(ownerType);
            fileInfo.setOwnerTypeName(FileOwnerTypeBaseEnum.getDes(ownerType));
            fileInfo.setUploaderId(uploaderDTO.getUploaderId());
            fileInfo.setUploaderName(uploaderDTO.getUploaderName());
            fileInfo.setUploaderType(uploaderDTO.getUploaderType());
            fileInfo.setCustId(uploaderDTO.getCustId());
            mapper.insert(fileInfo);
            // 保存业务关系
            fileRelateService.saveByFileInfo(fileInfo);
            return fileInfo;
        } catch (Exception e) {
            log.error("service方法[FileInfoService.uploadFile]调用失败,异常信息:"+e, e);
            throw new ServiceException("FileInfoService.uploadFile", e);
        }
    }
    /**
     * wechat端上传附件,保存附件信息和业务关系
     * @param file 附件
     * @param ownerId 所属业务编号
     * @param ownerType 所属业务名称
     * @param fileCount 第几份附件
     * @param uploaderDTO 上传人信息
     * @return
     */
    public FileInfo wechatPploadFile(MultipartFile file, String ownerId, String ownerType, int fileCount, UploaderDTO uploaderDTO) {
        try {
            String fileId = utilsClient.getNewTimeId();
            // 创建附件信息
            FileInfo fileInfo = new FtpMultipartFileWrapper(file).toWechatFileInfo(fileId);
            // 上传到ftp服务器
            FtpUtils ftpUtils = new FtpUtils();
            ftpUtils.upload(fileInfo.getPath(), fileInfo.getFileName(), file.getInputStream());
            // 保存附件信息
            fileInfo.setName(FileOwnerTypeBaseEnum.getDes(ownerType) + BaseConsts.UNDER + fileCount);
            fileInfo.setOwnerId(ownerId);
            fileInfo.setOwnerCat(FileOwnerTypeBaseEnum.getCat(ownerType));
            fileInfo.setOwnerCatName(FileOwnerTypeBaseEnum.getDes(fileInfo.getOwnerCat()));
            fileInfo.setOwnerType(ownerType);
            fileInfo.setOwnerTypeName(FileOwnerTypeBaseEnum.getDes(ownerType));
            fileInfo.setUploaderId(uploaderDTO.getUploaderId());
            fileInfo.setUploaderName(uploaderDTO.getUploaderName());
            fileInfo.setUploaderType(uploaderDTO.getUploaderType());
            fileInfo.setCustId(uploaderDTO.getCustId());
            mapper.insert(fileInfo);
            // 保存业务关系
            fileRelateService.saveByFileInfo(fileInfo);
            return fileInfo;
        } catch (Exception e) {
            log.error("service方法[FileInfoService.uploadFile]调用失败,异常信息:"+e, e);
            throw new ServiceException("FileInfoService.uploadFile", e);
        }
    }
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/service/FileRelateService.java
@@ -5,7 +5,10 @@
import cn.huge.base.common.utils.IdUtils;
import cn.huge.module.client.api.impl.UtilsClientImpl;
import cn.huge.module.file.dao.mapper.FileRelateMapper;
import cn.huge.module.file.domain.dto.UploaderDTO;
import cn.huge.module.file.domain.po.FileInfo;
import cn.huge.module.file.domain.po.FileRelate;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -130,4 +133,43 @@
        }
    }
    /**
     * 根据所属业务编号和类型统计
     * @param ownerId 所属业务编号
     * @param ownerType 所属业务类型
     * @return int 统计数
     */
    public int countByOwnerIdAndType(String ownerId, String ownerType){
        QueryWrapper<FileRelate> fileRelateQueryWrapper = new QueryWrapper<>();
        fileRelateQueryWrapper.eq("owner_id", ownerId).eq("owner_type", ownerType);
        return mapper.selectCount(fileRelateQueryWrapper);
    }
    /**
     * 根据附件信息新增附件业务关系
     * @param fileInfo 附件信息
     */
    public void saveByFileInfo(FileInfo fileInfo) {
        try {
            // 保存业务关系
            FileRelate fileRelate = new FileRelate();
            fileRelate.setId(utilsClient.getNewTimeId());
            fileRelate.setFileId(fileInfo.getId());
            fileRelate.setOwnerId(fileInfo.getOwnerId());
            fileRelate.setOwnerCat(fileInfo.getOwnerCat());
            fileRelate.setOwnerType(fileInfo.getOwnerType());
            fileRelate.setUploaderId(fileInfo.getUploaderId());
            fileRelate.setUploaderName(fileInfo.getUploaderName());
            fileRelate.setUploaderType(fileInfo.getUploaderType());
            fileRelate.setCustId(fileInfo.getCustId());
            Date nowDate = DateUtils.getNowDate();
            fileRelate.setCreateTime(nowDate);
            fileRelate.setUpdateTime(nowDate);
            mapper.insert(fileRelate);
        } catch (Exception e) {
            log.error("service方法[FileRelateService.uploadFile]调用异常:"+e, e);
            throw new ServiceException("FileRelateService.uploadFile", e);
        }
    }
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/utils/FileUtils.java
New file
@@ -0,0 +1,40 @@
package cn.huge.module.file.utils;
import cn.huge.base.common.constant.FileConsts;
/**
 * @author liyj
 */
public class FileUtils {
    /**
     * 校验文件格式
     *
     * @param fileSuffix
     * @return
     */
    public static Boolean checkFileSuffix(String fileSuffix){
        if(FileConsts._doc.equalsIgnoreCase(fileSuffix) || FileConsts._docx.equalsIgnoreCase(fileSuffix) ||
                FileConsts._jpeg.equalsIgnoreCase(fileSuffix) || FileConsts._jpg.equalsIgnoreCase(fileSuffix) || FileConsts._png.equalsIgnoreCase(fileSuffix) || FileConsts._bmp.equalsIgnoreCase(fileSuffix) ||
                FileConsts._pdf.equalsIgnoreCase(fileSuffix) || FileConsts._mp4.equalsIgnoreCase(fileSuffix) || FileConsts._mp3.equalsIgnoreCase(fileSuffix) || FileConsts._avi.equalsIgnoreCase(fileSuffix)
                || FileConsts._xlsx.equalsIgnoreCase(fileSuffix)){
            return true;
        }else {
            return false;
        }
        // 不做限制
//        return true;
    }
    public static Boolean checkImageSuffix(String fileSuffix){
        if(FileConsts._jpeg.equalsIgnoreCase(fileSuffix) || FileConsts._jpg.equalsIgnoreCase(fileSuffix) ||
                FileConsts._png.equalsIgnoreCase(fileSuffix) || FileConsts._bmp.equalsIgnoreCase(fileSuffix) ||
                FileConsts._gif.equalsIgnoreCase(fileSuffix)){
            return true;
        }else {
            return false;
        }
    }
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/utils/FtpMultipartFileWrapper.java
New file
@@ -0,0 +1,184 @@
package cn.huge.module.file.utils;
import cn.huge.base.common.constant.FileCatEnum;
import cn.huge.base.common.exception.ServiceException;
import cn.huge.base.common.utils.DateUtils;
import cn.huge.module.constant.BaseConsts;
import cn.huge.module.file.config.FtpFileConfig;
import cn.huge.module.file.domain.po.FileInfo;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Date;
/**
 * @title: 上传附件包装处理类
 * @description: 上传附件包装处理类
 * @company: hugeinfo
 * @author: liyj
 * @time: 2021-11-05 16:51:48
 * @version: 1.0.0
 */
public class FtpMultipartFileWrapper {
    static final long kilobyte = 1024;
    static final long megabyte = 1024 * 1024L;
    static final long gigabyte = 1024 * 1024 * 1024L;
    static final BigDecimal kilobyteDividend = new BigDecimal(kilobyte);
    static final BigDecimal megabyteDividend = new BigDecimal(megabyte);
    static final BigDecimal gigabyteDividend = new BigDecimal(gigabyte);
    static final String SHOW_URL_WEB = "/api/web/fileInfo/show";
    static final String DOWN_URL_WEB = "/api/web/fileInfo/down";
    static final String SHOW_URL_WECHAT = "/api/wechat/fileInfo/show";
    static final String DOWN_URL_WECHAT = "/api/wechat/fileInfo/down";
    static final String STORE_WAY = "ftp";
    private MultipartFile file;
    public FtpMultipartFileWrapper(MultipartFile file) {
        this.file = file;
    }
    /**
     * web端上传附件
     * @param fileId
     * @return
     */
    public FileInfo toWebFileInfo(String fileId) {
        FileInfo fileInfo = new FileInfo();
        fileInfo.setId(fileId);
        fileInfo.setSuffix(this.getFileSuffix());
        fileInfo.setTrueName(this.getFileName() + BaseConsts.DOT + fileInfo.getSuffix());
        fileInfo.setFileName(this.getFileName() + BaseConsts.UNDER + fileInfo.getId() + BaseConsts.DOT + fileInfo.getSuffix());
        fileInfo.setCat(FileCatEnum.getFileCat(fileInfo.getSuffix()));
        fileInfo.setSize(this.getFileSize());
        fileInfo.setUnit(this.getFileUnit());
        fileInfo.setMd5Code(this.getFileVerifyCode());
        fileInfo.setStoreWay(STORE_WAY);
        fileInfo.setPath(this.getFileDir());
        fileInfo.setFullPath(fileInfo.getPath() + BaseConsts.SLANT + fileInfo.getFileName());
        fileInfo.setShowUrl(SHOW_URL_WEB + BaseConsts.SLANT + fileInfo.getId());
        fileInfo.setDownUrl(DOWN_URL_WEB + BaseConsts.SLANT + fileInfo.getId());
        // todo
        fileInfo.setZipUrl(fileInfo.getShowUrl());
        Date nowDate = DateUtils.getNowDate();
        fileInfo.setCreateTime(nowDate);
        fileInfo.setUpdateTime(nowDate);
        fileInfo.setDeleteStatus(BaseConsts.DELETE_STATUS_1);
        return fileInfo;
    }
    /**
     * wechat上传附件
     * @param fileId
     * @return
     */
    public FileInfo toWechatFileInfo(String fileId) {
        FileInfo fileInfo = new FileInfo();
        fileInfo.setId(fileId);
        fileInfo.setSuffix(this.getFileSuffix());
        fileInfo.setTrueName(this.getFileName() + BaseConsts.DOT + fileInfo.getSuffix());
        fileInfo.setFileName(this.getFileName() + BaseConsts.UNDER + fileInfo.getId() + BaseConsts.DOT + fileInfo.getSuffix());
        fileInfo.setCat(FileCatEnum.getFileCat(fileInfo.getSuffix()));
        fileInfo.setSize(this.getFileSize());
        fileInfo.setUnit(this.getFileUnit());
        fileInfo.setMd5Code(this.getFileVerifyCode());
        fileInfo.setStoreWay(STORE_WAY);
        fileInfo.setPath(this.getFileDir());
        fileInfo.setFullPath(fileInfo.getPath() + BaseConsts.SLANT + fileInfo.getFileName());
        fileInfo.setShowUrl(SHOW_URL_WECHAT + BaseConsts.SLANT + fileInfo.getId());
        fileInfo.setDownUrl(DOWN_URL_WECHAT + BaseConsts.SLANT + fileInfo.getId());
        // todo
        fileInfo.setZipUrl(fileInfo.getShowUrl());
        Date nowDate = DateUtils.getNowDate();
        fileInfo.setCreateTime(nowDate);
        fileInfo.setUpdateTime(nowDate);
        fileInfo.setDeleteStatus(BaseConsts.DELETE_STATUS_1);
        return fileInfo;
    }
    /**
     * 获取文件名称
     */
    public String getFileName() {
        return StringUtils.substringBeforeLast(this.file.getOriginalFilename(), BaseConsts.DOT);
    }
    /**
     * 获取文件后缀
     */
    public String getFileSuffix() {
        return StringUtils.substringAfterLast(this.file.getOriginalFilename(), BaseConsts.DOT);
    }
    /**
     * 获取文件存储目录,以斜杠开头(/home/ftp/huge-dyh/2022/3)
     */
    public String getFileDir() {
        //按照年月构建目录
        Calendar ca = Calendar.getInstance();
        StringBuilder builder = new StringBuilder();
        builder.append(FtpFileConfig.getRootdir());
        builder.append(BaseConsts.SLANT);
        builder.append(ca.get(Calendar.YEAR));
        builder.append(BaseConsts.SLANT);
        builder.append(ca.get(Calendar.MONTH) + 1);
        return builder.toString();
    }
    /**
     * 获取文件大小, 根据不同的单位进行运算
     */
    public double getFileSize() {
        long size = this.file.getSize();
        BigDecimal divisor = new BigDecimal(size);
        String unit = this.getFileUnit();
        if (BaseConsts.B.equals(unit)) {
            return size;
        } else if (BaseConsts.KB.equals(unit)) {
            return divisor.divide(kilobyteDividend, 2, RoundingMode.HALF_UP).doubleValue();
        } else if (BaseConsts.MB.equals(unit)) {
            return divisor.divide(megabyteDividend, 2, RoundingMode.HALF_UP).doubleValue();
        } else if (BaseConsts.GB.equals(unit)) {
            return divisor.divide(gigabyteDividend, 2, RoundingMode.HALF_UP).doubleValue();
        }
        return 0.0;
    }
    /**
     * 获取文件单位, B|KB|MB|GB
     */
    public String getFileUnit() {
        long size = this.file.getSize();
        if (size > 0 && size <= kilobyte) {
            return BaseConsts.B;
        } else if (size > kilobyte && size <= megabyte) {
            return BaseConsts.KB;
        } else if (size > megabyte && size <= gigabyte) {
            return BaseConsts.MB;
        } else if (size > gigabyte) {
            return BaseConsts.GB;
        }
        return BaseConsts.B;
    }
    /**
     * 获取文件校验码, MD5
     */
    public String getFileVerifyCode() {
        try {
            return DigestUtils.md5Hex(this.file.getBytes());
        } catch (IOException e) {
            throw new ServiceException("MultipartFileWrapper.getFileVerifyCode", e);
        }
    }
}
dyh-service/dyh-sys/src/main/java/cn/huge/module/file/utils/FtpUtils.java
New file
@@ -0,0 +1,256 @@
package cn.huge.module.file.utils;
import cn.huge.base.common.exception.MethodException;
import cn.huge.module.constant.BaseConsts;
import cn.huge.module.file.config.FtpFileConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
/**
 * @title: ftp配工具类
 * @description: ftp配工具类
 * @company: hugeinfo
 * @author: liyj
 * @time: 2021-11-05 16:51:48
 * @version: 1.0.0
 */
@Slf4j
@Component
public class FtpUtils {
    /**
     * 上传附件.
     * @param path 服务器存储路径(/home/ftp/huge-dyh)
     * @param fileName 文件名(1.jpg)
     * @param inputStream 文件流
     */
    public void upload(String path, String fileName, InputStream inputStream) {
        FTPClient ftpClient = new FTPClient();
        try {
            if (connect(ftpClient)) {
                // 检查文件目录是否存在,不存在创建目录
                if (this.checkDir(ftpClient, path)) {
                    // 检查是否上传成功
                    if (storeFile(ftpClient, fileName, inputStream)) {
                        disconnect(ftpClient);
                    }else{
                        disconnect(ftpClient);
                        throw new MethodException("连接ftp成功,上传文件失败!");
                    }
                }else{
                    disconnect(ftpClient);
                    throw new MethodException("连接ftp成功,检查文件目录不存在!");
                }
            }else{
                disconnect(ftpClient);
                throw new MethodException("连接ftp失败!");
            }
        } catch (Exception e) {
            disconnect(ftpClient);
            log.error("方法[FtpUtils.upload]调用异常:"+e, e);
            throw new MethodException("FtpUtils.upload", e);
        }
    }
    /**
     * 从文件服务器获取文件流.
     * @param filePath 文件存储完整路径(/home/ftp/huge-dyh/1.jpg)
     * @return {@link InputStream}
     * @throws IOException
     */
    public InputStream retrieveFileStream(String filePath) {
        if (StringUtils.isBlank(filePath)) {
            throw new MethodException("文件路径为空!");
        }
        log.info("读取文件路径[filePath]值" + filePath);
        FTPClient ftpClient = new FTPClient();
        try {
            if (connect(ftpClient)) {
                filePath = new String(filePath.getBytes("UTF-8"), "iso-8859-1");
                InputStream inputStream = ftpClient.retrieveFileStream(filePath);
                disconnect(ftpClient);
                return inputStream;
            }else{
                disconnect(ftpClient);
                throw new MethodException("连接ftp失败!");
            }
        } catch (Exception e) {
            disconnect(ftpClient);
            log.error("方法[FtpUtils.retrieveFileStream]调用异常:"+e, e);
            throw new MethodException("FtpUtils.retrieveFileStream", e);
        }
    }
    /**
     * 删除文件
     * @param filePath 文件存储完整路径(/home/ftp/huge-dyh/1.jpg)
     */
    public void deleteFile(String filePath) {
        try{
            String workingPath = filePath.substring(0, filePath.lastIndexOf("/"));
            String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length());
            deleteFile(workingPath, fileName);
        }catch (Exception e){
            log.error("方法[FtpUtils.deleteFile]调用异常:"+e, e);
            throw new MethodException("FtpUtils.deleteFile", e);
        }
    }
    /**
     * ftp操作-连接ftp
     * @param ftpClient ftp工具
     * @return boolean
     */
    private boolean connect(FTPClient ftpClient) {
        boolean flag = false;
        try {
            // 远程ftp需要加上,允许被动连接
            ftpClient.enterLocalPassiveMode();
            FTPClientConfig clientConfig = new FTPClientConfig();
            clientConfig.setLenientFutureDates(true);
            ftpClient.configure(clientConfig);
            // 连接ftp
            ftpClient.connect(FtpFileConfig.getHostname(), FtpFileConfig.getPort());
            if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                log.info("连接ftp成功!");
                ftpClient.login(FtpFileConfig.getUsername(), FtpFileConfig.getPassword());
                if (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
                    // 设置以二进制方式传输
                    ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
                    // 设置UTF-8编码
                    ftpClient.setControlEncoding("UTF-8");
                    //设置传输方式为流方式
                    ftpClient.setFileTransferMode(FTPClient.STREAM_TRANSFER_MODE);
                    // 设置缓冲区大小
                    ftpClient.setBufferSize(1024);
                    log.info("登录ftp成功!");
                    flag = true;
                } else {
                    log.error("登录ftp失败,可能用户名或密码错误!");
                }
            }else{
                log.error("连接ftp失败,可能ip或端口错误!");
            }
            return flag;
        } catch (IOException e) {
            log.error("方法[FtpUtils.connect]调用异常:"+e, e);
            throw new MethodException("FtpUtils.connect", e);
        }
    }
    /**
     * ftp操作-检查文件目录不存在时,创建目录
     * @param ftpClient ftp工具
     * @param path 服务器存储路径(/home/ftp/huge-dyh)
     * @return String
     */
    public Boolean checkDir(FTPClient ftpClient, String path){
        try{
            log.info("上传路径为:" + path);
            Boolean flag = false;
            if (!ftpClient.changeWorkingDirectory(path)) {
                StringBuffer rootPath = new StringBuffer();
                rootPath.append(FtpFileConfig.getRootdir());
                // 创建文件目录
                path = path.replace(FtpFileConfig.getRootdir() + BaseConsts.SLANT, "");
                String[] paths = path.split(BaseConsts.SLANT);
                for (String filePath: paths){
                    if (StringUtils.isBlank(filePath)){
                        continue;
                    }else{
                        rootPath.append(BaseConsts.SLANT);
                        rootPath.append(filePath);
                        if (!ftpClient.changeWorkingDirectory(rootPath.toString())){
                            ftpClient.makeDirectory(rootPath.toString());
                        }
                    }
                }
                // 严谨一点,再检查文件目录是否存在
                if (ftpClient.changeWorkingDirectory(rootPath.toString())) {
                    flag = true;
                }
            }else{
                flag = true;
            }
            return flag;
        }catch (Exception e){
            log.error("方法[FtpUtils.makeDir]调用异常:"+e, e);
            throw new MethodException("FtpUtils.makeDir", e);
        }
    }
    /**
     * ftp操作-上传文件到ftp
     * @param ftpClient ftp工具
     * @param fileName 文件名称(1.jpg)
     * @param fileInputStream 文件流
     * @return boolean
     */
    private boolean storeFile(FTPClient ftpClient, String fileName, InputStream fileInputStream) {
        boolean flag = false;
        try {
            fileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
            log.info("上传文件名为:" + fileName);
            ftpClient.storeFile(fileName, fileInputStream);
            int reply = ftpClient.getReplyCode();
            if (FTPReply.isPositiveCompletion(reply)) {
                flag = true;
                log.info("上传文件成功!");
            }else{
                log.error("上传文件失败!请求响应码[reply]值为:" + reply);
            }
            fileInputStream.close();
            return flag;
        } catch (IOException e) {
            log.error("方法[FtpUtils.storeFile]调用异常:"+e, e);
            throw new MethodException("FtpUtils.storeFile", e);
        }
    }
    /**
     * ftp操作-删除附件.
     * @param path 服务器存储路径(/home/ftp/huge-dyh)
     * @param fileName 附件名称(1.jpg)
     */
    public void deleteFile(String path, String fileName) {
        FTPClient ftpClient = new FTPClient();
        try{
            connect(ftpClient);
            if (ftpClient.changeWorkingDirectory(path)) {
                // 删除文件
                ftpClient.dele(fileName);
                disconnect(ftpClient);
            }else {
                disconnect(ftpClient);
                throw new MethodException("文件路径不存在!");
            }
        }catch (Exception e){
            disconnect(ftpClient);
            log.error("方法[FtpUtils.deleteFile]调用异常:"+e, e);
            throw new MethodException("FtpUtils.deleteFile", e);
        }
    }
    /**
     * ftp操作-断开ftp连接.
     * @param ftpClient ftp工具
     */
    private void disconnect(FTPClient ftpClient) {
        if (ftpClient.isConnected()) {
            try {
                ftpClient.disconnect();
            } catch (IOException e) {
                log.error("方法[FtpUtils.disconnect]调用异常:"+e, e);
                throw new MethodException("FtpUtils.disconnect", e);
            }
        }
    }
}
dyh-service/dyh-sys/src/main/resources/config/application.yml
@@ -60,13 +60,4 @@
        logic-delete-value: 1
        #字段策略,IGNORED:忽略判断,NOT_NULL:非null判断,NOT_EMPTY:非空判断,DEFAULT:默认,NEVER:不加入sql
        update-strategy: IGNORED
  mapper-locations: classpath*:/cn/huge/*/*/dao/mapper/xml/*Mapper.xml
#附件配置
file:
  #存储方式
  store-way: ftp
  #查看地址
  show-path: /api/fileInfo/show
  #下载地址
  down-path: /api/fileInfo/down
  mapper-locations: classpath*:/cn/huge/*/*/dao/mapper/xml/*Mapper.xml