Vue使用vue-pdf实现pdf在线浏览 elementui 后台springboot

后台代码

这个文件是放在ftp服务器上,需要远程下载

    @GetMapping("/getBase64/{id}")
    @ApiOperation("获取文件base64")
    public ModelMap getBase64(HttpServletResponse response, @PathVariable String id){
        System.out.println(id);
        ModelMap modelMap = new ModelMap();
        try {
            BidOpenNegotiatingAnswer bidOpenNegotiatingAnswer = bidOpenNegotiatingAnswerService.queryById(id);
            BibenetFTPClient client = ftpClient();
            client.downloadToFile(response.getOutputStream(),bidOpenNegotiatingAnswer.getOfferFilePath());
//            byte[] byteArray = client.downloadToByteArray(bidOpenNegotiatingAnswer.getOfferFilePath());
//            String data1 = Base64Utils.encodeToString(byteArray);
//            modelMap.put("base64",data1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return modelMap;
    }

FTPClient.java 

package com.bitbid.middleware.components.ftp;

import com.bitbid.middleware.components.exception.BitbidException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

public class BibenetFTPClient {

	private static Logger logger = LoggerFactory.getLogger(BibenetFTPClient.class);

	private FTPClientPool pool;

	public FTPClientPool getPool() {
		return pool;
	}

	public void setPool(FTPClientPool pool) {
		this.pool = pool;
	}

	// FIXME 暂时
	public String getStringFtpPath(String fileFtpPath) {
		char _colon = ':';

		StringBuilder sb = new StringBuilder();
		sb.append("ftp://").append(pool.getUsername()).append(_colon)
				.append(pool.getPassword()).append("@").append(pool.getHost())
				.append(_colon).append(pool.getPort());

		if (fileFtpPath.startsWith("/")) {
			sb.append(fileFtpPath);
		} else {
			sb.append("/").append(fileFtpPath);
		}
		return sb.toString();
	}

	public String upload(File srcFile) {

		String fileName = srcFile.getName();
		String fileExtName = StringUtils.substringAfterLast(fileName, ".");
		FileInputStream fis = null;

		try {

			fis = new FileInputStream(srcFile);
			return upload(fis, fileExtName);

		} catch (FileNotFoundException e) {
			throw new BitbidException(
					"upload file to ftp failed. local file does not exists. file path is : "
							+ srcFile.getAbsolutePath());
		} catch (Exception e) {
			logger.error("upload file to ftp failed.", e);
			throw new BitbidException(e);
		} finally {
			IOUtils.closeQuietly(fis);
		}

	}

	public String upload(InputStream fis, String fileExtName) {

		FTPClient client = null;

		try {

			client = (FTPClient) pool.borrowClient();
			FileFtpPath fileFtpPath = FileFtpPath.generateOne(fileExtName);

			// 先切换到根目录
			client.changeWorkingDirectory("/");
			chg2SubDirIfNotExistsCreateIt(client, fileFtpPath.getFirstLevelFolder());
			chg2SubDirIfNotExistsCreateIt(client, fileFtpPath.getSecondLevelFolder());
			chg2SubDirIfNotExistsCreateIt(client, fileFtpPath.getThirdLevelFolder());
			// FIXME 能否替换成直接判断所有路径?
			boolean storeFile = client.storeFile(fileFtpPath.getRandomFileName(), fis);
			if(!storeFile){
				logger.error("upload file to ftp failed.");
				throw new BitbidException("upload file to ftp failed.");
			}
			return fileFtpPath.getAbsoluteFtpFilePath();
		} catch (Exception e) {
			logger.error("upload file to ftp failed.", e);
			throw new BitbidException(e);
		} finally {
			returnFTPClientQuietly(client);
		}
	}

	private void returnFTPClientQuietly(FTPClient client) {
		try {
			if (null != client) {
				pool.returnClient(client);
			}
		} catch (Exception e) {
			logger.info("return ftpclient to pool failed, ignore it.", e);
		}
	}

	public byte[] downloadToByteArray(String ftpFilePath) {

		if (logger.isDebugEnabled()) {
			logger.debug("begin downloadToByteArray file with ftpFilePath : "
					+ ftpFilePath);
		}

		String ftpFileDir = StringUtils.substringBeforeLast(ftpFilePath, "/");
		String ftpFileName = StringUtils.substringAfterLast(ftpFilePath, "/");

		if (!ftpFileDir.startsWith("/")) {
			ftpFileDir = "/" + ftpFileDir;
		}

		FTPClient client = null;

		ByteArrayOutputStream baos = new ByteArrayOutputStream();

		try {
			client = (FTPClient) pool.borrowClient();
			client.changeWorkingDirectory(ftpFileDir);

			client.retrieveFile(ftpFileName, baos);

			if (logger.isDebugEnabled()) {
				logger.debug("End downloadToByteArray file with ftpFilePath : "
						+ ftpFilePath);
			}

			return baos.toByteArray();

		} catch (Exception e) {
			logger.error("download file from ftp failed, file path is : "
					+ ftpFilePath, e);
			throw new BitbidException(e);
		} finally {
			IOUtils.closeQuietly(baos);
			returnFTPClientQuietly(client);
		}

	}

	private void chg2SubDirIfNotExistsCreateIt(FTPClient client,
			String directory) throws IOException {
		client.changeWorkingDirectory(directory);
		if (client.getReplyCode() == 550) {
			client.makeDirectory(directory);
			client.changeWorkingDirectory(directory);
		}
	}
	/**
	 * @author wangcong created it at 16:12 in 2019-1-9
	 * 直接下载,如果使用ByteArrayOutputStream,文件过大的情况下,Arrays.copyOf()会出现Java heap space问题
	 */
	public void downloadToFile(OutputStream os, String ftpFilePath) {
		if (logger.isDebugEnabled()) {
			logger.debug("begin downloadToByteArray file with ftpFilePath : "
					+ ftpFilePath);
		}
		String ftpFileDir = StringUtils.substringBeforeLast(ftpFilePath, "/");
		String ftpFileName = StringUtils.substringAfterLast(ftpFilePath, "/");
		if (!ftpFileDir.startsWith("/")) {
			ftpFileDir = "/" + ftpFileDir;
		}
		FTPClient client = null;
		try {
			client = (FTPClient) pool.borrowClient();
			client.changeWorkingDirectory(ftpFileDir);

			client.retrieveFile(ftpFileName, os);

			if (logger.isDebugEnabled()) {
				logger.debug("End downloadToByteArray file with ftpFilePath : "
						+ ftpFilePath);
			}
			os.flush();
		} catch (Exception e) {
			logger.error("download file from ftp failed, file path is : "
					+ ftpFilePath, e);
			throw new BitbidException(e);
		} finally {
			IOUtils.closeQuietly(os);
			returnFTPClientQuietly(client);
		}
	}
}
FTPClientPool
package com.bitbid.middleware.components.ftp;

import com.bitbid.middleware.components.exception.BitbidException;
import org.apache.commons.net.SocketClient;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPReply;

import java.io.IOException;

/**
 * FTP Client 连接池
 */
public class FTPClientPool extends SocketClientPoolSupport {

    public static final int DEFAULT_DATA_TIMEOUT = 120000; // two minutes
    public static final String DEFAULT_CONTROL_ENCODING = FTP.DEFAULT_CONTROL_ENCODING;

    private String username;
    private String password;
    private boolean binaryMode = true;
    private boolean passiveMode;
    private FTPClientConfig config;
    private String controlEncoding = DEFAULT_CONTROL_ENCODING;
    private int dataTimeout = DEFAULT_DATA_TIMEOUT;

    public FTPClientPool(){

    }

    public FTPClientPool(String host, String port, String username, String password) {
        super.setHost(host);
        super.setPort(Integer.valueOf(port));
        this.username = username;
        this.password = password;
    }

    @Override
	public boolean validateObject(Object object) {
        FTPClient client = (FTPClient) object;
        try {
            return client.sendNoOp();
        } catch (IOException e) {
            throw new RuntimeException("Failed to validate client: " + e, e);
        }
    }

    @Override
	public void activateObject(Object object) throws Exception {
        FTPClient client = (FTPClient) object;
//        client.setReaderThread(true);
    }

    @Override
	public void passivateObject(Object object) throws Exception {
        FTPClient client = (FTPClient) object;
//        client.setReaderThread(false);
    }

    public String getUsername() {
        return username;
    }

    /**
     * 用户名
     *
     * @param username
     */
    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    /**
     * 密码
     *
     * @param password to set.
     */
    public void setPassword(String password) {
        this.password = password;
    }

    public boolean isBinaryMode() {
        return binaryMode;
    }

     /**
     * 二进制传输模式
     *
     * @param binaryMode 默认为true
     */
    public void setBinaryMode(boolean binaryMode) {
        this.binaryMode = binaryMode;
    }

    /**
     * @return the passiveMode
     */
    public boolean isPassiveMode() {
        return passiveMode;
    }

    /**
     * 被动模式,默认false
     *
     * @param passiveMode
     */
    public void setPassiveMode(boolean passiveMode) {
        this.passiveMode = passiveMode;
    }

    public FTPClientConfig getConfig() {
        return config;
    }


    public void setConfig(FTPClientConfig config) {
        this.config = config;
    }

    /**
     * @return the controlEncoding
     */
    public String getControlEncoding() {
        return controlEncoding;
    }

    /**
     * FTP控制连接的编码格式.  默认为 <code>ISO-8859-1</code>
     *
     * @param controlEncoding
     */
    public void setControlEncoding(String controlEncoding) {
        this.controlEncoding = controlEncoding;
    }

    /**
     * @return the dataTimeout
     */
    public int getDataTimeout() {
        return dataTimeout;
    }


    /**
     * 指定超时时间.  默认为 <code>120000</code>
     *
     * @param dataTimeout after which the connection should be closed.
     * .
     */
    public void setDataTimeout(int dataTimeout) {
        this.dataTimeout = dataTimeout;
    }

    @Override
	protected void connect(SocketClient client) throws Exception {
        FTPClient ftp = (FTPClient) client;

        if (config != null) {
            ftp.configure(config);
        }
        ftp.setControlEncoding(getControlEncoding());

        super.connect(ftp);
        ftp.setDataTimeout(getDataTimeout());

        int code = ftp.getReplyCode();
        if (!FTPReply.isPositiveCompletion(code)) {
            ftp.disconnect();
            throw new BitbidException(String.valueOf(code));
        }
        if (!ftp.login(getUsername(), getPassword())) {
            ftp.disconnect();
            throw new BitbidException(String.valueOf(ftp.getReplyCode()));
        }
        if (isBinaryMode()) {
            ftp.setFileType(FTP.BINARY_FILE_TYPE);
        }
        if (isPassiveMode()) {
            ftp.enterLocalPassiveMode();
        }
    }

    @Override
	protected void disconnect(SocketClient client) throws Exception {
        FTPClient ftp = (FTPClient) client;
        if (ftp.isConnected()) {
            ftp.logout();
        }
        super.disconnect(client);
    }

    @Override
	protected SocketClient createSocketClient() {
        return new FTPClient();
    }
}

FileFtpPath
package com.bitbid.middleware.components.ftp;

import java.io.Serializable;
import java.util.Calendar;
import java.util.UUID;

public class FileFtpPath implements Serializable {

	private static final long serialVersionUID = 7406750362102141180L;

	private String firstLevelFolder;

	private String secondLevelFolder;

	private String thirdLevelFolder;

	private String randomFileName;

	public String getFirstLevelFolder() {
		return firstLevelFolder;
	}

	public String getSecondLevelFolder() {
		return secondLevelFolder;
	}

	public String getThirdLevelFolder() {
		return thirdLevelFolder;
	}

	public String getRandomFileName() {
		return randomFileName;
	}

	public String getAbsoluteFtpFilePath() {
		StringBuilder sb = new StringBuilder();
		sb.append(firstLevelFolder).append("/").append(secondLevelFolder)
				.append("/").append(thirdLevelFolder).append("/")
				.append(randomFileName);

		return sb.toString();
	}

	public String getAbsoluteFtpDirPath() {
		StringBuilder sb = new StringBuilder();
		sb.append(firstLevelFolder).append("/").append(secondLevelFolder)
				.append("/").append(thirdLevelFolder);

		return sb.toString();
	}

	public static FileFtpPath generateOne(String fileExtName) {
		FileFtpPath f = new FileFtpPath();

		Calendar c = Calendar.getInstance();
		int year = c.get(Calendar.YEAR);
		int month = c.get(Calendar.MONTH);
		int day = c.get(Calendar.DATE);
		int hour = c.get(Calendar.HOUR_OF_DAY);

		StringBuilder sb = new StringBuilder();

		f.firstLevelFolder = sb.append(year).append(month).toString();
		f.secondLevelFolder = String.valueOf(day);
		f.thirdLevelFolder = String.valueOf(hour);

		StringBuilder sbFileName = new StringBuilder();
		sbFileName.append(UUID.randomUUID().toString());
		if (fileExtName.startsWith(".")) {
			sbFileName.append(fileExtName);
		} else {
			sbFileName.append(".").append(fileExtName);
		}

		f.randomFileName = sbFileName.toString();

		return f;

	}

}
系统登录的token认证拦截器
package com.bitbid.bidopenconsultations.common.aspect.interceptors;

import com.bitbid.middleware.components.login.LoginFacade;
import com.bitbid.middleware.utils.beanfactory.IocBeanFactory;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;

/**
 * @author : renfeisheng
 * @date : 2018-9-22 11:16
 * 功能描述 : 适用于当前系统登录的token认证拦截器
 */
public class ToolsTokenValidationInterceptor implements HandlerInterceptor {

    public static final String TOKEN_MARK = "tools-token";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
        // Content-Type为application/x-www-form-urlencoded;charset的会发送OPTIONS预处理请求,验证接口是否正常,如果是预处理直接通过
        if(request.getMethod().equals("OPTIONS")){
            return true;
        }
        String token = getToken(request);
        if(StringUtils.isNotBlank(token) && IocBeanFactory.getBean(LoginFacade.class).validate(token)){
            return true;
        } else {
            //包装token认证失败的请求头,实现跨域
            wrapResponseHeader(request, response);
            //401状态,认证失败
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
    }

    /**
     * @author DELL created it at 12:57 in 2018-6-11
     * 包装token认证失败的请求头,实现跨域
     */
    private void wrapResponseHeader(HttpServletRequest request, HttpServletResponse response){
        //起源,来自哪个请求,必须和request同源才能接收到
        response.addHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        //跨域策略,前后端都为true的情况下才能收到
        response.addHeader("Access-Control-Allow-Credentials", "true");
        response.addHeader("Access-Control-Max-Age", "3600");
    }

    /**
     * @author wangcong created it at 3:18 in 2018-4-26
     * 查找cookie,首先从request.header中查找,若没有,从cookie中查找
     */
    private String getToken(HttpServletRequest request){
        if(StringUtils.isNotBlank(request.getHeader(TOKEN_MARK))){
            return request.getHeader(TOKEN_MARK);
        }
        if(ArrayUtils.isNotEmpty(request.getCookies())){
            Cookie tokenCookie = Arrays.stream(request.getCookies())
                    .filter(cookie -> StringUtils.containsIgnoreCase(cookie.getName(), TOKEN_MARK))
                    .findAny().orElse(null);
            if(tokenCookie != null){
                return tokenCookie.getValue();
            }
        }
        return null;
    }

}
注册拦截器-需要放开链接
package com.bitbid.bidopenconsultations.common.config;

import com.bitbid.bidopenconsultations.common.aspect.interceptors.ToolsSessionInteceptor;
import com.bitbid.bidopenconsultations.common.aspect.interceptors.ToolsTokenValidationInterceptor;
import com.bitbid.bidopenconsultations.common.servlet.PDFServerServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author : renfeisheng
 * @date : 2018-9-22 11:11
 * 功能描述 :  适用于当前系统的WeB的统一配置类
 */
@Configuration
public class ToolsWebConfig implements WebMvcConfigurer {

    /**
     * @author wangcong created it at 16:48 in 2018-4-18
     * 注册统一时间格式
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new DateFormatter("yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * @author wangcong created it at 16:48 in 2018-4-18
     * 注册拦截器
     */

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册SessionHandlerInterceptor
        ToolsSessionInteceptor sessionHandler = new ToolsSessionInteceptor();
        registry.addInterceptor(sessionHandler).addPathPatterns("/api/v1/bid-tools/**");
        //注册Token认证拦截器
        ToolsTokenValidationInterceptor tokenValidationInterceptor = new ToolsTokenValidationInterceptor();
        registry.addInterceptor(tokenValidationInterceptor)
                .addPathPatterns("/api/v1/bid-tools/**")
                .excludePathPatterns("/api/v1/bid-tools/login","/api/v1/bid-tools/loginCA","/api/v1/bid-tools/file/*","/api/v1/bid-tools/pluses/*","/api/v1/bid-tools/tender/tenderSign",
                        "/api/v1/bid-tools/tender/tenderDownLoad","/api/v1/bid-tools/tender/downloadPriceModel","/api/v1/bid-tools/negotiating-answer/getBase64/*");
    }

    /**
     * @author wangcong created it at 15:08 in 2018-4-20
     * 添加CORS配置,可能引起CORS攻击
     */

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedHeaders("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "OPTIONS", "PUT")
                .maxAge(3600);
    }
    /**
     * @author renfeisheng created it at 14:06 in 2018-4-19
     * 注册PDFServerServlet
     * 金格pdf签章保存-uri: /PDFServer?doc=xxx
     */
    @Bean
    public ServletRegistrationBean<PDFServerServlet> getPDFServerServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean();
        registrationBean.setServlet(new PDFServerServlet());
        registrationBean.addUrlMappings("/PDFSignatureServer/PDFServer");
        return registrationBean;
    }
}

vue前端

先安装这个包

npm install --save vue-pdf

页面引入

import pdf from 'vue-pdf'

使用

<el-dialog title="查看文件" :visible.sync="offerFilePathVisible" width="70%" top="10vh">
            <el-button-group>
              <el-button type="primary" icon="el-icon-arrow-left"  @click="prePage">上一页</el-button>
              <el-button type="primary" @click="nextPage">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button>
            </el-button-group>
            <div style="margintop: 10px; color: #409eff">
              {{ pageNum }} / {{ pageTotalNum }}
            </div>
            <div style="height: 600px;overflow: auto;">
              <pdf
                :page="pageNum"
                :src="url"
                @progress="loadedRatio = $event"
                @num-pages="pageTotalNum = $event"
              ></pdf>
            </div>
          </el-dialog>

data参数:

url: '', // http://192.168.1.104:6999/api/v1/bid-tools/negotiating-answer/getBase64/8cf3f0f8e78e4cee9515baf1bfc1fbb3
      pageNum: 1,
      pageTotalNum: 1, // 总页数
      loadedRatio: 0, // 当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了

function 

// 上一页
    prePage () {
      let page = this.pageNum
      page = page > 1 ? page - 1 : this.pageTotalNum
      this.pageNum = page
    },

    // 下一页
    nextPage () {
      let page = this.pageNum
      page = page < this.pageTotalNum ? page + 1 : 1
      this.pageNum = page
    },
    tenderFileBtn (scope) {
      // let url = pdfUrl + '?doc=' + scope.row.offerFilePath +
      //   '&height=' + this.winHeight + '&width=' + this.winWidth
      // let url = {offerFilePath: scope.row.offerFilePath}
      // consultingSummary.getBase64(scope.row.objectId).then((res) => {
      //   console.log(res)
      // })
      console.log(this.url)
      this.url = process.env.DOWNLOAD_LINK + 'bid-tools/negotiating-answer/getBase64/' + scope.row.objectId
      this.offerFilePathVisible = true
    },

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程界的小子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值