问答平台(7),生成长图

wkhtmltopdf

  • wkhtmltopdf url file
  • wkhtmltoimage url file
    1
    2
    3
    wkhtmltopdf https://www.nowcoder.com d:/work/data/wk-pdfs/1.pdf
    wkhtmltoimage https://www.nowcoder.com d:/work/data/wk-images/1.png
    wkhtmltoimage --quality 75 https://www.nowcoder.com d:/work/data/wk-images/2.png

java

  • Runtime().getRuntime().exec()

测试类

  • WkTests: 新增
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class WkTests {

    public static void main(String[] args) {
    String cmd = "d:/work/wkhtmltopdf/bin/wkhtmltoimage --quality 75 https://www.nowcoder.com d:/work/data/wk-images/3.png";
    try {
    Runtime.getRuntime().exec(cmd);
    System.out.println("ok");
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

项目开发

配置文件

  • application-develop.properties: 添加内容
    1
    2
    3
    # wk
    wk.image.command=d:/work/wkhtmltopdf/bin/wkhtmltoimage
    wk.image.storage=d:/work/data/wk-images

config

  • WkConfig: 新增
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @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);
    }
    }
    }

表现层

  • ShareController: 新增
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    @Controller
    public class ShareController implements CommunityConstant {

    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;

    @RequestMapping(path = "/share", method = RequestMethod.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);

    return CommunityUtil.getJSONString(0, null, map);
    }

    // 获取长图
    @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());
    }
    }
    }

消费事件

  • EventConsumer: 添加
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    @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");
    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.info("生成长图失败: " + e.getMessage());
    }
    }

结果展示

生成长图-图示
获取长图-图示
1
2
生成长图
获取长图

参考资料


问答平台(7),生成长图
https://lcf163.github.io/2020/06/18/问答平台(7),生成长图/
作者
乘风的小站
发布于
2020年6月18日
许可协议