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要保持一致

posted @ 2025-05-28 17:05  云翊宸  阅读(2138)  评论(0)    收藏  举报