JSP + ZXing で Web サイトに QRCode を表示してみる簡単なサンプル

JSP サイトを管理している知り合いが「QRCode を表示したい」と言っていたので、週末にちょっと試してみました。

Java だと OSS (Apache License 2.0) の [ZXing](https://github.com/zxing/zxing) がよく使われているみたいなので、JSP Web サイトに組み込んだメモとなります。

# 実際の Web 画面

以下のような入力画面で QRCode に指定したいURLを入力して「Submit」すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/4bda5e20-b3b5-b1d1-5933-5930239b7997.png)
以下のように URL を QRCode に変換して表示します。「Back」で元ページに戻ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/87abe81a-5140-2c69-cccc-8a4b28d3f4ce.png)

# 開発環境

今回利用した開発環境は素の Eclipse 2020-09 (4.17.0) の Java EE パースペクティブで、サーバーに Tomcat v8.5 を追加指定したものです.

赤枠が今回のために追加、作成したファイルになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193519/53ca04ef-8ff7-09b9-2fe1-4c2d93e1d419.png)
``WebContent/WEB-INF/lib`` には関連する jar ファイルをコピーしてあります。

[ZXing](https://github.com/zxing/zxing) リポジトリに jar が見当たらないので、MVN Repository の [ZXing Core](https://mvnrepository.com/artifact/com.google.zxing/core) や [ZXing Java SE Extensions](https://mvnrepository.com/artifact/com.google.zxing/javase) などから入手すると良いでしょう。

``jaxb-api-2.3.1.jar`` は　Java8 などの環境では必要ないかもしれません。エラーが出るようでしたら、やはり MVN Repository の [JAXB API](https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api) などから入手して配置してください。

# 実際のコード

## 入力ページ

入力ページは通常の html ページです。[Bootstrap のテンプレート](https://getbootstrap.com/docs/4.5/getting-started/introduction/) にフォーム要素を追加しただけの、非常にシンプルなものです。

```html:WebContent/index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <title>Simple QR sample with JSP</title>
  </head>
  <body>

<div class="container">
    <h2>Simple QR sample with JSP</h2>
    <form action="/test01/QRCode.jsp"> <!-- 遷移先の JSP ページ -->
        <div class="form-group">
            <label for="i_url">Target URL</label>
            <input type="text" class="form-control" id="i_url" name="i_url">
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
    </form>
</div>

<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
  </body>
</html>
```

## JSP ページ

さてこちらは、入力を受けて QRCode を生成している部分です。ZXing のサンプルを、そのまま JSP 化したので、素直なコードだと思います。

```jsp:WebContent/QRCode.jsp
<%@ page import="com.google.zxing.qrcode.QRCodeWriter" %>
<%@ page import="com.google.zxing.common.BitMatrix" %>
<%@ page import="com.google.zxing.BarcodeFormat" %>
<%@ page import="com.google.zxing.client.j2se.MatrixToImageWriter" %>
<%@ page import="java.awt.image.BufferedImage" %>
<%@ page import="test01.BufferedImageUtil" %>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
    <title>Output of "Simple QR sample with JSP"</title>
</head>
<body>

<%
String i_url = request.getParameter("i_url");
QRCodeWriter qrWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrWriter.encode(i_url, BarcodeFormat.QR_CODE, 300, 300);
BufferedImage bImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
%>

<div class="container">
    <h2>Output of "Simple QR sample with JSP"</h2>
    <p>Target URL: <%= i_url %></p>
    <img src="<%= BufferedImageUtil.convert2DataURI(bImage, "png") %>"/>
    <form action="/test01/">
        <button type="submit" class="btn btn-primary">Back</button>
    </form>
</div>

<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
</body>
</html>
```

## BufferedImageUtil クラス

今回、ポイントとなるのは ``BufferedImageUtil`` クラスです。

ZXing の Java サンプルを探してみたのですが、いったんファイルに出力する例が多くヒットしました。しかし Web サービスの場合、できればテンポラリファイル作成は避けたいところです。

というわけで ``convert2DataURI`` という、BufferedImage オブジェクトから Data URI をダイレクトに生成する簡単な関数を用意してみました。

```Java:test01.BufferedImageUtil.java
package test01;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.xml.bind.DatatypeConverter;

public class BufferedImageUtil {
	public static String convert2DataURI(BufferedImage bi, String type) throws IOException {
		if (bi == null || type == null) {
			return ""; // TODO: Default error image
		}
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ImageIO.write(bi, type, baos);
		return "data:image/" + type + ";base64," + DatatypeConverter.printBase64Binary(baos.toByteArray());
	}
}
```

エラー処理をサボっています。実際に使う際には、エラー画像の Data URI をあらかじめ用意しておいて、問題発生時にはそれを返してあげるのも良いとおもいます。

# ライセンス

この投稿に含まれる私の作成した全てのコードは [Creative Commons Zero](https://creativecommons.org/publicdomain/zero/1.0/deed.ja) ライセンスとします。自由にお使いください。

# Enjoy!

以上、JSP で作成した Web サイトに、QRCode 表示の実装を試してみました。これをベースに、いろいろ機能を追加して遊んでみてください。

ではまた！