生成长图 通常在app分享的时候才有,
生成长图 手段通常有两种,
客户端实现,app当前界面截图,
服务端实现, 服务端用html做和app界面一模一样的模板,然后读取模板内容生成长图。
因为web项目没有app,本节只探讨在服务端怎么利用html模板生成长图。
把模板转换为图片,需要用到
wk html topdf工具
语法:wkhtmltopdf 模板访问路径 file(pdf存放位置)
下载安装后,将此路径 添加到环境变量
新建几个目录:
导出命令:
导出后:
接下来导出图片:
C:\Users\Administrator>wkhtmltopdf https://www.baidu.com E:/java/wkhtmltox/wk-pdfs/1.pdf
Loading pages (1/6)
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done
通常对图片进行压缩使其变小,
一般压缩75%
C:\Users\Administrator>wkhtmltoimage --quality 75 https://www.baidu.com E:/java/wkhtmltox/wk-images/2.png
接下来通过java来访问
新建WkTests
package com.nowcoder.community;
import java.io.IOException;
public class WkTests {
public static void main(String[] args) {
String cmd = "E:/java/wkhtmltox/wkhtmltopdf/bin/wkhtmltoimage --quality 75 https://www.nowcoder.com E:/java/wkhtmltox/wk-images/3.png";
try {
Runtime.getRuntime().exec(cmd);
System.out.println("ok.");///没有异常则输出ok
} catch (IOException e) {
e.printStackTrace();
}
}
}
在application Properties中
# wk
wk.image.command=E:/java/wkhtmltox/wkhtmltopdf/bin/wkhtmltoimage
wk.image.storage=E:/java/wkhtmltox/wk-images
先删掉 wk-images
新建WkConfig
@Configuration
public class WkConfig {
//Wk和spring没关系,所以无需创建bean
private static final Logger logger = LoggerFactory.getLogger(WkConfig.class);
@Value("${wk.image.storage}")//注入路径给wkImageStorage
private String wkImageStorage;
@PostConstruct//初始化
public void init() {//初始化方法
// 创建WK图片目录
File file = new File(wkImageStorage);//file是目录
if (!file.exists()) {//判断其是否存在
file.mkdir();//若不存在,则创建路径
logger.info("创建WK图片目录: " + wkImageStorage);//记录日志
}
}
}
接下来新建ShareController,处理前端的请求,在该请求内生成图片,生成图片后,生成一个请求允许访问图片。
@Controller
public class ShareController implements CommunityConstant {
//前端一访问就生成图片,生成图片时间较长,所以一定是异步的方式,controller只需把事件丢给卡夫卡,后续用卡夫卡异步实现,而不是在这儿等着
private static final Logger logger = LoggerFactory.getLogger(ShareController.class);
@Autowired
private EventProducer eventProducer;//因为要用卡夫卡
@Value("${community.path.domain}")
private String domain;//应用程序域名
@Value("${server.servlet.context-path}")
private String contextPath;//项目访问名
@Value("${wk.image.storage}")
private String wkImageStorage;//图片存放位置
@Value("${qiniu.bucket.share.url}")
private String shareBucketUrl;
@RequestMapping(path = "/share", method = RequestMethod.GET)//分享请求,方式GET
@ResponseBody//异步
public String share(String htmlUrl) {
// 文件名(随机,每次都要变,不然很容易重名)
String fileName = CommunityUtil.generateUUID();
// 异步生成长图
Event event = new Event()
.setTopic(TOPIC_SHARE)
.setData("htmlUrl", htmlUrl)
.setData("fileName", fileName)
.setData("suffix", ".png");
eventProducer.fireEvent(event);
// 生成长图以后,如何访问呢---返回访问路径
Map<String, Object> map = new HashMap<>();
// map.put("shareUrl", domain + contextPath + "/share/image/" + fileName);//domain项目域名
map.put("shareUrl", shareBucketUrl + "/" + fileName);
return CommunityUtil.getJSONString(0, null, map);
}
触发以后,在EventConsumer中进行消费
@Value("${wk.image.command}")
private String wkImageCommand;
@Value("${wk.image.storage}")
private String wkImageStorage;
// 消费分享事件
@KafkaListener(topics = TOPIC_SHARE)
public void handleShareMessage(ConsumerRecord record) {
if (record == null || record.value() == null) {
logger.error("消息的内容为空!");
return;
}
Event event = JSONObject.parseObject(record.value().toString(), Event.class);
if (event == null) {
logger.error("消息格式错误!");
return;
}
String htmlUrl = (String) event.getData().get("htmlUrl");//event.getData()是map
String fileName = (String) event.getData().get("fileName");
String suffix = (String) event.getData().get("suffix");//后缀
//利用上述三个,把命令拼出来
String cmd = wkImageCommand + " --quality 75 "
+ htmlUrl + " " + wkImageStorage + "/" + fileName + suffix;
try {
Runtime.getRuntime().exec(cmd);//传入cmd,执行
logger.info("生成长图成功: " + cmd);
} catch (IOException e) {
logger.error("生成长图失败: " + e.getMessage());
}
在ShareController中
// 上面只是生成长图,下面获取长图
@RequestMapping(path = "/share/image/{fileName}", method = RequestMethod.GET)
public void getShareImage(@PathVariable("fileName") String fileName, HttpServletResponse response) {
if (StringUtils.isBlank(fileName)) {//参数为空,抛出异常
throw new IllegalArgumentException("文件名不能为空!");
}
response.setContentType("image/png");//image表示输出的图片,png表示输出的格式
File file = new File(wkImageStorage + "/" + fileName + ".png");//实例化file
try {
OutputStream os = response.getOutputStream();
FileInputStream fis = new FileInputStream(file);//把文件转为输入流
byte[] buffer = new byte[1024];//缓冲区
int b = 0;//游标
while ((b = fis.read(buffer)) != -1) {//!= -1表示读到了数据
os.write(buffer, 0, b);
}
} catch (IOException e) {
logger.error("获取长图失败: " + e.getMessage());
}
}
测试: