文章目录
参考牛客网高级项目教程
功能需求
- 1.使用
wkhtmltopdf
软件,可以实现将指定的url网页内容转为pdf文件或图片文件 - 2.熟悉使用spring客户端操作软件,分享长图,为今后社区的分享功能做准备
- 3.kafak应用的第三个场景:将请求放进kafka,异步制成长图保存到制定文件夹中
一、wkhtmltopdf
基本操作
1. 下载安装,配置环境变量
2. 默认不会创建文件夹,先创建生成文件的位置
3. 在cmd中输入命令,测试
生成pdf文件
wkhtmltopdf https://www.nowcoder.com E:/javaWeb/data/wk-pdf/1.pdf
生成压缩图片
wkhtmltoimage --quality 75 https://www.nowcoder.com E:/javaWeb/data/wk-image/1.png
二、使用java操作
1. 直接操作命名
Runtime.getRuntime().exec(cmd)
- 异步加载生成图片
public class WkTests {
public static void main(String[] args) {
String cmd = "E:/javaWeb/wkhtmltopdf/bin/wkhtmltoimage --quality 75 https://www.nowcoder.com E:/javaWeb/data/wk-image/2.png";
try {
Runtime.getRuntime().exec(cmd);
System.out.println("ok.");
} catch (IOException e) {
e.printStackTrace();
}
}
}
ok.
2. Spring中配置路径
自定义配置-今后迁移到linux系统方便修改
# wk
wk.image.command=E:/javaWeb/wkhtmltopdf/bin/wkhtmltoimage
wk.image.storage=E:/javaWeb/data/wk-image
写一个可以自动生成文件夹的配置类
- 这样,如果没有建文件夹,程序可以自动创建文件夹
file.mkdir()
-创建文件夹
@Configuration
public class WkConfig {
private static final Logger logger = LoggerFactory.getLogger(WkConfig.class);
@Value("${wk.image.storage}")
private String wkImageStorage;
@PostConstruct
public void init() {
// 创建WK图片目录
File file = new File(wkImageStorage);
if (!file.exists()) {
file.mkdir();
logger.info("创建WK图片目录: " + wkImageStorage);
}
}
}
三、使用服务端请求分享生成长图
1. 在controller层处理分享请求
- 有前面的命令可知,软件启动命名和文件保存路径均已经配置
- 自定义的是:动态访问的html的url,以及制作成长图的文件名和后缀名
@Controller
public class ShareController implements CommunityConstant {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
EventProducer eventProducer;
@Value("${community.path.domain}")
String domain;
@Value("${server.servlet.context-path}")
String contextPath;
@Value("${wk.image.storage}")
String imageStorage;
/**
* 处理分享的异步请求-将请求处理放进kafka,异步消费制成图片
* @param htmlUrl 域名后输入要分享的网页url-将此网页制成长图
* @return 返回带有完整访问路径的json信息
*/
@RequestMapping(path = "/share", method = RequestMethod.GET)
@ResponseBody
public String share(String htmlUrl) {
// 1.图片名称随机-防止命名重复冲突
String fileName = CommunityUtil.generateUUID();
// 2.将制作长图的信息和命令发布到kafka消息队列中
Event event = new Event()
.setTopic(TOPIC_SHARE)
.setData("htmlUrl", htmlUrl)
.setData("fileName", fileName)
.setData("suffix", ".png");
eventProducer.sendEvent(event);
// 3. 将访问的路径用json格式返回到页面,以便可以点击显示制作的长图
Map<String, Object> map = new HashMap<>();
map.put("shareUrl", domain + contextPath + "/share/image/" + fileName);
return CommunityUtil.getJSONString(0, null, map);
}
}
2. 定义kafak消费事件
- 获取消息中的数据和配置文件的启动命令、文件夹保存路径,拼接操作的命令cmd
/**
* 消费分享制成长图的消息-将指定url制成长图保存到指定文件中
*/
@KafkaListener(topics = TOPIC_SHARE)
public void handleShareMessage(ConsumerRecord record) {
// 1.边界条件:先检查有无取到消息
if (record == null || record.value() == null) {
logger.error("消息的内容为空!");
return;
}
// 2.将拿到的消息恢复成Object类型,方便操作
Event event = JSONObject.parseObject(record.value().toString(), Event.class);
if(event == null) {
logger.error("消息的格式错了!");
return;
}
// 3.将访问的网页url制作长图保存到指定文件中
String htmlUrl = (String) event.getData().get("htmlUrl");
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);
logger.info("生成长图成功: " + cmd);
} catch (IOException e) {
logger.error("生成长图失败: " + e.getMessage());
}
}
测试结果
3. Controller获取长图的请求
/**
* 显示长图的请求
* @param fileName 图片的文件名
* @param response 服务器响应中向浏览器写图片
*/
@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");
File file = new File(wkImageStorage + "/" + fileName + ".png");
try {
// 边读取图片边向浏览器写入图片
OutputStream os = response.getOutputStream();
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
int b = 0;
while ((b = fis.read(buffer)) != -1) {
os.write(buffer, 0, b);
}
} catch (IOException e) {
logger.error("获取长图失败: " + e.getMessage());
}
}