完美解决java截图网页并保存到数据库中预览
公司项目中老板提的需求,说是作为一个亮点,这里下载两个驱动,window和liunx的,在执行的时候通过判断当前系统是什么类型的然后进行调用不同的驱动
正在负责做公司的监控系统模块,主要架构就是分为前台,后台。
后台只是一个springboot程序,会打成jar包放到服务器,让其自启检测,里面是一个个定时任务,会将检测服务器的cpu,端口,数据库等等,然后将检查结果放到数据库里,前台只是负责配置检测项等。
其中有一个检查项就是检查网页是否能正常打开,如果能打开,我们在前台能够预览一下,但是他们不属于一个程序,最初的解决方案就是将请求的结果的源码放到数据库,然后通过html渲染出来,因为有很多静态资源不能显示,所以方案否认。
最终通过phantojs,无头浏览器,执行js脚本进行网页截图,但是图片预览怎么访问呢,后台程序也不是web程序,图片存放的访问路径也不好访问,又不想使用其他存储服务,于是,决定在后台程序中再读取一下图片并转为base64格式存放到数据库,然后前台程序拿到base64之后就可以直接进行解析成图片了。
代码如下
springboot的resources结构,其中pluging就是需要用到的驱动和执行脚本,必须要有
//工具类
package com.open.capacity.yachtar.utils.cutting;
import org.springframework.core.io.ClassPathResource;
import sun.misc.BASE64Encoder;
import java.io.*;
/**
* @create 2023-03-02 10:08:32
*//*
@author ljj
@date 2023-03-02 10:08
*/
public class Utils {
final static String BLANK = " ";
//通过phantomjs将url截取成图片保存
public static String UrlHtmlToImage(String phantomPath, String jsPath, String url, String dest) throws IOException {
Process process = Runtime.getRuntime().exec(phantomPath + BLANK //你的phantomjs.exe路径
+ jsPath + BLANK //就是上文中那段javascript脚本的存放路径
+ url + BLANK //你的目标url地址
+ dest);//你的图片输出路径
InputStream inputStream = process.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
return dest;
}
//将打包后的文件的绝对地址取出来,打成jar包的里面的文件是获取不到绝对路径的
// status=0window,=1liunx
public static String getTargetPathToAbsPath(String targetPath, int status) throws IOException {
//获取文件输入流
InputStream resourceAsStream = Utils.class.getClassLoader().getResourceAsStream("pluging/" + targetPath);
if (status == 0) {//所以我们需要把对应的文件根据操作系统先复制到本地下面,然后使用
//window上的位置
File localFile = new File("c:\\TEMP\\" + targetPath);
if (!localFile.exists()) {
//如果本地没有该文件,则复制一个
FileOutputStream fileOutputStream = new FileOutputStream(localFile);
IOUtils.copy(resourceAsStream, fileOutputStream);
fileOutputStream.close();//必须关闭,否则会报错程序被占用
}
return localFile.getAbsolutePath();//返回本地文件路径
} else {
//liunx
File localFile = new File("/tmp/" + targetPath);
if (!localFile.exists()) {
FileOutputStream fileOutputStream = new FileOutputStream(localFile);
IOUtils.copy(resourceAsStream, fileOutputStream);//复制到liunx的对应路径
fileOutputStream.close();
}
return localFile.getAbsolutePath();
}
}
public static String imageToBase64(String path) {// 将图片文件转化为字节数组字符串,并对其进行Base64编码处理
byte[] data = null;
// 读取图片字节数组
try {
InputStream in = new FileInputStream(path);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
// 对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data);// 返回Base64编码过的字节数组字符串
}
}
/*
截图程序,根据url地址,返回一个base64的图片,
*/
public String cuttingUrlToImage(String url) throws IOException {
String phantomJsPath = "";
String jsPath = "";//截图js脚本
//截屏并保存在相应路径,返回一个图片的路径
String fpath = "";
//根据操作系统
if (CommonUtils.isWindowsOS()) {
//如果是window,则选择合适的phantomjs
phantomJsPath = Utils.getTargetPathToAbsPath("phantomjs.exe", 0);
jsPath = Utils.getTargetPathToAbsPath("jt.js", 0);
//获取js的路径
fpath = "C:\\TEMP\\temp.jpg";
} else {
phantomJsPath = Utils.getTargetPathToAbsPath("phantomjs", 1);
//获取js的路径
jsPath = Utils.getTargetPathToAbsPath("jt.js", 1);
fpath = "/tmp/temp.jpg";
}
if (StringUtils.isEmpty(phantomJsPath)) {
return "操作系统不支持";
}
String s = Utils.UrlHtmlToImage(phantomJsPath , jsPath, url, fpath);
String base64Image = "data:image/jpg;base64," + Utils.imageToBase64(s);//根据图片路径将对应的图片转为base64
File file = new File(fpath);//生成一个临时的图片,并转为base64,然后把图片删除
if (file.exists()) {
file.delete();
}
return base64Image;
}
//js脚本
var page = require('webpage').create();
system = require('system');
//var url = 'http://yule.club.sohu.com/gifttrade/thread/2m2efbrpfui';
var address;
var filePath;
if (system.args.length == 1) {
phantom.exit();
} else {
adress = system.args[1];
page.open(adress, function (status) {
if (status != "success") {
console.log('FAIL to load the address');
phantom.exit();
}
page.viewportSize = {//截图大小
width: 1300,
height: 800
};
/*
page.evaluate(function () {
//此函数在目标页面执行的,上下文环境非本phantomjs,所以不能用到这个js中其他变量
window.scrollTo(0, 10000);//滚动到底部
//window.document.body.scrollTop = document.body.scrollHeight;
/*
window.setTimeout(function(){
var plist = document.querySelectorAll("a");
var len = plist.length;
while(len)
{
len--;
var el = plist[len];
el.style.border = "1px solid red";
}
},5000);
});*/
// page.clipRect = {
// top: 0,
// left: 0,
// width: 1500, //宽度
// height: 800, // 高度
// }
filePath = system.args[2];
window.setTimeout(function () {
//在本地生成截图
page.render(filePath);
// console.log(page.content);
console.log('render success...')
phantom.exit();
}, 2000 + 1000);
});
}
测试结果如下
String photo="D:\\分类\\demo\\src\\main\\resources\\phantomjs.exe"; //驱动所在路径
String jsPath="D:\\分类\\demo\\src\\main\\resources\\jt.js"; //js脚本所在路径
String url="https://www.baidu.com"; //访问的url
String dest="D:\\分类\\demo\\src\\main\\resources\\a.png"; //保存图片的位置
String s = UrlHtmlToImage(photo, jsPath, url,dest); //获取截图的保存的位置
System.out.println(s);
调用转换成base64方法
String base64 = imageToBase64(image);
System.out.println(base64);
说明
将base64字符串保存到数据库中对应字段即可,然后前端进行渲染。若有oss存储,则截图图片直接上传到oss服务,然后使用oss路径存储到对应字段中更好。