docker搭建kkfileview过程记录
1、构建kkfileview4.4.0的docker镜像,可参考这个地址:https://blog.csdn.net/qq_15612715/article/details/146205228 的方式去制作镜像
参考上面的教程构建kkfileview-base的基础镜像,然后使用maven打包kkfileview的server项目,将kkFileView-4.4.0.tar.gz文件放图中Dockerfile相同层级目录下,通过docker build构建出kkfileview-4.4.0的docker镜像,并使用docker save 的命令打成tar包便于传输

2、将kkfileview的tar包上传到指定的服务器上,使用docker load命令解压缩到成image,首先运行临时容器将其中的配置文件复制到宿主机的目录下,然后通过挂载的方式启动启动kkfileview的docker容器,相关命令如下

#运行临时容器
docker run -d -p 8012:8012 --name=kkfileview kkfileview:4.4.0
#复制配置文件到宿主机
docker cp kkfileview:/opt/kkFileView-4.4.0/config/application.properties ./config
#挂载方式运行docker容器
docker run -d --name=kkfileview --network=host --restart always -v /root/apps/kkfileview/config/application.properties:/opt/kkFileView-4.4.0/config/application.properties kkfileview:4.4.0
3、nginx配置访问路径,这一部一定要参考官方文档这里

1)笔者负责系统用的是nginx两层代理,就是第一层nginx如下图1的配置,第二层nginx用下图2的配置,其中图2的服务器为kkfileview部署的服务器


2)按照文档所说修改挂载的application.properties的文件配置


4、生成预览链接的代码如下
package com.scdq.env.water.ecological.controller; import com.scdq.env.common.vo.Result; import com.scdq.env.water.ecological.service.KkFileViewService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("/kkfileview") @Api(tags = "kkfileview预览接口") public class KkFileViewController { @Resource private KkFileViewService kkFileViewService; @GetMapping("/fileDownload") @ApiOperation("附件下载接口") public void fileDownload(@RequestParam("attachmentId") String attachmentId, @RequestParam("token") String token) { kkFileViewService.fileDownload(attachmentId, token); } @GetMapping("/getPreviewUrl") @ApiOperation("获取预览地址接口") public Result<String> getPreviewUrl(@RequestParam("attachmentId") String attachmentId) { return Result.success(kkFileViewService.getPreviewUrl(attachmentId)); } }
package com.scdq.env.water.ecological.service.impl; import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Tuple; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.scdq.env.common.exception.BaseException; import com.scdq.env.common.jwt.JwtUtils; import com.scdq.env.common.log.domain.TokenConstants; import com.scdq.env.water.ecological.service.DAttachmentService; import com.scdq.env.water.ecological.service.KkFileViewService; import com.scdq.env.water.ecological.utils.AuthUtil; import com.scdq.env.water.entity.DAttachmentDO; import com.scdq.env.water.mapper.DAttachmentMapper; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Objects; import static com.scdq.env.common.exception.SystemErrorType.*; import static com.scdq.env.water.ecological.utils.ExceptionUtils.buildBaseException; /** * <p> * 公共服务实现类 * </p> * * @author zhangl * @since 2023-09-18 */ @Service @Slf4j public class KkFileViewServiceImpl implements KkFileViewService { @Resource private DAttachmentService attachmentService; @Resource private DAttachmentMapper attachmentMapper; /** * kkfileview预览接口url前缀, http://xxxx:xxxx/preview/onlinePreview?(公网ip+port) */ @Value("${onlinePreviewUrlPrefix}") private String onlinePreviewUrlPrefix; /** * 附件数据下载接口url前缀, http://xxxx:xxxx/jxhb/water-ecological/kkfileview/fileDownload?(公网ip+port) */ @Value("${downloadAttachmentUrlPrefix}") private String downloadAttachmentUrlPrefix; /** * 文件数据下载接口url模板 */ private static final String DOWNLOAD_URL_TEMPLATE = "attachmentId={}&token={}&fullfilename={}"; /** * 预览链接url模板 */ private static final String PREVIEW_URL_TEMPLATE = "url={}&watermarkTxt={}"; /** * 文件下载 * * @param attachmentId 文件id * @param token token */ @Override public void fileDownload(String attachmentId, String token) { //token校验 validateToken(token); //下载附件流 downloadAttachmentStream(attachmentId); } /** * 获取预览地址 * * @param attachmentId * @return */ @Override public String getPreviewUrl(String attachmentId) { ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); if (ObjectUtil.isNull(sra)) { return null; } //token校验 HttpServletRequest request = sra.getRequest(); String token = request.getHeader(TokenConstants.AUTHENTICATION); Assert.isTrue(ObjectUtil.isNotNull(request) && StrUtil.isNotBlank(token), buildBaseException(ARGUMENT_NOT_VALID, "未获取到有效token"));
//获取用户名,内部是通过请求header中的AUTHENTICATION的值用JwtUtil去获取用户名 String userName = AuthUtil.selectUserName(); //获取附件信息 DAttachmentDO attachment = attachmentMapper.selectById(attachmentId); Assert.notNull(attachment, buildBaseException(ARGUMENT_NOT_VALID, "附件不存在")); try { //创建附件下载url String downloadUrl = createDownloadUrl(attachmentId, token, attachment); log.info("文件下载地址:{}", downloadUrl); //创建在线预览url String onlinePreviewUrl = createOnlinePreviewUrl(downloadUrl, userName); log.info("预览地址:{}", onlinePreviewUrl); return onlinePreviewUrl; } catch (Exception e) { log.error("预览地址获取失败:", e); throw new BaseException(SYSTEM_ERROR, "预览地址获取失败"); } } public static String base64UrlEncode(String url) { String base64Url = Base64.getEncoder().encodeToString(url.getBytes(StandardCharsets.UTF_8)); return URLEncoder.encode(base64Url, StandardCharsets.UTF_8); } //鉴权 private static void validateToken(String token) { try { JwtUtils.getUserName(token); } catch (Exception e) { log.error("鉴权失败:" + e.getMessage()); throw new BaseException(ARGUMENT_NOT_VALID, "用户信息不存在"); } } private void downloadAttachmentStream(String attachmentId) { try { //获取response响应流 HttpServletResponse response = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse(); Assert.notNull(response, buildBaseException(REQUEST_ERROR)); //获取附件信息及附件输入流 Tuple tuple = attachmentService.getAttachment(attachmentId); //获取附件输入流 InputStream inputStream = tuple.get(0); //获取到附件信息对象 DAttachmentDO attachmentDO = tuple.get(1); // 设置响应头信息,告诉前端浏览器下载文件 if (response != null) { response.setContentType("application/octet-stream;charset=UTF-8"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(attachmentDO.getFileOriginalName(), StandardCharsets.UTF_8)); // 获取输出流进行写入数据 OutputStream outputStream = response.getOutputStream(); // 将输入流复制到输出流 byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } // 关闭流资源 inputStream.close(); outputStream.close(); } } catch (Exception e) { log.error("文件下载失败:" + e.getMessage()); throw new BaseException(SYSTEM_ERROR, "文件下载失败"); } } @NotNull private String createOnlinePreviewUrl(String downloadUrl, String userName) { String previewTemplate = StrUtil.format(PREVIEW_URL_TEMPLATE, base64UrlEncode(downloadUrl), URLEncoder.encode(userName, StandardCharsets.UTF_8)); return onlinePreviewUrlPrefix + previewTemplate; } @NotNull private String createDownloadUrl(String attachmentId, String token, DAttachmentDO attachment) { String downloadTemplate = StrUtil.format(DOWNLOAD_URL_TEMPLATE, attachmentId, token, URLEncoder.encode(attachment.getFileOriginalName(), StandardCharsets.UTF_8)); return downloadAttachmentUrlPrefix + downloadTemplate; } }

注意事项:
1、第三步nginx的配置一定要配对,否则预览会有问题,
2、下载文件的downloadAttachmentUrl要用公网的地址,否则图片会无法预览
3、nginx的第一层匹配路径和kkfileview的application.properties中的base_url要保持一致
浙公网安备 33010602011771号