目录

一、easyexcel实现表格填充

1. maven依赖

2. 官方参考文档地址

二、FreeMarker导出word文档

1. maven依赖

2. 参考博文

三、springBoot中Modubus协议连接工具类

1. maven依赖

2.工具类(包含02 03 04 05功能码)

四、m3u8格式视频转成MP4格式视频

1. maven依赖

2.相关工具类

五、集成螺丝钉输出数据库设计文档

1. maven依赖

2.工具类


一、easyexcel实现表格填充

1. maven依赖


<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency><!-- easyexcel工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>

2. 官方参考文档地址

https://www.yuque.com/easyexcel/doc/easyexcel

二、FreeMarker导出word文档

1. maven依赖

<dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.29</version>
</dependency>

2. 参考博文

https://www.cnblogs.com/duanrantao/p/9377818.html

三、springBoot中Modubus协议连接工具类

1. maven依赖

<dependency><groupId>com.infiniteautomation</groupId><artifactId>modbus4j</artifactId><version>3.0.3</version>
</dependency>

2.工具类(包含02 03 04 05功能码)

说明:目前工具类中定义了一个静态的tcpMaster,可以在main方法中调用不同功能码函数时传入。这种方式在实际开发时可以定一个连接池,可以避免一直创建连接,避免未知错误。

import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.msg.*;
import com.serotonin.modbus4j.sero.util.queue.ByteQueue;
import lombok.extern.slf4j.Slf4j;import java.util.Arrays;/*** @author xiehan* @version 1.0* @date 2020/6/24 14:38*/
@Slf4j
public class Modbus4jUtils {/*** 工厂。*/static ModbusFactory modbusFactory;//建立链接static ModbusMaster tcpMaster;static {if (modbusFactory == null) {modbusFactory = new ModbusFactory();tcpMaster = getMaster("192.168.1.xxx",502);}}/*** 获取master** @return* @throws ModbusInitException*/public static ModbusMaster getMaster(String ip,Integer port){IpParameters params = new IpParameters();params.setHost(ip);params.setPort(port);//params.setHost("192.168.1.xxx");//params.setPort(502);// modbusFactory.createRtuMaster(wapper); //RTU 协议// modbusFactory.createUdpMaster(params);//UDP 协议// modbusFactory.createAsciiMaster(wrapper);//ASCII 协议ModbusMaster  master = modbusFactory.createTcpMaster(params, true);// TCP 协议try {master.setTimeout(5000);master.setRetries(3);master.init();} catch (ModbusInitException e) {e.printStackTrace();}return master;}/*** 读取离散输入状态[02]* @param start  开始位* @param readLenth  位数* @return* @throws ModbusInitException*/public static ByteQueue modbusTCP02(int slaveId,ModbusMaster tcpMaster,int start, int readLenth) throws ModbusInitException {//建立链接//ModbusMaster tcpMaster = getMaster(ip,port);//发送请求ModbusRequest modbusRequest=null;try {modbusRequest = new ReadDiscreteInputsRequest(slaveId, start, readLenth);//功能码02} catch (ModbusTransportException e) {e.printStackTrace();}//收到响应ReadResponse modbusResponse=null;try {modbusResponse = (ReadResponse) tcpMaster.send(modbusRequest);System.out.println(modbusResponse.getData());System.out.println(Arrays.toString(modbusResponse.getBooleanData()));} catch (ModbusTransportException e) {e.printStackTrace();}ByteQueue byteQueue= new ByteQueue(12);modbusResponse.write(byteQueue);System.out.println("功能码:"+modbusRequest.getFunctionCode());System.out.println("从站地址:"+modbusRequest.getSlaveId());System.out.println("开始地址:"+start);System.out.println("收到的响应信息大小:"+byteQueue.size());System.out.println("收到的响应信息值:"+byteQueue);return byteQueue;}/*** 读取离散输入状态[02]* @param start  开始位* @param readLength  位数* @return 返回boolean数组* @throws*/public static boolean[] modbusTCP02Boolean(int slaveId, ModbusMaster tcpMaster, int start, int readLength) {ModbusRequest modbusRequest;ReadResponse modbusResponse;boolean [] ret = null;try {modbusRequest = new ReadDiscreteInputsRequest(slaveId, start, readLength);//功能码02modbusResponse = (ReadResponse) tcpMaster.send(modbusRequest);if(modbusResponse.isException()){log.error("读取异常 {}",modbusResponse.getExceptionMessage());return ret;}ret = modbusResponse.getBooleanData();} catch (ModbusTransportException e) {log.error("02功能码读取异常 ",e);}return ret;}/*** 读取保持寄存器[03]* @param start   开始地址* @param readLenth  读取数量* @return 返回short 数组* @throws*/public static short[] modbusTCP03Short(int slaveId,ModbusMaster tcpMaster,int start, int readLenth) {ModbusRequest modbusRequest = null;ReadResponse modbusResponse = null;short [] ret = null;try {modbusRequest = new ReadHoldingRegistersRequest(slaveId, start, readLenth);//功能码03modbusResponse = (ReadResponse) tcpMaster.send(modbusRequest);ret = modbusResponse.getShortData();} catch (ModbusTransportException e) {log.error("03功能码读取异常 ",e);}return ret;}/*** 读取保持寄存器[03]* @param start   开始地址* @param readLenth  读取数量* @return* @throws ModbusInitException*/public static ByteQueue modbusTCP03(int slaveId,ModbusMaster tcpMaster,int start, int readLenth) throws ModbusInitException {//建立链接//ModbusMaster tcpMaster = getMaster(ip,port);//发送请求ModbusRequest modbusRequest=null;try {modbusRequest = new ReadHoldingRegistersRequest(slaveId, start, readLenth);//功能码03} catch (ModbusTransportException e) {e.printStackTrace();}//收到响应ModbusResponse modbusResponse=null;try {modbusResponse = tcpMaster.send(modbusRequest);} catch (ModbusTransportException e) {e.printStackTrace();}ByteQueue byteQueue= new ByteQueue(12);modbusResponse.write(byteQueue);System.out.println("功能码:"+modbusRequest.getFunctionCode());System.out.println("从站地址:"+modbusRequest.getSlaveId());System.out.println("开始地址:"+start);System.out.println("收到的响应信息大小:"+byteQueue.size());System.out.println("收到的响应信息值:"+byteQueue);return byteQueue;}/*** 读取输入寄存器[04]* @param start   开始地址* @param readLenth  读取数量* @return* @throws ModbusInitException*/public static ByteQueue modbusTCP04(int slaveId, ModbusMaster tcpMaster, int start, int readLenth) throws ModbusInitException {//建立链接
//        ModbusMaster tcpMaster = getMaster(ip,port);//发送请求ModbusRequest modbusRequest=null;try {modbusRequest = new ReadInputRegistersRequest(slaveId, start, readLenth);//功能码04} catch (ModbusTransportException e) {e.printStackTrace();}//收到响应ModbusResponse modbusResponse=null;try {modbusResponse = tcpMaster.send(modbusRequest);} catch (ModbusTransportException e) {e.printStackTrace();}ByteQueue byteQueue= new ByteQueue(12);modbusResponse.write(byteQueue);System.out.println("功能码:"+modbusRequest.getFunctionCode());System.out.println("从站地址:"+modbusRequest.getSlaveId());System.out.println("开始地址:"+start);System.out.println("收到的响应信息大小:"+byteQueue.size());System.out.println("收到的响应信息值:"+byteQueue);return byteQueue;}/*** 读取输入寄存器[04]* @param start   开始地址* @param readLenth  读取数量* @return* @throws ModbusInitException*/public static short[] modbusTCP04Short(int slaveId, ModbusMaster tcpMaster, int start, int readLenth){ModbusRequest modbusRequest = null;ReadResponse modbusResponse = null;short [] ret = null;try {modbusRequest = new ReadInputRegistersRequest(slaveId, start, readLenth);//功能码03modbusResponse = (ReadResponse) tcpMaster.send(modbusRequest);ret = modbusResponse.getShortData();System.out.println("功能码:"+modbusRequest.getFunctionCode());System.out.println("从站地址:"+modbusRequest.getSlaveId());System.out.println("开始地址:"+start);System.out.println("收到的响应信息值:"+Arrays.toString(ret));} catch (ModbusTransportException e) {log.error("04功能码读取异常 ",e);}return ret;}/*** 写单个线圈[05]* @param writeOffset  开始位* @param writeValue  true false* @return* @throws ModbusInitException*/public static ByteQueue modbusTCP05(int slaveId,ModbusMaster tcpMaster,int writeOffset, boolean writeValue) throws ModbusInitException {//建立链接//ModbusMaster tcpMaster = getMaster(ip,port);//发送请求ModbusRequest modbusRequest=null;try {modbusRequest = new WriteCoilRequest(slaveId, writeOffset, writeValue);//功能码05} catch (ModbusTransportException e) {e.printStackTrace();}//收到响应ModbusResponse modbusResponse=null;try {modbusResponse = tcpMaster.send(modbusRequest);} catch (ModbusTransportException e) {e.printStackTrace();}ByteQueue byteQueue= new ByteQueue(12);modbusResponse.write(byteQueue);System.out.println("功能码:"+modbusRequest.getFunctionCode());System.out.println("从站地址:"+modbusRequest.getSlaveId());System.out.println("收到的响应信息大小:"+byteQueue.size());System.out.println("收到的响应信息值:"+byteQueue);return byteQueue;}}

四、m3u8格式视频转成MP4格式视频

1. maven依赖

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.60</version></dependency>

2.相关工具类

public class Constant {//文件分隔符,在window中为\\,在linux中为/public static final String FILESEPARATOR = System.getProperty("file.separator");//因子public static final float FACTOR = 1.15F;//默认文件每次读取字节数public static final int BYTE_COUNT = 40960;//日志级别 控制台不输出public static final int NONE = 0X453500;//日志级别 控制台输出所有信息public static final int INFO = 0X453501;//日志级别 控制台输出调试和错误信息public static final int DEBUG = 0X453502;//日志级别 控制台只输出错误信息public static final int ERROR = 0X453503;}
public interface DownloadListener {void start();void process(String downloadUrl, int finished, int sum, float percent);void speed(String speedPerSecond);void end();}
public class Log {private static volatile int level = Constant.INFO;public static void i(CharSequence message) {if (level == Constant.INFO) {System.out.println("\33[0;2m" + message);}}public static void d(CharSequence message) {if (level == Constant.INFO || level == Constant.DEBUG) {System.out.println("\33[36;2m" + message);System.out.print("\33[0;2m");}}public static void e(CharSequence message) {if (level == Constant.INFO || level == Constant.ERROR) {System.out.println("\33[31;2m" + message);System.out.print("\33[0;2m");}}public static void setLevel(int level) {if (level != Constant.NONE && level != Constant.INFO && level != Constant.DEBUG && level != Constant.ERROR) {throw new IllegalArgumentException("日志参数信息设置错误!");}Log.level = level;}public static int getLevel() {return level;}
}
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Security;
import java.security.spec.AlgorithmParameterSpec;
import java.util.*;
import java.util.concurrent.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;public class M3u8DownloadFactory {private static M3u8Download m3u8Download;/**** 解决java不支持AES/CBC/PKCS7Padding模式解密**/static {Security.addProvider(new BouncyCastleProvider());}public static class M3u8Download {//要下载的m3u8链接private final String DOWNLOADURL;//优化内存占用private static final BlockingQueue<byte[]> BLOCKING_QUEUE = new LinkedBlockingQueue<>();//线程数private int threadCount = 1;//重试次数private int retryCount = 30;//链接连接超时时间(单位:毫秒)private long timeoutMillisecond = 1000L;//合并后的文件存储目录private String dir;//合并后的视频文件名称private String fileName;//已完成ts片段个数private int finishedCount = 0;//解密算法名称private String method;//密钥private String key = "";//密钥字节private byte[] keyBytes = new byte[16];//key是否为字节private boolean isByte = false;//IVprivate String iv = "";//所有ts片段下载链接private Set<String> tsSet = new LinkedHashSet<>();//解密后的片段private Set<File> finishedFiles = new ConcurrentSkipListSet<>(Comparator.comparingInt(o -> Integer.parseInt(o.getName().replace(".xyz", ""))));//已经下载的文件大小private BigDecimal downloadBytes = new BigDecimal(0);//监听间隔private volatile long interval = 0L;//自定义请求头private Map<String, Object> requestHeaderMap = new HashMap<>();;//监听事件private Set<DownloadListener> listenerSet = new HashSet<>(5);/*** 开始下载视频*/public void start() {setThreadCount(30);checkField();String tsUrl = getTsUrl();if (StringUtils.isEmpty(tsUrl)) {Log.i("不需要解密");}startDownload();}/*** 下载视频*/private void startDownload() {//线程池final ExecutorService fixedThreadPool = Executors.newFixedThreadPool(threadCount);int i = 0;//如果生成目录不存在,则创建File file1 = new File(dir);if (!file1.exists()) {file1.mkdirs();}//执行多线程下载for (String s : tsSet) {i++;fixedThreadPool.execute(getThread(s, i));}fixedThreadPool.shutdown();//下载过程监视new Thread(() -> {int consume = 0;//轮询是否下载成功while (!fixedThreadPool.isTerminated()) {try {consume++;BigDecimal bigDecimal = new BigDecimal(downloadBytes.toString());Thread.sleep(1000L);Log.i("已用时" + consume + "秒!\t下载速度:" + StringUtils.convertToDownloadSpeed(new BigDecimal(downloadBytes.toString()).subtract(bigDecimal), 3) + "/s");Log.i("\t已完成" + finishedCount + "个,还剩" + (tsSet.size() - finishedCount) + "个!");Log.i(new BigDecimal(finishedCount).divide(new BigDecimal(tsSet.size()), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP) + "%");} catch (InterruptedException e) {e.printStackTrace();}}Log.i("下载完成,正在合并文件!共" + finishedFiles.size() + "个!" + StringUtils.convertToDownloadSpeed(downloadBytes, 3));//开始合并视频mergeTs();//删除多余的ts片段deleteFiles();Log.i("视频合并完成,欢迎使用!");}).start();startListener(fixedThreadPool);}private void startListener(ExecutorService fixedThreadPool) {new Thread(() -> {for (DownloadListener downloadListener : listenerSet) {downloadListener.start();}//轮询是否下载成功while (!fixedThreadPool.isTerminated()) {try {Thread.sleep(interval);for (DownloadListener downloadListener : listenerSet) {downloadListener.process(DOWNLOADURL, finishedCount, tsSet.size(), new BigDecimal(finishedCount).divide(new BigDecimal(tsSet.size()), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue());}} catch (InterruptedException e) {e.printStackTrace();}}for (DownloadListener downloadListener : listenerSet) {downloadListener.end();}}).start();new Thread(() -> {while (!fixedThreadPool.isTerminated()) {try {BigDecimal bigDecimal = new BigDecimal(downloadBytes.toString());Thread.sleep(1000L);for (DownloadListener downloadListener : listenerSet) {downloadListener.speed(StringUtils.convertToDownloadSpeed(new BigDecimal(downloadBytes.toString()).subtract(bigDecimal), 3) + "/s");}} catch (InterruptedException e) {e.printStackTrace();}}}).start();}/*** 合并下载好的ts片段*/private void mergeTs() {try {File file = new File(dir + Constant.FILESEPARATOR + fileName + ".mp4");System.gc();if (file.exists()) {file.delete();} else {file.createNewFile();}FileOutputStream fileOutputStream = new FileOutputStream(file);byte[] b = new byte[4096];for (File f : finishedFiles) {FileInputStream fileInputStream = new FileInputStream(f);int len;while ((len = fileInputStream.read(b)) != -1) {fileOutputStream.write(b, 0, len);}fileInputStream.close();fileOutputStream.flush();}fileOutputStream.close();} catch (Exception e) {e.printStackTrace();}}/*** 删除下载好的片段*/private void deleteFiles() {File file = new File(dir);for (File f : file.listFiles()) {if (f.getName().endsWith(".xy") || f.getName().endsWith(".xyz"))f.delete();}}/*** 开启下载线程** @param urls ts片段链接* @param i    ts片段序号* @return 线程*/private Thread getThread(String urls, int i) {return new Thread(() -> {int count = 1;HttpURLConnection httpURLConnection = null;//xy为未解密的ts片段,如果存在,则删除File file2 = new File(dir + Constant.FILESEPARATOR + i + ".xy");if (file2.exists())file2.delete();OutputStream outputStream = null;InputStream inputStream1 = null;FileOutputStream outputStream1 = null;byte[] bytes;try {bytes = BLOCKING_QUEUE.take();} catch (InterruptedException e) {bytes = new byte[Constant.BYTE_COUNT];}//重试次数判断while (count <= retryCount) {try {//模拟http请求获取ts片段文件URL url = new URL(urls);httpURLConnection = (HttpURLConnection) url.openConnection();httpURLConnection.setConnectTimeout((int) timeoutMillisecond);for (Map.Entry<String, Object> entry : requestHeaderMap.entrySet()) {httpURLConnection.addRequestProperty(entry.getKey(), entry.getValue().toString());}httpURLConnection.setUseCaches(false);httpURLConnection.setReadTimeout((int) timeoutMillisecond);httpURLConnection.setDoInput(true);InputStream inputStream = httpURLConnection.getInputStream();try {outputStream = new FileOutputStream(file2);} catch (FileNotFoundException e) {e.printStackTrace();continue;}int len;//将未解密的ts片段写入文件while ((len = inputStream.read(bytes)) != -1) {outputStream.write(bytes, 0, len);synchronized (this) {downloadBytes = downloadBytes.add(new BigDecimal(len));}}outputStream.flush();inputStream.close();inputStream1 = new FileInputStream(file2);int available = inputStream1.available();if (bytes.length < available) {bytes = new byte[available];}inputStream1.read(bytes);File file = new File(dir + Constant.FILESEPARATOR + i + ".xyz");outputStream1 = new FileOutputStream(file);//开始解密ts片段,这里我们把ts后缀改为了xyz,改不改都一样byte[] decrypt = decrypt(bytes, available, key, iv, method);if (decrypt == null) {outputStream1.write(bytes, 0, available);} else {outputStream1.write(decrypt);}finishedFiles.add(file);break;} catch (Exception e) {if (e instanceof InvalidKeyException || e instanceof InvalidAlgorithmParameterException) {Log.e("解密失败!");break;}Log.d("第" + count + "获取链接重试!\t" + urls);count++;
//                        e.printStackTrace();} finally {try {if (inputStream1 != null) {inputStream1.close();}if (outputStream1 != null) {outputStream1.close();}if (outputStream != null) {outputStream.close();}BLOCKING_QUEUE.put(bytes);} catch (IOException | InterruptedException e) {e.printStackTrace();}if (httpURLConnection != null) {httpURLConnection.disconnect();}}}if (count > retryCount)//自定义异常{throw new M3u8Exception("连接超时!");}finishedCount++;
//                Log.i(urls + "下载完毕!\t已完成" + finishedCount + "个,还剩" + (tsSet.size() - finishedCount) + "个!");});}/*** 获取所有的ts片段下载链接** @return 链接是否被加密,null为非加密*/private String getTsUrl() {StringBuilder content = getUrlContent(DOWNLOADURL, false);//判断是否是m3u8链接if (!content.toString().contains("#EXTM3U")) {throw new M3u8Exception(DOWNLOADURL + "不是m3u8链接!");}String[] split = content.toString().split("\\n");String keyUrl = "";boolean isKey = false;for (String s : split) {//如果含有此字段,则说明只有一层m3u8链接if (s.contains("#EXT-X-KEY") || s.contains("#EXTINF")) {isKey = true;keyUrl = DOWNLOADURL;break;}//如果含有此字段,则说明ts片段链接需要从第二个m3u8链接获取if (s.contains(".m3u8")) {if (StringUtils.isUrl(s)) {return s;}String relativeUrl = DOWNLOADURL.substring(0, DOWNLOADURL.lastIndexOf("/") + 1);if (s.startsWith("/")) {s = s.replaceFirst("/", "");}keyUrl = mergeUrl(relativeUrl, s);break;}}if (StringUtils.isEmpty(keyUrl)) {throw new M3u8Exception("未发现key链接!");}//获取密钥String key1 = isKey ? getKey(keyUrl, content) : getKey(keyUrl, null);if (StringUtils.isNotEmpty(key1)) {key = key1;} else {key = null;}return key;}/*** 获取ts解密的密钥,并把ts片段加入set集合** @param url     密钥链接,如果无密钥的m3u8,则此字段可为空* @param content 内容,如果有密钥,则此字段可以为空* @return ts是否需要解密,null为不解密*/private String getKey(String url, StringBuilder content) {StringBuilder urlContent;if (content == null || StringUtils.isEmpty(content.toString())) {urlContent = getUrlContent(url, false);} else {urlContent = content;}if (!urlContent.toString().contains("#EXTM3U")) {throw new M3u8Exception(DOWNLOADURL + "不是m3u8链接!");}String[] split = urlContent.toString().split("\\n");for (String s : split) {//如果含有此字段,则获取加密算法以及获取密钥的链接if (s.contains("EXT-X-KEY")) {String[] split1 = s.split(",");for (String s1 : split1) {if (s1.contains("METHOD")) {method = s1.split("=", 2)[1];continue;}if (s1.contains("URI")) {key = s1.split("=", 2)[1];continue;}if (s1.contains("IV")) {iv = s1.split("=", 2)[1];}}}}String relativeUrl = url.substring(0, url.lastIndexOf("/") + 1);//将ts片段链接加入set集合for (int i = 0; i < split.length; i++) {String s = split[i];if (s.contains("#EXTINF")) {String s1 = split[++i];tsSet.add(StringUtils.isUrl(s1) ? s1 : mergeUrl(relativeUrl, s1));}}if (!StringUtils.isEmpty(key)) {key = key.replace("\"", "");return getUrlContent(StringUtils.isUrl(key) ? key : mergeUrl(relativeUrl, key), true).toString().replaceAll("\\s+", "");}return null;}/*** 模拟http请求获取内容** @param urls  http链接* @param isKey 这个url链接是否用于获取key* @return 内容*/private StringBuilder getUrlContent(String urls, boolean isKey) {int count = 1;HttpURLConnection httpURLConnection = null;StringBuilder content = new StringBuilder();while (count <= retryCount) {try {URL url = new URL(urls);httpURLConnection = (HttpURLConnection) url.openConnection();httpURLConnection.setConnectTimeout((int) timeoutMillisecond);httpURLConnection.setReadTimeout((int) timeoutMillisecond);httpURLConnection.setUseCaches(false);httpURLConnection.setDoInput(true);for (Map.Entry<String, Object> entry : requestHeaderMap.entrySet()) {httpURLConnection.addRequestProperty(entry.getKey(), entry.getValue().toString());}String line;InputStream inputStream = httpURLConnection.getInputStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));if (isKey) {byte[] bytes = new byte[128];int len;len = inputStream.read(bytes);isByte = true;if (len == 1 << 4) {keyBytes = Arrays.copyOf(bytes, 16);content.append("isByte");} else {content.append(new String(Arrays.copyOf(bytes, len)));}return content;}while ((line = bufferedReader.readLine()) != null) {content.append(line).append("\n");}bufferedReader.close();inputStream.close();Log.i(content);break;} catch (Exception e) {Log.d("第" + count + "获取链接重试!\t" + urls);count++;
//                    e.printStackTrace();} finally {if (httpURLConnection != null) {httpURLConnection.disconnect();}}}if (count > retryCount) {throw new M3u8Exception("连接超时!");}return content;}/*** 解密ts** @param sSrc   ts文件字节数组* @param length* @param sKey   密钥* @return 解密后的字节数组*/private byte[] decrypt(byte[] sSrc, int length, String sKey, String iv, String method) throws Exception {if (StringUtils.isNotEmpty(method) && !method.contains("AES")) {throw new M3u8Exception("未知的算法!");}// 判断Key是否正确if (StringUtils.isEmpty(sKey)) {return null;}// 判断Key是否为16位if (sKey.length() != 16 && !isByte) {throw new M3u8Exception("Key长度不是16位!");}Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");SecretKeySpec keySpec = new SecretKeySpec(isByte ? keyBytes : sKey.getBytes(StandardCharsets.UTF_8), "AES");byte[] ivByte;if (iv.startsWith("0x")) {ivByte = StringUtils.hexStringToByteArray(iv.substring(2));} else {ivByte = iv.getBytes();}if (ivByte.length != 16) {ivByte = new byte[16];}//如果m3u8有IV标签,那么IvParameterSpec构造函数就把IV标签后的内容转成字节数组传进去AlgorithmParameterSpec paramSpec = new IvParameterSpec(ivByte);cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec);return cipher.doFinal(sSrc, 0, length);}/*** 字段校验*/private void checkField() {if ("m3u8".compareTo(MediaFormat.getMediaFormat(DOWNLOADURL)) != 0) {throw new M3u8Exception(DOWNLOADURL + "不是一个完整m3u8链接!");}if (threadCount <= 0) {throw new M3u8Exception("同时下载线程数只能大于0!");}if (retryCount < 0) {throw new M3u8Exception("重试次数不能小于0!");}if (timeoutMillisecond < 0) {throw new M3u8Exception("超时时间不能小于0!");}if (StringUtils.isEmpty(dir)) {throw new M3u8Exception("视频存储目录不能为空!");}if (StringUtils.isEmpty(fileName)) {throw new M3u8Exception("视频名称不能为空!");}finishedCount = 0;method = "";key = "";isByte = false;iv = "";tsSet.clear();finishedFiles.clear();downloadBytes = new BigDecimal(0);}private String mergeUrl(String start, String end) {if (end.startsWith("/")) {end = end.replaceFirst("/", "");}int position = 0;String subEnd, tempEnd = end;while ((position = end.indexOf("/", position)) != -1) {subEnd = end.substring(0, position + 1);if (start.endsWith(subEnd)) {tempEnd = end.replaceFirst(subEnd, "");break;}++position;}return start + tempEnd;}public String getDOWNLOADURL() {return DOWNLOADURL;}public int getThreadCount() {return threadCount;}public void setThreadCount(int threadCount) {if (BLOCKING_QUEUE.size() < threadCount) {for (int i = BLOCKING_QUEUE.size(); i < threadCount * Constant.FACTOR; i++) {try {BLOCKING_QUEUE.put(new byte[Constant.BYTE_COUNT]);} catch (InterruptedException ignored) {}}}this.threadCount = threadCount;}public int getRetryCount() {return retryCount;}public void setRetryCount(int retryCount) {this.retryCount = retryCount;}public long getTimeoutMillisecond() {return timeoutMillisecond;}public void setTimeoutMillisecond(long timeoutMillisecond) {this.timeoutMillisecond = timeoutMillisecond;}public String getDir() {return dir;}public void setDir(String dir) {this.dir = dir;}public String getFileName() {return fileName;}public void setFileName(String fileName) {this.fileName = fileName;}public int getFinishedCount() {return finishedCount;}public void setLogLevel(int level) {Log.setLevel(level);}public Map<String, Object> getRequestHeaderMap() {return requestHeaderMap;}public void addRequestHeaderMap(Map<String, Object> requestHeaderMap) {this.requestHeaderMap.putAll(requestHeaderMap);}public void setInterval(long interval) {this.interval = interval;}public void addListener(DownloadListener downloadListener) {listenerSet.add(downloadListener);}private M3u8Download(String DOWNLOADURL) {this.DOWNLOADURL = DOWNLOADURL;requestHeaderMap.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36");}}/*** 获取实例** @param downloadUrl 要下载的链接* @return 返回m3u8下载实例*/public static M3u8Download getInstance(String downloadUrl) {if (m3u8Download == null) {synchronized (M3u8Download.class) {if (m3u8Download == null) {m3u8Download = new M3u8Download(downloadUrl);}}}return m3u8Download;}public static void destroied() {m3u8Download = null;}}
public class M3u8Exception extends RuntimeException {public M3u8Exception() {super();}public M3u8Exception(String message) {super(message);}public M3u8Exception(String message, Throwable cause) {super(message, cause);}
}
import java.util.HashSet;
import java.util.Set;public class MediaFormat {private static Set<String> set = new HashSet<>();static {set.add("mp4");set.add("mkv");set.add("webm");set.add("gif");set.add("mov");set.add("ogg");set.add("flv");set.add("avi");set.add("3gp");set.add("wmv");set.add("mpg");set.add("vob");set.add("swf");set.add("m3u8");}private MediaFormat() {}public static String getMediaFormat(String url) {if (!StringUtils.isUrl(url))throw new M3u8Exception(url + "不是一个完整URL链接!");url = url.substring(url.lastIndexOf("/") - 1);for (String s : set) {if (url.contains(s))return s;}throw new M3u8Exception("非视频链接!");}
}
import java.math.BigDecimal;public class StringUtils {public static boolean isBlank(String str) {return str == null || str.length() == 0;}public static boolean isEmpty(String str) {return str == null || str.trim().length() == 0;}public static boolean isNotBlank(String str) {return !isBlank(str);}public static boolean isNotEmpty(String str) {return !isEmpty(str);}public static boolean isUrl(String str) {if (isEmpty(str)) {return false;}str = str.trim();return str.matches("^(http|https)://.+");}public static String convertToDownloadSpeed(BigDecimal bigDecimal, int scale) {BigDecimal unit = new BigDecimal(1);BigDecimal kb = new BigDecimal(1 << 10);BigDecimal mb = new BigDecimal(1 << 10).multiply(kb);BigDecimal gb = new BigDecimal(1 << 10).multiply(mb);BigDecimal tb = new BigDecimal(1 << 10).multiply(gb);BigDecimal pb = new BigDecimal(1 << 10).multiply(tb);BigDecimal eb = new BigDecimal(1 << 10).multiply(pb);if (bigDecimal.divide(kb, scale, BigDecimal.ROUND_HALF_UP).compareTo(unit) < 0) {return bigDecimal.divide(unit, scale, BigDecimal.ROUND_HALF_UP).toString() + " B";} else if (bigDecimal.divide(mb, scale, BigDecimal.ROUND_HALF_UP).compareTo(unit) < 0) {return bigDecimal.divide(kb, scale, BigDecimal.ROUND_HALF_UP).toString() + " KB";} else if (bigDecimal.divide(gb, scale, BigDecimal.ROUND_HALF_UP).compareTo(unit) < 0) {return bigDecimal.divide(mb, scale, BigDecimal.ROUND_HALF_UP).toString() + " MB";} else if (bigDecimal.divide(tb, scale, BigDecimal.ROUND_HALF_UP).compareTo(unit) < 0) {return bigDecimal.divide(gb, scale, BigDecimal.ROUND_HALF_UP).toString() + " GB";} else if (bigDecimal.divide(pb, scale, BigDecimal.ROUND_HALF_UP).compareTo(unit) < 0) {return bigDecimal.divide(tb, scale, BigDecimal.ROUND_HALF_UP).toString() + " TB";} else if (bigDecimal.divide(eb, scale, BigDecimal.ROUND_HALF_UP).compareTo(unit) < 0) {return bigDecimal.divide(pb, scale, BigDecimal.ROUND_HALF_UP).toString() + " PB";}return bigDecimal.divide(eb, scale, BigDecimal.ROUND_HALF_UP).toString() + " EB";}public static byte[] hexStringToByteArray(String s) {int len = s.length();if ((len & 1) == 1) {s = "0" + s;len++;}byte[] data = new byte[len / 2];for (int i = 0; i < len; i += 2) {data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)+ Character.digit(s.charAt(i + 1), 16));}return data;}}
import com.ruoyi.common.utils.m3u8.Constant;
import com.ruoyi.common.utils.m3u8.DownloadListener;
import com.ruoyi.common.utils.m3u8.M3u8DownloadFactory;/*** @author xiehan* @Description M3u8格式转换成MP4格式* @date 2021/10/29 16:44*/
public class M3u8Download {public static void MergeM3u8ToMp4(String M3U8URL,String dir,String fileName) {M3u8DownloadFactory.M3u8Download m3u8Download = M3u8DownloadFactory.getInstance(M3U8URL);//设置生成目录m3u8Download.setDir(dir);//设置视频名称m3u8Download.setFileName(fileName);//设置线程数m3u8Download.setThreadCount(100);//设置重试次数m3u8Download.setRetryCount(100);//设置连接超时时间(单位:毫秒)m3u8Download.setTimeoutMillisecond(10000L);/*设置日志级别可选值:NONE INFO DEBUG ERROR*/m3u8Download.setLogLevel(Constant.INFO);//设置监听器间隔(单位:毫秒)m3u8Download.setInterval(500L);//添加额外请求头/*  Map<String, Object> headersMap = new HashMap<>();headersMap.put("Content-Type", "text/html;charset=utf-8");m3u8Download.addRequestHeaderMap(headersMap);*///添加监听器m3u8Download.addListener(new DownloadListener() {@Overridepublic void start() {System.out.println("开始下载!");}@Overridepublic void process(String downloadUrl, int finished, int sum, float percent) {System.out.println("下载网址:" + downloadUrl + "\t已下载" + finished + "个\t一共" + sum + "个\t已完成" + percent + "%");}@Overridepublic void speed(String speedPerSecond) {System.out.println("下载速度:" + speedPerSecond);}@Overridepublic void end() {System.out.println("下载完毕");}});//开始下载m3u8Download.start();}public static void main(String[] args) {MergeM3u8ToMp4("http://xxxx","H:\\work\\video\\","录屏");}
}

五、集成螺丝钉输出数据库设计文档

1. maven依赖

 <!--mysql连接--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><!--screw [skruː]:螺丝钉--><dependency><groupId>cn.smallbun.screw</groupId><artifactId>screw-core</artifactId><version>1.0.5</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.30</version></dependency><!-- HikariCP:数据库连接池组件 --><dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>3.4.5</version></dependency>

2.工具类

import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;import javax.sql.DataSource;
import java.util.Arrays;
import java.util.Collections;public class CreateDbDesignFileUtil {/*** 数据库路径*/private static final String MYSQL_URL = "jdbc:mysql://localhost:3306/app-serve?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8";/*** mysql用户名*/private static final String MYSQL_USERNAME = "root";/*** mysql密码*/private static final String MYSQL_PASSWORD = "root";/*** mysql驱动类*/private static final String DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver";/*** 文件输出目录*/private static final String FILE_OUTPUT_DIR = "G:\\data";/*** 可以设置 Word 或者 Markdown 格式*/private static final EngineFileType FILE_OUTPUT_TYPE = EngineFileType.WORD;private static final String DOC_FILE_NAME = "java实现数据库表设计文档";private static final String DOC_VERSION = "V1.0.0";private static final String DOC_DESCRIPTION = "数据库表设计描述";public static void main(String[] args) {// 创建 screw 的配置Configuration config = Configuration.builder()// 版本.version(DOC_VERSION)// 描述.description(DOC_DESCRIPTION)// 数据源.dataSource(buildDataSource())// 引擎配置.engineConfig(buildEngineConfig())// 处理配置.produceConfig(buildProcessConfig()).build();// 执行 screw,生成数据库文档new DocumentationExecute(config).execute();}/*** 创建数据源** @return*/private static DataSource buildDataSource() {// 创建 HikariConfig 配置类HikariConfig hikariConfig = new HikariConfig();hikariConfig.setDriverClassName(DRIVER_CLASS_NAME);hikariConfig.setJdbcUrl(MYSQL_URL);hikariConfig.setUsername(MYSQL_USERNAME);hikariConfig.setPassword(MYSQL_PASSWORD);// 设置可以获取 tables remarks 信息hikariConfig.addDataSourceProperty("useInformationSchema", "true");hikariConfig.setMinimumIdle(2);hikariConfig.setMaximumPoolSize(5);// 创建数据源HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);return hikariDataSource;}/*** 创建 screw 的引擎配置** @return*/private static EngineConfig buildEngineConfig() {return EngineConfig.builder()// 生成文件路径.fileOutputDir(FILE_OUTPUT_DIR)// 打开目录.openOutputDir(false)// 文件类型.fileType(FILE_OUTPUT_TYPE)// 文件类型.produceType(EngineTemplateType.freemarker)// 自定义文件名称.fileName(DOC_FILE_NAME).build();}/*** 创建 screw 的处理配置,一般可忽略* 指定生成逻辑、当存在指定表、指定表前缀、指定表后缀时,将生成指定表,其余表不生成、并跳过忽略表配置** @return*/private static ProcessConfig buildProcessConfig() {return ProcessConfig.builder()// 根据名称指定表生成.designatedTableName(Collections.<String>emptyList())// 根据表前缀生成.designatedTablePrefix(Collections.<String>emptyList())// 根据表后缀生成.designatedTableSuffix(Collections.<String>emptyList())// 忽略数据库中address这个表名//.ignoreTableName(Arrays.asList("address"))// 忽略表前缀,就是db1数据库中表名是t_开头的都不生产数据库文档(t_student,t_user这两张表)//.ignoreTablePrefix(Collections.singletonList("t_"))// 忽略表后缀(就是db1数据库中表名是_teacher结尾的都不生产数据库文档:stu_teacher)//.ignoreTableSuffix(Collections.singletonList("_teacher")).build();}
}

Java超实用工具分享,excel填充、m3u8格式合成MP4...相关推荐

  1. 【工具分享】佳能CR2格式的文件怎么转换成jpg?

    [工具分享]佳能CR2格式的文件怎么转换成jpg? 叮嘟!这里是小啊呜的学习课程资料整理.好记性不如烂笔头,今天也是努力进步的一天.一起加油进阶吧! 亲测好用. https://www.iloveim ...

  2. Java 利用POI处理Excel的时间格式

    问题: 用Java的POI处理Excel中的时间单元格,往往得到的格式不是我们想要的.比如: 按上图中方式设置好后,通过以下代码 XSSFRow row = sheet.getRow(0);Cell ...

  3. python视频转化_python实现m3u8格式转换为mp4视频格式

    开发动机:最近用手机QQ浏览器下载了一些视频,视频越来越多,占用了手机内存,于是想把下载的视频传到电脑上保存,可后来发现这些视频都是m3u8格式的,且这个格式的视频都切成了碎片,存在电脑里不方便查看, ...

  4. m3u8转换到mp4 python_python实现m3u8格式转换为mp4视频格式

    开发动机:最近用手机QQ浏览器下载了一些视频,视频越来越多,占用了手机内存,于是想把下载的视频传到电脑上保存,可后来发现这些视频都是m3u8格式的,且这个格式的视频都切成了碎片,存在电脑里不方便查看, ...

  5. 多种Java开发工具分享

    Java软件开发工具介绍: 1.Java Marine API Java Marine API介绍Java Marine API是得到了许多肯定的教育教学软件.只要是有使用过Java Marine A ...

  6. m3u8格式转换mp4软件_怎么把mkv格式转换成mp4?教你转换mkv格式的方法

    我们在工作中经常会获取一些mkv视频格式,但是mkv格式是一种封装格式,很多软件是不能直接打开的.如果需要用pr剪辑视频也是不能直接导入的,一般可以用迅捷视频转换器无损的把mkv格式转换成mp4格式达 ...

  7. m3u8格式转mp4格式方法

    1. 在淘宝直播间按F12打开开发者页面,然后输入.m3u8作为筛选条件 2. 复制m3u8链接 3. 点击添加 4. 点击全部开始 下载的结果就在output文件里

  8. 项目经验分享——Java常用工具类集合 转

    http://blog.csdn.net/xyw591238/article/details/51678525 写在前面 本文涉及的工具类部分是自己编写,另一部分是在项目里收集的.工具类涉及数据库连接 ...

  9. java 兼容excel_Java解析Excel工具类(兼容xls和xlsx)

    依赖jar org.apache.poi poi-ooxml 4.0.1 ExcelUtils.java package javax.utils; import java.io.File; impor ...

  10. java写excel_java写excel文件工具

    之前写过一个用java操作csv与excel文件的工具<操作CSV与EXCEL的工具>,它写入几十.几百行数据都没有问题.但如果写几万行,就有些吃力了,速度太慢.另外也没有抽出工具代码,与 ...

最新文章

  1. CUDA Samples:Vector Add
  2. 【Nodejs篇一】Node js 简介
  3. 复制文件时怎么保留权限
  4. format函数使用matlab,Matlab基本函数-format函数
  5. 文字排版不在单调!可临摹的网页UI设计模板,轻松驾驭!
  6. 一个简单简洁的社交媒体共享菜单
  7. MATLAB实现Otsu算法
  8. 【源码好又多】开源在线教育系统
  9. 我的世界 java错误_我的世界error错误信息 应用程序错误解决方法
  10. python3 pdf转成txt
  11. 特征点匹配(SIFI)
  12. 怎么在html中复制粘贴图片,如何复制其他网页上的文章和图片
  13. ff14服务器建信号,《FF14》服务器人口平均化公告 陆行鸟区关闭角色创建
  14. linux菜鸟入门命令——自我学习
  15. python使用pandas模块介绍以及使用,dataframe结构,Series结构,基本数据操作,DataFrame运算,pandas画图,存储,缺失值处理,离散化,合并
  16. 单叶双曲面MATLAB编程,在matlab中画函数(x^2+y^2)/9-z^2/4=1的旋转单叶双曲面
  17. JSON 的文档数据库 RedisJson 介绍
  18. 关于在Opengl中先平移后旋转和先旋转后平移的效果不一样的原因
  19. 安卓简洁地实现点击ImageView查看大图功能
  20. java开发实战经典第二版网课,成功收获美团,小米offer

热门文章

  1. 新世纪大学英语(第二版)综合教程第一册 Unit 3 (中英翻译和重点单词)
  2. 建立PCI网卡无盘工作站自动上网(转)
  3. 将洛奇的MML乐谱转为beep(蜂鸣器)乐谱
  4. 派森诺细菌完成图标准分析轻松发文
  5. FAI自动部署debian
  6. 微信小程序调试过程中页面加载不出来
  7. AWS亚马逊服务器配置过程
  8. 房子装饰风水有哪些讲究和忌讳
  9. 高数_第3章重积分_三重积分可证明为3个定积分的乘积__很重要
  10. uboot2021.10-nandflash-1.nand_fill_oob