完善文件V2功能,修改文件下载方式为重定向下载,增加查看码校验,增加文件下载次数统计
This commit is contained in:
parent
5c8ed3e294
commit
56b317684d
@ -0,0 +1,31 @@
|
||||
package ink.wgink.module.file.config;
|
||||
|
||||
import ink.wgink.module.file.filter.FilesFilter;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @ClassName: FileConfig
|
||||
* @Description: 文件配置
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/1 09:48
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Configuration
|
||||
public class FileConfig {
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean filesFilter() {
|
||||
FilesFilter filesFilter = new FilesFilter();
|
||||
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
|
||||
filterRegistrationBean.setFilter(filesFilter);
|
||||
filterRegistrationBean.addUrlPatterns("/files/*");
|
||||
filterRegistrationBean.setName("filesFilter");
|
||||
filterRegistrationBean.setOrder(20);
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package ink.wgink.module.file.controller.api.filedownload;
|
||||
|
||||
import ink.wgink.common.base.DefaultBaseController;
|
||||
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||
import ink.wgink.module.file.pojo.dtos.filedownload.FileDownloadDTO;
|
||||
import ink.wgink.module.file.service.filedownload.IFileDownloadService;
|
||||
import ink.wgink.pojo.ListPage;
|
||||
import ink.wgink.pojo.result.ErrorResult;
|
||||
import ink.wgink.pojo.result.SuccessResultList;
|
||||
import io.swagger.annotations.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassName: FileDownloadController
|
||||
* @Description: 文件下载
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/2 16:21
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "文件下载接口")
|
||||
@RestController
|
||||
@RequestMapping(ISystemConstant.API_PREFIX + "/file-download")
|
||||
public class FileDownloadController extends DefaultBaseController {
|
||||
|
||||
@Autowired
|
||||
private IFileDownloadService fileDownloadService;
|
||||
|
||||
@ApiOperation(value = "下载分页列表", notes = "下载分页列表接口")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "page", value = "当前页码", paramType = "query", dataType = "int", defaultValue = "1"),
|
||||
@ApiImplicitParam(name = "rows", value = "显示数量", paramType = "query", dataType = "int", defaultValue = "20"),
|
||||
})
|
||||
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||
@GetMapping("listpage/file-id/{fileId}")
|
||||
public SuccessResultList<List<FileDownloadDTO>> listPageByFileId(@PathVariable("fileId") String fileId, ListPage page) {
|
||||
Map<String, Object> params = requestParams();
|
||||
page.setParams(params);
|
||||
return fileDownloadService.listPageByFileId(fileId, page);
|
||||
}
|
||||
|
||||
}
|
@ -3,18 +3,23 @@ package ink.wgink.module.file.controller.api.v2;
|
||||
import ink.wgink.common.base.DefaultBaseController;
|
||||
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||
import ink.wgink.module.file.enums.UploadTypeEnum;
|
||||
import ink.wgink.module.file.pojo.dtos.FileInfoDTO;
|
||||
import ink.wgink.module.file.pojo.dtos.v2.FileUploadSuccessDTO;
|
||||
import ink.wgink.module.file.service.v2.IFileService;
|
||||
import ink.wgink.pojo.ListPage;
|
||||
import ink.wgink.pojo.result.ErrorResult;
|
||||
import ink.wgink.pojo.result.SuccessResult;
|
||||
import ink.wgink.pojo.result.SuccessResultData;
|
||||
import ink.wgink.pojo.result.SuccessResultList;
|
||||
import io.swagger.annotations.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassName: FileController
|
||||
* @Description: 文件处理
|
||||
@ -22,7 +27,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
* @Date: 2019/3/10 7:03 PM
|
||||
* @Version: 1.0
|
||||
**/
|
||||
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "文件接口")
|
||||
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "文件接口-V2")
|
||||
@RestController("fileControllerV2")
|
||||
@RequestMapping(ISystemConstant.API_PREFIX + "/file/v2")
|
||||
public class FileController extends DefaultBaseController {
|
||||
@ -70,11 +75,35 @@ public class FileController extends DefaultBaseController {
|
||||
return uploadSingle(audio, UploadTypeEnum.AUDIO);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "删除文件", notes = "删除文件接口")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "ids", value = "ID列表,用下划线分隔", paramType = "path", example = "1_2_3")
|
||||
})
|
||||
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||
@DeleteMapping("delete/{ids}")
|
||||
public synchronized SuccessResult delete(@PathVariable("ids") String ids) {
|
||||
fileService.delete(Arrays.asList(ids.split("\\_")));
|
||||
return new SuccessResult();
|
||||
}
|
||||
|
||||
@ApiOperation(value = "文件分页列表", notes = "文件分页列表接口")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "page", value = "当前页码", paramType = "query", dataType = "int", defaultValue = "1"),
|
||||
@ApiImplicitParam(name = "rows", value = "显示数量", paramType = "query", dataType = "int", defaultValue = "20"),
|
||||
@ApiImplicitParam(name = "keywords", value = "关键字", paramType = "query", dataType = "String")
|
||||
})
|
||||
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||
@GetMapping("listpage")
|
||||
public SuccessResultList<List<FileInfoDTO>> listPage(ListPage page) {
|
||||
Map<String, Object> params = requestParams();
|
||||
page.setParams(params);
|
||||
return fileService.listPage(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传文件
|
||||
*
|
||||
* @param uploadFile
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
private SuccessResultData<FileUploadSuccessDTO> uploadSingle(MultipartFile uploadFile, UploadTypeEnum uploadTypeEnum) {
|
||||
|
@ -0,0 +1,28 @@
|
||||
package ink.wgink.module.file.controller.route.filedownload;
|
||||
|
||||
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||
import io.swagger.annotations.Api;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* @ClassName: FileDownloadRouteController
|
||||
* @Description: 文件下载
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/2 16:34
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "文件下载")
|
||||
@Controller
|
||||
@RequestMapping(ISystemConstant.ROUTE_PREFIX + "/file-download")
|
||||
public class FileDownloadRouteController {
|
||||
|
||||
@GetMapping("list")
|
||||
public ModelAndView list() {
|
||||
ModelAndView modelAndView = new ModelAndView("file-download/list");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package ink.wgink.module.file.controller.route.v2;
|
||||
|
||||
import ink.wgink.interfaces.consts.ISystemConstant;
|
||||
import ink.wgink.module.file.service.v2.IFileService;
|
||||
import ink.wgink.pojo.result.ErrorResult;
|
||||
import io.swagger.annotations.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @ClassName: FileRouteController
|
||||
* @Description: 文件路由
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/1 15:21
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "文件路由-V2")
|
||||
@Controller("fileRouteControllerV2")
|
||||
@RequestMapping(ISystemConstant.ROUTE_PREFIX + "/file/v2")
|
||||
public class FileRouteController {
|
||||
|
||||
@Autowired
|
||||
private IFileService fileService;
|
||||
|
||||
@GetMapping("list")
|
||||
public ModelAndView list() {
|
||||
ModelAndView modelAndView = new ModelAndView("file/v2/list");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@ApiOperation(value = "文件下载", notes = "文件下载接口")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "isOpen", value = "是否打开,true和false", paramType = "path"),
|
||||
@ApiImplicitParam(name = "fileId", value = "文件ID", paramType = "path")
|
||||
})
|
||||
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
|
||||
@GetMapping("download/{isOpen}/{fileId}")
|
||||
public void download(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
@PathVariable("isOpen") Boolean isOpen,
|
||||
@PathVariable("fileId") String fileId) {
|
||||
fileService.download(request, response, isOpen, fileId);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package ink.wgink.module.file.dao.filedownload;
|
||||
|
||||
import ink.wgink.exceptions.SaveException;
|
||||
import ink.wgink.exceptions.SearchException;
|
||||
import ink.wgink.interfaces.init.IInitBaseTable;
|
||||
import ink.wgink.module.file.pojo.dtos.filedownload.FileDownloadDTO;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassName: IFileDownloadDao
|
||||
* @Description: 文件下载
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/2 09:58
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Repository
|
||||
public interface IFileDownloadDao extends IInitBaseTable {
|
||||
|
||||
/**
|
||||
* 新增下载记录
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
void save(Map<String, Object> params) throws SaveException;
|
||||
|
||||
/**
|
||||
* 下载记录列表
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
* @throws SearchException
|
||||
*/
|
||||
List<FileDownloadDTO> list(Map<String, Object> params) throws SearchException;
|
||||
|
||||
/**
|
||||
* 下载记录统计
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
* @throws SearchException
|
||||
*/
|
||||
Integer count(Map<String, Object> params) throws SearchException;
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package ink.wgink.module.file.filter;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import ink.wgink.exceptions.base.SystemException;
|
||||
import ink.wgink.module.file.manager.FilesManager;
|
||||
import ink.wgink.pojo.bos.files.FilesShowCode;
|
||||
import ink.wgink.pojo.result.ErrorResult;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
/**
|
||||
* @ClassName: FilesFilter
|
||||
* @Description: 文件过滤器
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/1 09:21
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class FilesFilter implements Filter {
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
Filter.super.init(filterConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
|
||||
HttpServletRequest request = (HttpServletRequest) servletRequest;
|
||||
HttpServletResponse response = (HttpServletResponse) servletResponse;
|
||||
String fileId = request.getParameter("file");
|
||||
String code = request.getParameter("code");
|
||||
String isOpen = request.getParameter("open");
|
||||
if (StringUtils.isBlank(code)) {
|
||||
notFoundResponse(response, "查看码不存在");
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(fileId)) {
|
||||
notFoundResponse(response, "文件不存在");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
FilesShowCode showCode = FilesManager.getInstance().getShowCode(fileId, code);
|
||||
if (Integer.parseInt(isOpen) == 0) {
|
||||
// 下载
|
||||
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(showCode.getFileName(), "UTF-8"));
|
||||
}
|
||||
} catch (SystemException e) {
|
||||
notFoundResponse(response, e.getMessage());
|
||||
return;
|
||||
}
|
||||
filterChain.doFilter(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
Filter.super.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件未找到
|
||||
*
|
||||
* @param response
|
||||
* @param errorInfo
|
||||
* @throws IOException
|
||||
*/
|
||||
private void notFoundResponse(HttpServletResponse response, String errorInfo) throws IOException {
|
||||
response.setStatus(HttpStatus.NOT_FOUND.value());
|
||||
response.setHeader("Content-Type", "application/json;charset=UTF-8");
|
||||
ErrorResult result = new ErrorResult(ErrorResult.ErrorResultCodeEnum.FILE_ERROR.getValue(), errorInfo);
|
||||
response.getWriter().write(JSON.toJSONString(result));
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package ink.wgink.module.file.impl;
|
||||
|
||||
import ink.wgink.exceptions.ParamsException;
|
||||
import ink.wgink.interfaces.manager.IFilesShowCodeService;
|
||||
import ink.wgink.pojo.bos.files.FilesShowCode;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @ClassName: FileShowCodeServiceImpl
|
||||
* @Description: 文件显示码
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/1 17:16
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class DefaultFilesShowCodeServiceImpl implements IFilesShowCodeService {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DefaultFilesShowCodeServiceImpl.class);
|
||||
private Map<String, FilesShowCode> showCodeMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void addShowCode(String code, String fileId, String fileName) {
|
||||
showCodeMap.put(fileId, new FilesShowCode(code, fileId, fileName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTimeoutShowCode() {
|
||||
Set<String> keySet = showCodeMap.keySet();
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
long clearTimeoutShowCodeCount = 0;
|
||||
for (String key : keySet) {
|
||||
FilesShowCode showCode = getShowCode(key);
|
||||
if (currentTimeMillis - showCode.getLatestUpdateTime() > SHOW_CODE_TIMEOUT_MILLIS) {
|
||||
showCodeMap.remove(key);
|
||||
clearTimeoutShowCodeCount++;
|
||||
}
|
||||
}
|
||||
LOG.trace(">>>>>> count of clear timeout show code: {}", clearTimeoutShowCodeCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilesShowCode getShowCode(String fileId, String code) {
|
||||
FilesShowCode showCode = getShowCode(fileId);
|
||||
if (showCode == null) {
|
||||
throw new ParamsException("查看码不存在");
|
||||
}
|
||||
if (!StringUtils.equals(showCode.getCode(), code)) {
|
||||
throw new ParamsException("查看码不匹配");
|
||||
}
|
||||
return showCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized FilesShowCode getShowCode(String fileId) {
|
||||
FilesShowCode showCode = showCodeMap.get(fileId);
|
||||
if (showCode != null) {
|
||||
showCode.setLatestUpdateTime(System.currentTimeMillis());
|
||||
}
|
||||
return showCode;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package ink.wgink.module.file.init.build;
|
||||
|
||||
import ink.wgink.interfaces.init.build.IBuildServiceMenu;
|
||||
import ink.wgink.pojo.bos.menu.InitMenuBO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @ClassName: BuildFileMenu
|
||||
* @Description: 构建文件菜单
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/2 17:17
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Component
|
||||
public class BuildFileMenu implements IBuildServiceMenu {
|
||||
|
||||
@Override
|
||||
public void buildMenu(List<InitMenuBO> initMenus) {
|
||||
InitMenuBO fileParentMenu = new InitMenuBO();
|
||||
fileParentMenu.setMenuName("文件管理");
|
||||
fileParentMenu.setMenuSummary("文件管理");
|
||||
|
||||
// 获取子菜单
|
||||
List<InitMenuBO> subMenus = new ArrayList<>();
|
||||
InitMenuBO initMenu = new InitMenuBO();
|
||||
initMenu.setMenuName("上传文件");
|
||||
initMenu.setMenuSummary("上传文件");
|
||||
initMenu.setMenuUrl("/route/file/v2/list");
|
||||
subMenus.add(initMenu);
|
||||
|
||||
// 设置子菜单
|
||||
fileParentMenu.setSubMenus(subMenus);
|
||||
// 更新子菜单
|
||||
initMenus.add(fileParentMenu);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package ink.wgink.module.file.manager;
|
||||
|
||||
import ink.wgink.interfaces.manager.IFilesShowCodeService;
|
||||
import ink.wgink.pojo.bos.files.FilesShowCode;
|
||||
import ink.wgink.util.string.WStringUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @ClassName: FilesManager
|
||||
* @Description: 文件管理
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/1 10:47
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class FilesManager {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FilesManager.class);
|
||||
// 查看码超时清理时间,1分钟
|
||||
private static FilesManager filesManager = FilesManagerBuilder.filesManager;
|
||||
private IFilesShowCodeService filesShowCodeService;
|
||||
|
||||
private FilesManager() {
|
||||
|
||||
}
|
||||
|
||||
public static FilesManager getInstance() {
|
||||
return filesManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成显示码
|
||||
*
|
||||
* @param fileId
|
||||
* @return
|
||||
*/
|
||||
public String generateCode(String fileId, String fileName) {
|
||||
FilesShowCode showCode = filesShowCodeService.getShowCode(fileId);
|
||||
String code;
|
||||
if (showCode == null) {
|
||||
code = WStringUtil.randomSubStr(fileId.replaceAll("-", ""), 4);
|
||||
filesShowCodeService.addShowCode(code, fileId, fileName);
|
||||
} else {
|
||||
code = showCode.getCode();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除超时显示码
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public void clearTimeoutShowCode() {
|
||||
filesShowCodeService.clearTimeoutShowCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取显示码
|
||||
*
|
||||
* @param fileId
|
||||
* @param code
|
||||
*/
|
||||
public FilesShowCode getShowCode(String fileId, String code) {
|
||||
return filesShowCodeService.getShowCode(fileId, code);
|
||||
}
|
||||
|
||||
public void setFilesShowCodeService(IFilesShowCodeService filesShowCodeService) {
|
||||
this.filesShowCodeService = filesShowCodeService;
|
||||
}
|
||||
|
||||
private static class FilesManagerBuilder {
|
||||
public static FilesManager filesManager = new FilesManager();
|
||||
}
|
||||
|
||||
}
|
@ -24,6 +24,12 @@ public class FileInfoDTO extends FileDTO {
|
||||
private String fileSummary;
|
||||
@ApiModelProperty(name = "isBack", value = "是否备份")
|
||||
private Integer isBack;
|
||||
@ApiModelProperty(name = "creator", value = "创建人")
|
||||
private String creator;
|
||||
@ApiModelProperty(name = "gmtCreate", value = "创建时间")
|
||||
private String gmtCreate;
|
||||
@ApiModelProperty(name = "downloadCount", value = "下载次数")
|
||||
private Integer downloadCount;
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath == null ? "" : filePath.trim();
|
||||
@ -59,6 +65,30 @@ public class FileInfoDTO extends FileDTO {
|
||||
this.isBack = isBack;
|
||||
}
|
||||
|
||||
public String getCreator() {
|
||||
return creator == null ? "" : creator.trim();
|
||||
}
|
||||
|
||||
public void setCreator(String creator) {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
public String getGmtCreate() {
|
||||
return gmtCreate == null ? "" : gmtCreate.trim();
|
||||
}
|
||||
|
||||
public void setGmtCreate(String gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
|
||||
public Integer getDownloadCount() {
|
||||
return downloadCount == null ? 0 : downloadCount;
|
||||
}
|
||||
|
||||
public void setDownloadCount(Integer downloadCount) {
|
||||
this.downloadCount = downloadCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("{");
|
||||
@ -70,6 +100,12 @@ public class FileInfoDTO extends FileDTO {
|
||||
.append(fileSummary).append('\"');
|
||||
sb.append(",\"isBack\":")
|
||||
.append(isBack);
|
||||
sb.append(",\"creator\":\"")
|
||||
.append(creator).append('\"');
|
||||
sb.append(",\"gmtCreate\":\"")
|
||||
.append(gmtCreate).append('\"');
|
||||
sb.append(",\"downloadCount\":")
|
||||
.append(downloadCount);
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
package ink.wgink.module.file.pojo.dtos.filedownload;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
/**
|
||||
* @ClassName: FileDownloadDTO
|
||||
* @Description: 文件下载
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/2 10:07
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@ApiModel
|
||||
public class FileDownloadDTO {
|
||||
|
||||
@ApiModelProperty(name = "fileDownloadId", value = "主键")
|
||||
private String fileDownloadId;
|
||||
@ApiModelProperty(name = "fileId", value = "文件ID")
|
||||
private String fileId;
|
||||
@ApiModelProperty(name = "clientIp", value = "客户端IP")
|
||||
private String clientIp;
|
||||
@ApiModelProperty(name = "gmtCreate", value = "下载时间")
|
||||
private String gmtCreate;
|
||||
|
||||
public String getFileDownloadId() {
|
||||
return fileDownloadId == null ? "" : fileDownloadId.trim();
|
||||
}
|
||||
|
||||
public void setFileDownloadId(String fileDownloadId) {
|
||||
this.fileDownloadId = fileDownloadId;
|
||||
}
|
||||
|
||||
public String getFileId() {
|
||||
return fileId == null ? "" : fileId.trim();
|
||||
}
|
||||
|
||||
public void setFileId(String fileId) {
|
||||
this.fileId = fileId;
|
||||
}
|
||||
|
||||
public String getClientIp() {
|
||||
return clientIp == null ? "" : clientIp.trim();
|
||||
}
|
||||
|
||||
public void setClientIp(String clientIp) {
|
||||
this.clientIp = clientIp;
|
||||
}
|
||||
|
||||
public String getGmtCreate() {
|
||||
return gmtCreate == null ? "" : gmtCreate.trim();
|
||||
}
|
||||
|
||||
public void setGmtCreate(String gmtCreate) {
|
||||
this.gmtCreate = gmtCreate;
|
||||
}
|
||||
}
|
@ -23,6 +23,8 @@ public class FileUploadSuccessDTO implements Serializable {
|
||||
private String fileName;
|
||||
@ApiModelProperty(name = "fileSize", value = "文件大小")
|
||||
private Long fileSize;
|
||||
@ApiModelProperty(name = "fileUrl", value = "文件路径")
|
||||
private String fileUrl;
|
||||
|
||||
public FileUploadSuccessDTO() {
|
||||
}
|
||||
@ -33,6 +35,14 @@ public class FileUploadSuccessDTO implements Serializable {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
|
||||
public FileUploadSuccessDTO(String fileId, String fileName, Long fileSize, String fileUrl) {
|
||||
this.fileId = fileId;
|
||||
this.fileName = fileName;
|
||||
this.fileSize = fileSize;
|
||||
this.fileUrl = fileUrl;
|
||||
}
|
||||
|
||||
public String getFileId() {
|
||||
return fileId == null ? "" : fileId.trim();
|
||||
}
|
||||
@ -57,6 +67,14 @@ public class FileUploadSuccessDTO implements Serializable {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
public String getFileUrl() {
|
||||
return fileUrl == null ? "" : fileUrl.trim();
|
||||
}
|
||||
|
||||
public void setFileUrl(String fileUrl) {
|
||||
this.fileUrl = fileUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("{");
|
||||
@ -66,6 +84,8 @@ public class FileUploadSuccessDTO implements Serializable {
|
||||
.append(fileName).append('\"');
|
||||
sb.append(",\"fileSize\":")
|
||||
.append(fileSize);
|
||||
sb.append(",\"fileUrl\":\"")
|
||||
.append(fileUrl).append('\"');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
package ink.wgink.module.file.pojo.vos.filedownload;
|
||||
|
||||
/**
|
||||
* @ClassName: FileDownloadVO
|
||||
* @Description: 文件下载
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/2 09:56
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class FileDownloadVO {
|
||||
|
||||
private String fileId;
|
||||
private String clientIp;
|
||||
|
||||
public FileDownloadVO() {
|
||||
}
|
||||
|
||||
public FileDownloadVO(String fileId, String clientIp) {
|
||||
this.fileId = fileId;
|
||||
this.clientIp = clientIp;
|
||||
}
|
||||
|
||||
public String getFileId() {
|
||||
return fileId == null ? "" : fileId.trim();
|
||||
}
|
||||
|
||||
public void setFileId(String fileId) {
|
||||
this.fileId = fileId;
|
||||
}
|
||||
|
||||
public String getClientIp() {
|
||||
return clientIp == null ? "" : clientIp.trim();
|
||||
}
|
||||
|
||||
public void setClientIp(String clientIp) {
|
||||
this.clientIp = clientIp;
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package ink.wgink.module.file.service.filedownload;
|
||||
|
||||
import ink.wgink.module.file.pojo.dtos.filedownload.FileDownloadDTO;
|
||||
import ink.wgink.module.file.pojo.vos.filedownload.FileDownloadVO;
|
||||
import ink.wgink.pojo.ListPage;
|
||||
import ink.wgink.pojo.result.SuccessResultList;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassName: IFileDownloadService
|
||||
* @Description: 文件下载
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/2 09:58
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public interface IFileDownloadService {
|
||||
|
||||
/**
|
||||
* 新增下载记录
|
||||
*
|
||||
* @param fileDownloadVO
|
||||
*/
|
||||
void save(FileDownloadVO fileDownloadVO);
|
||||
|
||||
/**
|
||||
* 下载列表
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
List<FileDownloadDTO> list(Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 下载列表
|
||||
*
|
||||
* @param fileId
|
||||
* @return
|
||||
*/
|
||||
List<FileDownloadDTO> listByFileId(String fileId);
|
||||
|
||||
/**
|
||||
* 下载分页列表
|
||||
*
|
||||
* @param page
|
||||
* @return
|
||||
*/
|
||||
SuccessResultList<List<FileDownloadDTO>> listPage(ListPage page);
|
||||
|
||||
/**
|
||||
* 下载分页列表
|
||||
*
|
||||
* @param fileId
|
||||
* @param page
|
||||
* @return
|
||||
*/
|
||||
SuccessResultList<List<FileDownloadDTO>> listPageByFileId(String fileId, ListPage page);
|
||||
|
||||
|
||||
/**
|
||||
* 统计下载列表
|
||||
*
|
||||
* @param fileId
|
||||
* @return
|
||||
*/
|
||||
Integer countByFileId(String fileId);
|
||||
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
package ink.wgink.module.file.service.filedownload.impl;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import ink.wgink.common.base.DefaultBaseService;
|
||||
import ink.wgink.module.file.dao.filedownload.IFileDownloadDao;
|
||||
import ink.wgink.module.file.pojo.dtos.filedownload.FileDownloadDTO;
|
||||
import ink.wgink.module.file.pojo.vos.filedownload.FileDownloadVO;
|
||||
import ink.wgink.module.file.service.filedownload.IFileDownloadService;
|
||||
import ink.wgink.pojo.ListPage;
|
||||
import ink.wgink.pojo.result.SuccessResultList;
|
||||
import ink.wgink.util.UUIDUtil;
|
||||
import ink.wgink.util.date.DateUtil;
|
||||
import ink.wgink.util.map.HashMapUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @ClassName: FileDownloadServiceImpl
|
||||
* @Description: 文件下载
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/2 09:58
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class FileDownloadServiceImpl extends DefaultBaseService implements IFileDownloadService {
|
||||
|
||||
@Autowired
|
||||
private IFileDownloadDao fileDownloadDao;
|
||||
|
||||
@Override
|
||||
public void save(FileDownloadVO fileDownloadVO) {
|
||||
Map<String, Object> params = HashMapUtil.beanToMap(fileDownloadVO);
|
||||
params.put("fileDownloadId", UUIDUtil.getUUID());
|
||||
params.put("gmtCreate", DateUtil.getTime());
|
||||
fileDownloadDao.save(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileDownloadDTO> list(Map<String, Object> params) {
|
||||
params = params == null ? getHashMap(0) : params;
|
||||
return fileDownloadDao.list(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileDownloadDTO> listByFileId(String fileId) {
|
||||
Map<String, Object> params = getHashMap(2);
|
||||
params.put("fileId", fileId);
|
||||
return list(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuccessResultList<List<FileDownloadDTO>> listPage(ListPage page) {
|
||||
PageHelper.startPage(page.getPage(), page.getRows());
|
||||
List<FileDownloadDTO> fileDownloadDTOS = list(page.getParams());
|
||||
PageInfo<FileDownloadDTO> pageInfo = new PageInfo<>(fileDownloadDTOS);
|
||||
return new SuccessResultList<>(fileDownloadDTOS, pageInfo.getPageNum(), pageInfo.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuccessResultList<List<FileDownloadDTO>> listPageByFileId(String fileId, ListPage page) {
|
||||
page.getParams().put("fileId", fileId);
|
||||
return listPage(page);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer countByFileId(String fileId) {
|
||||
Map<String, Object> params = getHashMap(2);
|
||||
params.put("fileId", fileId);
|
||||
return fileDownloadDao.count(params);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,13 +1,19 @@
|
||||
package ink.wgink.module.file.service.v2;
|
||||
|
||||
import ink.wgink.module.file.enums.UploadTypeEnum;
|
||||
import ink.wgink.module.file.pojo.dtos.FileInfoDTO;
|
||||
import ink.wgink.module.file.pojo.dtos.v2.FileUploadSuccessDTO;
|
||||
import ink.wgink.module.file.pojo.vos.v2.FileSaveVO;
|
||||
import ink.wgink.module.file.pojo.vos.v2.FileUpdateVO;
|
||||
import ink.wgink.pojo.ListPage;
|
||||
import ink.wgink.pojo.pos.FilePO;
|
||||
import ink.wgink.pojo.result.SuccessResultList;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -96,6 +102,13 @@ public interface IFileService {
|
||||
*/
|
||||
void update(FileUpdateVO fileUpdateVO);
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
*
|
||||
* @param fileIds
|
||||
*/
|
||||
void delete(List<String> fileIds);
|
||||
|
||||
/**
|
||||
* 获取文件
|
||||
*
|
||||
@ -112,4 +125,30 @@ public interface IFileService {
|
||||
*/
|
||||
FilePO getPO(String fileId);
|
||||
|
||||
/**
|
||||
* 下载
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param isOpen 是否打开
|
||||
* @param fileId 文件ID
|
||||
*/
|
||||
void download(HttpServletRequest request, HttpServletResponse response, boolean isOpen, String fileId);
|
||||
|
||||
/**
|
||||
* 文件列表
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
List<FileInfoDTO> list(Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 文件分页列表
|
||||
*
|
||||
* @param page
|
||||
* @return
|
||||
*/
|
||||
SuccessResultList<List<FileInfoDTO>> listPage(ListPage page);
|
||||
|
||||
}
|
||||
|
@ -1,24 +1,41 @@
|
||||
package ink.wgink.module.file.service.v2.impl;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import ink.wgink.common.base.DefaultBaseService;
|
||||
import ink.wgink.exceptions.FileException;
|
||||
import ink.wgink.exceptions.SearchException;
|
||||
import ink.wgink.module.file.components.FileComponent;
|
||||
import ink.wgink.module.file.dao.IFileDao;
|
||||
import ink.wgink.module.file.enums.UploadTypeEnum;
|
||||
import ink.wgink.module.file.manager.FilesManager;
|
||||
import ink.wgink.module.file.pojo.dtos.FileInfoDTO;
|
||||
import ink.wgink.module.file.pojo.dtos.v2.FileUploadSuccessDTO;
|
||||
import ink.wgink.module.file.pojo.vos.filedownload.FileDownloadVO;
|
||||
import ink.wgink.module.file.pojo.vos.v2.FileSaveVO;
|
||||
import ink.wgink.module.file.pojo.vos.v2.FileUpdateVO;
|
||||
import ink.wgink.module.file.service.filedownload.IFileDownloadService;
|
||||
import ink.wgink.module.file.service.v2.IFileService;
|
||||
import ink.wgink.pojo.ListPage;
|
||||
import ink.wgink.pojo.pos.FilePO;
|
||||
import ink.wgink.pojo.result.SuccessResultList;
|
||||
import ink.wgink.util.UUIDUtil;
|
||||
import ink.wgink.util.date.DateUtil;
|
||||
import ink.wgink.util.request.RequestUtil;
|
||||
import ink.wgink.util.thread.CachedThreadPoolUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -35,6 +52,8 @@ public class FileServiceImpl extends DefaultBaseService implements IFileService
|
||||
private FileComponent fileComponent;
|
||||
@Autowired
|
||||
private IFileDao fileDao;
|
||||
@Autowired
|
||||
private IFileDownloadService fileDownloadService;
|
||||
|
||||
@Override
|
||||
public FileUploadSuccessDTO uploadSingle(MultipartFile uploadFile, UploadTypeEnum uploadTypeEnum) {
|
||||
@ -81,12 +100,13 @@ public class FileServiceImpl extends DefaultBaseService implements IFileService
|
||||
|
||||
@Override
|
||||
public FileUploadSuccessDTO saveFile(FileSaveVO fileSaveVO) {
|
||||
String fileUrl = fileComponent.getFileUrl(fileSaveVO.getUploadPath());
|
||||
String fileId = UUIDUtil.getUUID();
|
||||
Map<String, Object> params = getHashMap(10);
|
||||
params.put("fileId", fileId);
|
||||
params.put("fileName", fileSaveVO.getFileName());
|
||||
params.put("filePath", fileSaveVO.getUploadPath());
|
||||
params.put("fileUrl", fileComponent.getFileUrl(fileSaveVO.getUploadPath()));
|
||||
params.put("fileUrl", fileUrl);
|
||||
params.put("fileType", fileSaveVO.getFileType());
|
||||
params.put("fileSize", fileSaveVO.getFileSize());
|
||||
params.put("isBack", 0);
|
||||
@ -99,7 +119,7 @@ public class FileServiceImpl extends DefaultBaseService implements IFileService
|
||||
params.put("isDelete", 0);
|
||||
fileDao.save(params);
|
||||
|
||||
return new FileUploadSuccessDTO(fileId, fileSaveVO.getFileName(), fileSaveVO.getFileSize());
|
||||
return new FileUploadSuccessDTO(fileId, fileSaveVO.getFileName(), fileSaveVO.getFileSize(), fileUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -116,6 +136,26 @@ public class FileServiceImpl extends DefaultBaseService implements IFileService
|
||||
fileDao.update(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(List<String> fileIds) {
|
||||
if (fileIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> params = getHashMap(2);
|
||||
params.put("fileIds", fileIds);
|
||||
List<FilePO> filePOS = fileDao.listPO(params);
|
||||
// 删除源文件
|
||||
filePOS.forEach(filePO -> {
|
||||
File file = new File(filePO.getFilePath());
|
||||
if (!file.exists()) {
|
||||
return;
|
||||
}
|
||||
file.delete();
|
||||
});
|
||||
// 删除记录
|
||||
fileDao.delete(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilePO getPO(Map<String, Object> params) {
|
||||
return fileDao.getPO(params);
|
||||
@ -128,6 +168,87 @@ public class FileServiceImpl extends DefaultBaseService implements IFileService
|
||||
return getPO(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(HttpServletRequest request, HttpServletResponse response, boolean isOpen, String fileId) {
|
||||
FilePO filePO = getPO(fileId);
|
||||
if (filePO == null) {
|
||||
throw new FileException("查询失败");
|
||||
}
|
||||
File file = new File(filePO.getFilePath());
|
||||
if (!file.exists()) {
|
||||
throw new FileException("文件不存在");
|
||||
}
|
||||
try {
|
||||
String requestIp = RequestUtil.getRequestIp(request);
|
||||
String code = FilesManager.getInstance().generateCode(fileId, filePO.getFileName());
|
||||
response.sendRedirect(String.format("%s/%s?file=%s&code=%s&open=%d", request.getContextPath(), filePO.getFileUrl(), fileId, code, isOpen ? 1 : 0));
|
||||
if (!isOpen && !StringUtils.isBlank(requestIp)) {
|
||||
// 记录下载历史
|
||||
CachedThreadPoolUtil.execute(() -> {
|
||||
FileDownloadVO fileDownloadVO = new FileDownloadVO(filePO.getFileId(), requestIp);
|
||||
fileDownloadService.save(fileDownloadVO);
|
||||
});
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfoDTO> list(Map<String, Object> params) {
|
||||
params = params == null ? getHashMap(0) : params;
|
||||
setQueryFileType(params);
|
||||
List<FileInfoDTO> fileInfoDTOs = fileDao.listInfo(params);
|
||||
setDownloadCount(fileInfoDTOs);
|
||||
return fileInfoDTOs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuccessResultList<List<FileInfoDTO>> listPage(ListPage page) {
|
||||
PageHelper.startPage(page.getPage(), page.getRows());
|
||||
List<FileInfoDTO> fileInfoDTOs = list(page.getParams());
|
||||
setDownloadCount(fileInfoDTOs);
|
||||
PageInfo<FileInfoDTO> pageInfo = new PageInfo<>(fileInfoDTOs);
|
||||
return new SuccessResultList<>(fileInfoDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置查询文件类型
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
private void setQueryFileType(Map<String, Object> params) {
|
||||
String fileType = (String) params.get("fileType");
|
||||
if (StringUtils.isBlank(fileType)) {
|
||||
return;
|
||||
}
|
||||
List<String> fileTypes;
|
||||
if (StringUtils.equals("image", fileType)) {
|
||||
fileTypes = Arrays.asList(fileComponent.getImageTypes());
|
||||
} else if (StringUtils.equals("video", fileType)) {
|
||||
fileTypes = Arrays.asList(fileComponent.getVideoTypes());
|
||||
} else if (StringUtils.equals("audio", fileType)) {
|
||||
fileTypes = Arrays.asList(fileComponent.getAudioTypes());
|
||||
} else if (StringUtils.equals("file", fileType)) {
|
||||
fileTypes = Arrays.asList(fileComponent.getFileTypes());
|
||||
} else {
|
||||
fileTypes = new ArrayList<>();
|
||||
}
|
||||
params.put("fileTypes", fileTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置下载次数
|
||||
*
|
||||
* @param fileInfoDTOs
|
||||
*/
|
||||
private void setDownloadCount(List<FileInfoDTO> fileInfoDTOs) {
|
||||
fileInfoDTOs.forEach(fileInfoDTO -> {
|
||||
Integer downloadCount = fileDownloadService.countByFileId(fileInfoDTO.getFileId());
|
||||
fileInfoDTO.setDownloadCount(downloadCount);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件保存VO
|
||||
*
|
||||
|
@ -0,0 +1,33 @@
|
||||
package ink.wgink.module.file.startup;
|
||||
|
||||
import ink.wgink.interfaces.manager.IFilesShowCodeService;
|
||||
import ink.wgink.module.file.manager.FilesManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @ClassName: FileStartUp
|
||||
* @Description: 文件启动类
|
||||
* @Author: wanggeng
|
||||
* @Date: 2022/8/1 16:17
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Component
|
||||
public class FilesStartUp implements ApplicationRunner {
|
||||
|
||||
@Autowired
|
||||
private IFilesShowCodeService filesShowCodeService;
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
FilesManager.getInstance().setFilesShowCodeService(filesShowCodeService);
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 0/1 * * * ?")
|
||||
public void clearTimeoutShowCode() {
|
||||
FilesManager.getInstance().clearTimeoutShowCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
<?xml version="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="ink.wgink.module.file.dao.filedownload.IFileDownloadDao">
|
||||
|
||||
<resultMap id="fileDownloadDTO" type="ink.wgink.module.file.pojo.dtos.filedownload.FileDownloadDTO">
|
||||
<id property="fileDownloadId" column="file_download_id"/>
|
||||
<result property="fileId" column="file_id"/>
|
||||
<result property="clientIp" column="client_ip"/>
|
||||
<result property="gmtCreate" column="gmt_create"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 建表 -->
|
||||
<update id="createTable">
|
||||
CREATE TABLE IF NOT EXISTS `sys_file_download` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`file_download_id` char(36) DEFAULT NULL COMMENT '主键',
|
||||
`file_id` char(36) DEFAULT NULL COMMENT '文件ID',
|
||||
`client_ip` varchar(20) DEFAULT NULL COMMENT '客户端IP',
|
||||
`gmt_create` datetime DEFAULT NULL COMMENT '下载时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `file_download_id` (`file_download_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
</update>
|
||||
|
||||
<!-- 保存文件 -->
|
||||
<insert id="save" parameterType="map">
|
||||
INSERT INTO sys_file_download (
|
||||
file_download_id,
|
||||
file_id,
|
||||
client_ip,
|
||||
gmt_create
|
||||
) VALUES(
|
||||
#{fileDownloadId},
|
||||
#{fileId},
|
||||
#{clientIp},
|
||||
#{gmtCreate}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- 文件列表 -->
|
||||
<select id="list" parameterType="map" resultMap="fileDownloadDTO">
|
||||
SELECT
|
||||
file_download_id,
|
||||
file_id,
|
||||
client_ip,
|
||||
gmt_create
|
||||
FROM
|
||||
sys_file_download
|
||||
WHERE
|
||||
file_id = #{fileId}
|
||||
</select>
|
||||
|
||||
<!-- 统计 -->
|
||||
<select id="count" parameterType="map" resultType="java.lang.Integer">
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM
|
||||
sys_file_download
|
||||
WHERE
|
||||
file_id = #{fileId}
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
@ -283,6 +283,13 @@
|
||||
#{fileIds[${index}]}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="fileTypes != null and fileTypes.size > 0">
|
||||
AND
|
||||
file_type IN
|
||||
<foreach collection="fileTypes" index="index" open="(" separator="," close=")">
|
||||
#{fileTypes[${index}]}
|
||||
</foreach>
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<!-- 文件列表 -->
|
||||
|
121
module-file/src/main/resources/templates/file-download/list.html
Normal file
121
module-file/src/main/resources/templates/file-download/list.html
Normal file
@ -0,0 +1,121 @@
|
||||
<!doctype html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<base th:href="${#request.getContextPath() + '/'} ">
|
||||
<meta charset="utf-8">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
|
||||
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
|
||||
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
|
||||
<link rel="stylesheet" type="text/css" href="assets/js/vendor/viewer/viewer.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-anim layui-anim-fadein">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body" id="cardBody">
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/layuiadmin/layui/layui.js"></script>
|
||||
<script type="text/javascript">
|
||||
layui.config({
|
||||
base: 'assets/layuiadmin/'
|
||||
}).extend({
|
||||
index: 'lib/index'
|
||||
}).use(['index', 'table', 'laydate', 'common'], function() {
|
||||
var $ = layui.$;
|
||||
var $win = $(window);
|
||||
var table = layui.table;
|
||||
var admin = layui.admin;
|
||||
var laydate = layui.laydate;
|
||||
var common = layui.common;
|
||||
var resizeTimeout = null;
|
||||
var fileId = top.restAjax.params(window.location.href).fileId;
|
||||
var tableUrl = 'api/file-download/listpage/file-id/{fileId}';
|
||||
|
||||
// 初始化表格
|
||||
function initTable() {
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
id: 'dataTable',
|
||||
url: top.restAjax.path(tableUrl, [fileId]),
|
||||
width: admin.screen() > 1 ? '100%' : '',
|
||||
height: $win.height() - 20,
|
||||
limit: 20,
|
||||
limits: [20, 40, 60, 80, 100, 200],
|
||||
request: {
|
||||
pageName: 'page',
|
||||
limitName: 'rows'
|
||||
},
|
||||
cols: [
|
||||
[
|
||||
{field: 'rowNum', width: 80, title: '序号', fixed: 'left', align: 'center', templet: '<span>{{d.LAY_INDEX}}</span>'},
|
||||
{field: 'clientIp', width: 200, title: '客户端地址', align: 'center',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '-';
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
},
|
||||
{field: 'gmtCreate', width: 180, title: '下载时间', align: 'center',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '-';
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
},
|
||||
]
|
||||
],
|
||||
page: true,
|
||||
parseData: function (data) {
|
||||
return {
|
||||
'code': 0,
|
||||
'msg': '',
|
||||
'count': data.total,
|
||||
'data': data.rows
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 重载表格
|
||||
function reloadTable(currentPage) {
|
||||
table.reload('dataTable', {
|
||||
url: top.restAjax.path(tableUrl, []),
|
||||
where: {
|
||||
keywords: $('#keywords').val(),
|
||||
startTime: $('#startTime').val(),
|
||||
endTime: $('#endTime').val()
|
||||
},
|
||||
page: {
|
||||
curr: currentPage
|
||||
},
|
||||
height: $win.height() - 90,
|
||||
});
|
||||
}
|
||||
|
||||
initTable();
|
||||
|
||||
// 事件 - 页面变化
|
||||
$win.on('resize', function () {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(function () {
|
||||
reloadTable();
|
||||
}, 500);
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
290
module-file/src/main/resources/templates/file/v2/list.html
Normal file
290
module-file/src/main/resources/templates/file/v2/list.html
Normal file
@ -0,0 +1,290 @@
|
||||
<!doctype html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<base th:href="${#request.getContextPath() + '/'} ">
|
||||
<meta charset="utf-8">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
|
||||
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
|
||||
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
|
||||
<link rel="stylesheet" type="text/css" href="assets/js/vendor/viewer/viewer.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-fluid layui-anim layui-anim-fadein">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body" id="cardBody">
|
||||
<div class="test-table-reload-btn" style="margin-bottom: 10px;">
|
||||
<div class="layui-inline">
|
||||
<input type="text" id="keywords" class="layui-input search-item" placeholder="输入文件名">
|
||||
</div>
|
||||
<div class="layui-inline layui-form search-item">
|
||||
<select id="fileType" name="fileType">
|
||||
<option value="">选择类型</option>
|
||||
<option value="image">图片</option>
|
||||
<option value="video">视频</option>
|
||||
<option value="audio">音频</option>
|
||||
<option value="file">文件</option>
|
||||
</select>
|
||||
</div>
|
||||
<button type="button" id="search" class="layui-btn layui-btn-sm">
|
||||
<i class="fa fa-lg fa-search"></i> 搜索
|
||||
</button>
|
||||
</div>
|
||||
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
|
||||
<!-- 表头按钮组 -->
|
||||
<script type="text/html" id="headerToolBar">
|
||||
<div class="layui-btn-group">
|
||||
<button type="button" class="layui-btn layui-btn-danger layui-btn-sm" lay-event="removeEvent">
|
||||
<i class="fa fa-lg fa-trash"></i> 删除
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="assets/layuiadmin/layui/layui.js"></script>
|
||||
<script type="text/javascript">
|
||||
layui.config({
|
||||
base: 'assets/layuiadmin/'
|
||||
}).extend({
|
||||
index: 'lib/index'
|
||||
}).use(['index', 'table', 'laydate', 'common'], function() {
|
||||
var $ = layui.$;
|
||||
var $win = $(window);
|
||||
var table = layui.table;
|
||||
var admin = layui.admin;
|
||||
var laydate = layui.laydate;
|
||||
var common = layui.common;
|
||||
var resizeTimeout = null;
|
||||
var tableUrl = 'api/file/v2/listpage';
|
||||
var previewTypeArray = [
|
||||
'png','jpg','jpeg','gif','blob',
|
||||
'mp4',
|
||||
'mp3', 'wav',
|
||||
'pdf'
|
||||
]
|
||||
|
||||
/**
|
||||
* 是否是预览类型
|
||||
* @param fileType
|
||||
* @return {boolean}
|
||||
*/
|
||||
function isPreviewType(fileType) {
|
||||
for(var i = 0, item; item = previewTypeArray[i++];) {
|
||||
if(fileType.toLowerCase() == item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 初始化表格
|
||||
function initTable() {
|
||||
table.render({
|
||||
elem: '#dataTable',
|
||||
id: 'dataTable',
|
||||
url: top.restAjax.path(tableUrl, []),
|
||||
width: admin.screen() > 1 ? '100%' : '',
|
||||
height: $win.height() - 90,
|
||||
limit: 20,
|
||||
limits: [20, 40, 60, 80, 100, 200],
|
||||
toolbar: '#headerToolBar',
|
||||
request: {
|
||||
pageName: 'page',
|
||||
limitName: 'rows'
|
||||
},
|
||||
cols: [
|
||||
[
|
||||
{type: 'checkbox', fixed: 'left'},
|
||||
{field: 'rowNum', width: 80, title: '序号', fixed: 'left', align: 'center', templet: '<span>{{d.LAY_INDEX}}</span>'},
|
||||
{field: 'fileId', width: 300, title: '主键', align: 'center',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '-';
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
},
|
||||
{field: 'fileName', width: 200, title: '文件名称', align: 'center',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '-';
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
},
|
||||
{field: 'filePath', width: 300, title: '存放位置', align: 'center',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '-';
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
},
|
||||
{field: 'fileUrl', width: 300, title: '访问地址', align: 'center',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '-';
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
},
|
||||
{field: 'fileType', width: 100, title: '文件类型', align: 'center',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '-';
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
},
|
||||
{field: 'fileSize', width: 120, title: '文件大小', align: 'center',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '-';
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
},
|
||||
{field: 'fileSummary', width: 200, title: '文件描述', align: 'center',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '-';
|
||||
}
|
||||
return rowData;
|
||||
}
|
||||
},
|
||||
{field: 'preview', width: 90, title: '预览', align: 'center', fixed: 'right',
|
||||
templet: function (row) {
|
||||
if(isPreviewType(row.fileType)) {
|
||||
return '<a href="route/file/v2/download/true/'+ row.fileId +'" target="_blank" title="点击预览" class="layui-btn layui-btn-xs" ><i class="fa fa-eye" aria-hidden="true"></i> 预览</a>'
|
||||
}
|
||||
return '-'
|
||||
}
|
||||
},
|
||||
{field: 'download', width: 90, title: '下载', align: 'center', fixed: 'right',
|
||||
templet: function (row) {
|
||||
return '<a href="route/file/v2/download/false/'+ row.fileId +'" target="_blank" title="点击下载" class="layui-btn layui-btn-xs layui-btn-normal" ><i class="fa fa-cloud-download" aria-hidden="true"></i> 下载</a>'
|
||||
}
|
||||
},
|
||||
{field: 'downloadCount', width: 100, title: '下载次数', align: 'center', fixed: 'right',
|
||||
templet: function (row) {
|
||||
var rowData = row[this.field];
|
||||
if (typeof (rowData) === 'undefined' || rowData == null || rowData == '') {
|
||||
return '0';
|
||||
}
|
||||
if(rowData == 0) {
|
||||
return rowData;
|
||||
}
|
||||
return '<button class="layui-btn layui-btn-xs layui-btn-danger" lay-event="showDownloadFilter">'+ rowData +'次</button>';
|
||||
}
|
||||
},
|
||||
]
|
||||
],
|
||||
page: true,
|
||||
parseData: function (data) {
|
||||
return {
|
||||
'code': 0,
|
||||
'msg': '',
|
||||
'count': data.total,
|
||||
'data': data.rows
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 重载表格
|
||||
function reloadTable(currentPage) {
|
||||
table.reload('dataTable', {
|
||||
url: top.restAjax.path(tableUrl, []),
|
||||
where: {
|
||||
keywords: $('#keywords').val(),
|
||||
fileType: $('#fileType').val()
|
||||
},
|
||||
page: {
|
||||
curr: currentPage
|
||||
},
|
||||
height: $win.height() - 90,
|
||||
});
|
||||
}
|
||||
|
||||
function deleteData(ids) {
|
||||
top.dialog.confirm('删除记录与源文件', function() {
|
||||
var layIndex;
|
||||
top.restAjax.delete(top.restAjax.path('api/file/v2/delete/{ids}', [ids]), {}, null, function (code, data) {
|
||||
top.dialog.msg('删除成功', {time: 1000});
|
||||
reloadTable();
|
||||
}, function (code, data) {
|
||||
top.dialog.msg(data.msg);
|
||||
}, function () {
|
||||
layIndex = top.dialog.msg(top.dataMessage.deleting, {icon: 16, time: 0, shade: 0.3});
|
||||
}, function () {
|
||||
top.dialog.close(layIndex);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
initTable();
|
||||
|
||||
// 事件 - 页面变化
|
||||
$win.on('resize', function () {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(function () {
|
||||
reloadTable();
|
||||
}, 500);
|
||||
});
|
||||
// 事件 - 搜索
|
||||
$(document).on('click', '#search', function () {
|
||||
reloadTable(1);
|
||||
});
|
||||
|
||||
// 事件 - 增删改
|
||||
table.on('toolbar(dataTable)', function (obj) {
|
||||
var layEvent = obj.event;
|
||||
var checkStatus = table.checkStatus('dataTable');
|
||||
var checkDatas = checkStatus.data;
|
||||
if (layEvent === 'removeEvent') {
|
||||
if (checkDatas.length === 0) {
|
||||
top.dialog.msg(top.dataMessage.table.selectDelete);
|
||||
} else {
|
||||
var ids = '';
|
||||
for (var i = 0, item; item = checkDatas[i++];) {
|
||||
if (i > 1) {
|
||||
ids += '_';
|
||||
}
|
||||
ids += item['fileId'];
|
||||
}
|
||||
deleteData(ids);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
table.on('tool(dataTable)', function(obj) {
|
||||
var data = obj.data;
|
||||
var event = obj.event;
|
||||
if(event === 'showDownloadFilter') {
|
||||
top.dialog.open({
|
||||
title: '下载记录',
|
||||
url: top.restAjax.path('route/file-download/list?fileId={fileId}', [data.fileId]),
|
||||
width: '500px',
|
||||
height: '500px',
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user