文件下载限流

package com.wnsys.admin.limiter;

import com.wnsys.admin.util.FileDownloadUtils;

/**
 * @Author: zhuquanwen
 * @Description:
 * @Date: 2018/3/8 16:54
 * @Modified:
 **/
public class BandwidthLimiter {
    public static int maxBandWith = 2 * 1024; //KB

    /* KB */
    private static Long KB = 1024l;
    /* The smallest count chunk length in bytes */
    private static Long CHUNK_LENGTH = 1024l;
    /* How many bytes will be sent or receive */
    private int bytesWillBeSentOrReceive = 0;
    /* When the last piece was sent or receive */
    private long lastPieceSentOrReceiveTick = System.nanoTime();
    /* Default rate is 1024KB/s */
    private int maxRate = 1024;
    /* Time cost for sending CHUNK_LENGTH bytes in nanoseconds */
    private long timeCostPerChunk = (1000000000l * CHUNK_LENGTH)
            / (this.maxRate * KB);

    /**
     * Initialize a BandwidthLimiter object with a certain rate.
     *
     * @param maxRate the download or upload speed in KBytes
     */
    public BandwidthLimiter(int maxRate) {
        this.setMaxRate(maxRate);
    }

    /**
     * Set the max upload or download rate in KB/s. maxRate must be grater than
     * 0. If maxRate is zero, it means there is no bandwidth limit.
     *
     * @param maxRate If maxRate is zero, it means there is no bandwidth limit.
     * @throws IllegalArgumentException
     */
    public synchronized void setMaxRate(int maxRate)
            throws IllegalArgumentException {
        if (maxRate < 0) {
            throw new IllegalArgumentException("maxRate can not less than 0");
        }
        this.maxRate = maxRate < 0 ? 0 : maxRate;
        if (maxRate == 0)
            this.timeCostPerChunk = 0;
        else
            this.timeCostPerChunk = (1000000000l * CHUNK_LENGTH)
                    / (this.maxRate * KB);
    }

    /**
     * Next 1 byte should do bandwidth limit.
     */
    public synchronized void limitNextBytes() {
        this.limitNextBytes(1);
    }

    /**
     * Next len bytes should do bandwidth limit
     *
     * @param len
     */
    public synchronized void limitNextBytes(int len) {
        int online = FileDownloadUtils.onlineDownloadNumber.get();
        int max =  online> 0 ? BandwidthLimiter.maxBandWith/online : BandwidthLimiter.maxBandWith;
        setMaxRate(max);
        this.bytesWillBeSentOrReceive += len;

                 /* We have sent CHUNK_LENGTH bytes */
        while (this.bytesWillBeSentOrReceive > CHUNK_LENGTH) {
            long nowTick = System.nanoTime();
            long missedTime = this.timeCostPerChunk
                    - (nowTick - this.lastPieceSentOrReceiveTick);
            if (missedTime > 0) {
                try {
                    Thread.currentThread().sleep(missedTime / 1000000,
                            (int) (missedTime % 1000000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.bytesWillBeSentOrReceive -= CHUNK_LENGTH;
            this.lastPieceSentOrReceiveTick = nowTick
                    + (missedTime > 0 ? missedTime : 0);
        }
    }

}

package com.wnsys.admin.limiter;

import java.io.IOException;
import java.io.InputStream;

/**
 * @Author: zhuquanwen
 * @Description:
 * @Date: 2018/3/8 17:06
 * @Modified:
 **/
public class LimiterInputStream extends InputStream {
    private InputStream is = null;
    private BandwidthLimiter bandwidthLimiter = null;

    public LimiterInputStream(InputStream is, BandwidthLimiter bandwidthLimiter) {
        this.is = is;
        this.bandwidthLimiter = bandwidthLimiter;
    }

    @Override
    public int read() throws IOException {
        if (this.bandwidthLimiter != null)
            this.bandwidthLimiter.limitNextBytes();
        return this.is.read();
    }

    public int read(byte b[], int off, int len) throws IOException {
        if (bandwidthLimiter != null)
            bandwidthLimiter.limitNextBytes(len);
        return this.is.read(b, off, len);
    }
 }


package com.wnsys.admin.limiter;

import java.io.IOException;
import java.io.OutputStream;

/**
 * @Author: zhuquanwen
 * @Description:
 * @Date: 2018/3/9 9:01
 * @Modified:
 **/
public class LimiterOutputStream extends OutputStream {
    private OutputStream os = null;
    private BandwidthLimiter bandwidthLimiter = null;

    public LimiterOutputStream(OutputStream os, BandwidthLimiter bandwidthLimiter) {
        this.os = os;
        this.bandwidthLimiter = bandwidthLimiter;
    }

    @Override
    public void write(int b) throws IOException {
        if (bandwidthLimiter != null)
            bandwidthLimiter.limitNextBytes();
        this.os.write(b);
    }

    public void write(byte[] b, int off, int len) throws IOException {
        if (bandwidthLimiter != null)
            bandwidthLimiter.limitNextBytes(len);
        this.os.write(b, off, len);
    }

}


package com.wnsys.admin.util;

import com.wnsys.admin.limiter.BandwidthLimiter;
import com.wnsys.admin.limiter.LimiterOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: zhuquanwen
 * @Description: 文件下载工具类
 * @Date: 2018/1/18 13:57
 * @Modified:
 **/
public class FileDownloadUtils {
    private static Logger logger = LoggerFactory.getLogger(FileDownloadUtils.class);
    public static AtomicInteger onlineDownloadNumber = new AtomicInteger(0);
    private FileDownloadUtils(){

    }

    public static String transFileName(String fileName, HttpServletRequest request) throws Exception{
        String agent = request.getHeader("USER-AGENT");
        //fileName = fileName.trim();       //去首尾空格

            //根据文件头判断请求来自的浏览器,以便有针对性的对文件名转码
            if(null != agent && -1 != agent.indexOf("theworld")){   //世界之窗
                fileName = new String(fileName.getBytes("gb2312"), "ISO8859-1");    //解决下载的文件名中含有小括号转变义符%28%29
            }else if(null != agent && -1 != agent.indexOf("MSIE 8.0")){ //IE8
                String lenFileName = URLEncoder.encode(fileName, "UTF-8");
                if (lenFileName.length() > 150) {    //文件名长度是否大于150个字符
                    fileName = new String(fileName.getBytes("gb2312"), "ISO8859-1");
                } else {
                    fileName = URLEncoder.encode(fileName,"UTF-8").replace("+","%20");
                }
            }else if(null != agent && -1 != agent.indexOf("MSIE 7.0") && -1 != agent.indexOf("SE 2.X MetaSr 1.0")){ //sogo浏览器
                fileName = URLEncoder.encode(fileName,"UTF-8").replace("+","%20");
            }else if(null != agent && (-1 != agent.indexOf("SV1") || -1 != agent.indexOf("360SE"))){    //360安全浏览器
                String lenFileName = URLEncoder.encode(fileName, "UTF-8");
                if (lenFileName.length() > 150) {    //文件名长度是否大于150个字符
                    fileName = new String(fileName.getBytes("gb2312"), "ISO8859-1");
                } else {
                    fileName = URLEncoder.encode(fileName,"UTF-8").replace("+","%20");
                }
            }else if(null != agent && -1 != agent.indexOf("Chrome")){   //google
                fileName = new String(fileName.getBytes("gb2312"), "ISO8859-1");    //解决下载的文件名中含有小括号转变义符%28%29
            }else if(null != agent && -1 != agent.indexOf("Firefox")){  //Firefox
                fileName = new String(fileName.getBytes("gb2312"), "ISO8859-1");
            }else if(null != agent && -1 != agent.indexOf("Safari")){   //Firefox
                fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
            }else { //其它浏览器
                fileName = new String(fileName.getBytes("gb2312"), "ISO8859-1");
            }

        return fileName;
    }


    public static void setResponseExcelHeader(HttpServletRequest request,HttpServletResponse response,String name) throws Exception {
        response.reset();
        response.setContentType("application/octet-stream;charset=utf-8"); // 改成输出excel文件
        String fileName = transFileName(name, request);
        response.setHeader(
                "Content-disposition",
                "attachment; filename="
                        +fileName);
    }

    public static void downFile(HttpServletRequest request, HttpServletResponse response, String path,
                                String name) throws Exception{
        Long fileLength = new File(path).length();// 文件的长度
        if (fileLength != 0) {
            response.reset();
            response.setContentType("application/force-download;charset=utf-8");
            String fileName = transFileName(name, request);
            response.setHeader(
                    "Content-disposition",
                    "attachment; filename="
                            +fileName);
            response.setHeader("Content-Length", String.valueOf(fileLength));

            try(
                    FileInputStream fis = new FileInputStream(path);
                    BufferedInputStream bis = new BufferedInputStream(fis);
                    // 输出流
                    BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
            ){
                logger.info("文件开始下载传输");
                byte[] buff = new byte[2048];
                int bytesread;
                // 写文件
                while (-1 != (bytesread = bis.read(buff, 0, buff.length))) {
                    bos.write(buff, 0, bytesread);
                }
            }

        }
    }

    public static void downFileWithLimiter(HttpServletRequest request, HttpServletResponse response, String path,
                                           String name, int maxRate) throws Exception{

        Long fileLength = new File(path).length();// 文件的长度
        if (fileLength != 0) {
            response.reset();
            response.setContentType("application/force-download;charset=utf-8");
            String fileName = transFileName(name, request);
            response.setHeader(
                    "Content-disposition",
                    "attachment; filename="
                            +fileName);
            response.setHeader("Content-Length", String.valueOf(fileLength));
            BandwidthLimiter bandwidthLimiter = new BandwidthLimiter(maxRate);
            try(
                    FileInputStream fis = new FileInputStream(path);
//                    LimiterInputStream limiterInput = new LimiterInputStream(fis,bandwidthLimiter);
                    BufferedInputStream bis = new BufferedInputStream(fis);
                    // 输出流
                    BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
                    OutputStream os = new LimiterOutputStream(bos,bandwidthLimiter);
            ){
                logger.info("文件开始下载传输");
                byte[] buff = new byte[2048];
                int bytesread;
                // 写文件
                while (-1 != (bytesread = bis.read(buff, 0, buff.length))) {
                    os.write(buff, 0, bytesread);
                }
            }

        }
    }


    public static void downFileWithLimiter(HttpServletRequest request, HttpServletResponse response, String path,
                                String name) throws Exception{
        int onlineNumber = onlineDownloadNumber.incrementAndGet();
        int maxRate = BandwidthLimiter.maxBandWith/onlineNumber;
        Long fileLength = new File(path).length();// 文件的长度
        if (fileLength != 0) {
            response.reset();
            response.setContentType("application/force-download;charset=utf-8");
            String fileName = transFileName(name, request);
            response.setHeader(
                    "Content-disposition",
                    "attachment; filename="
                            +fileName);
            response.setHeader("Content-Length", String.valueOf(fileLength));
            BandwidthLimiter bandwidthLimiter = new BandwidthLimiter(maxRate);
            try{
                try(
                        FileInputStream fis = new FileInputStream(path);
//                    LimiterInputStream limiterInput = new LimiterInputStream(fis,bandwidthLimiter);
                        BufferedInputStream bis = new BufferedInputStream(fis);
                        // 输出流
                        BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
                        OutputStream os = new LimiterOutputStream(bos,bandwidthLimiter);
                ){
                    logger.info("文件开始下载传输");
                    byte[] buff = new byte[2048];
                    int bytesread;
                    // 写文件
                    while (-1 != (bytesread = bis.read(buff, 0, buff.length))) {
                        os.write(buff, 0, bytesread);
                    }
                }
            }catch(Exception e){
                throw e;
            }finally{
                onlineDownloadNumber.decrementAndGet();
            }


        }
    }

    public static void downExcelFile(HttpServletRequest request, HttpServletResponse response, String path,
                              String name) throws Exception {
        Long fileLength = new File(path).length();// 文件的长度
        if (fileLength != 0) {
            setResponseExcelHeader(request,response,name);
            response.setHeader("Content-Length", String.valueOf(fileLength));
            try(
                    FileInputStream fis = new FileInputStream(path);
                    BufferedInputStream bis = new BufferedInputStream(fis);
                    // 输出流
                    BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
            ){
                logger.info("文件开始下载传输");
                byte[] buff = new byte[2048];
                int bytesread;
                // 写文件
                while (-1 != (bytesread = bis.read(buff, 0, buff.length))) {
                    bos.write(buff, 0, bytesread);
                }
            }

        }
    }

    public static void downExcelStream(HttpServletRequest request, HttpServletResponse response, InputStream inputStream,
                                     String name) throws Exception {
       setResponseExcelHeader(request,response,name);
//      response.setHeader("Content-Length", String.valueOf(fileLength));
        try(
                BufferedInputStream bis = new BufferedInputStream(inputStream);
                // 输出流
                BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
        ){
            logger.info("文件开始下载传输");
            byte[] buff = new byte[2048];
            int bytesread;
            // 写文件
            while (-1 != (bytesread = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesread);
            }
        }

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值