完善文件V2功能,修改文件下载方式为重定向下载,增加查看码校验,增加文件下载次数统计

This commit is contained in:
wanggeng 2022-08-02 17:57:48 +08:00
parent 5c8ed3e294
commit 56b317684d
23 changed files with 1474 additions and 8 deletions

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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
*

View File

@ -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();
}
}

View File

@ -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>

View File

@ -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>
<!-- 文件列表 -->

View 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>

View 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>