在二维码已不是稀奇事物的今天,你的应用中有大概率会有产生二维码的需求。最近因为开始在做以太坊相关的开发,其中就有一个非常俗的需求:用户的钱包地址需要用二维码展示。
生成
在Java界,产生二维码用Google的ZXing即可。其本身没啥好说的,因为用起来很简单。在应用中简单封装一下(Groovy代码):
class QRCodeUtil {
static void writeToStream(String walletAddress, OutputStream stream) {
BitMatrix bitMatrix = new MultiFormatWriter().encode(walletAddress, BarcodeFormat.QR_CODE, 500, 500)
MatrixToImageWriter.writeToStream(bitMatrix, 'png', stream)
}
}
这样就可以在Controller中去调用了(Grails Controller):
def printWallet() {
String wallet = params.wallet
if (!wallet) {
render status: BAD_REQUEST
return
}
PipedInputStream inputStream = new PipedInputStream()
try {
inputStream.withStream {
PipedOutputStream outputStream = new PipedOutputStream(inputStream)
outputStream.withStream {
QRCodeUtil.writeToStream(wallet, outputStream)
}
render file: inputStream, contentType: 'image/png'
}
} catch (Exception e) {
log.error("Render QR image error: ", e)
respond([message: '无法生成钱包二维码'], status: INTERNAL_SERVER_ERROR)
}
}
请注意,这里面使用了PipedInputStream/PipedOutputStream,因为这样可以直接将两个流对接,更顺畅的完成图片的输出。
前端使用也很简单,在页面中,直接使用:< img src='地址' >就行了。
测试
生成代码其实已经是烂大街了,这里只是用grails代码重新诠释了一下而已。但是关于二维码的测试,好像就没有那么多的例子了。在这里,我将展示一下我们的做法。
本质上就是利用ZXing的类读出图片里的字符串,下面是我们的测试工具类(Groovy):
static String readQRCode(byte[] imageBytes) {
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(
new BufferedImageLuminanceSource(ImageIO.read(new ByteArrayInputStream(imageBytes)))))
Map<DecodeHintType, ?> hints = new HashMap<>()
hints.put(DecodeHintType.PURE_BARCODE, true)
Result qrCodeResult = new MultiFormatReader().decode(binaryBitmap, hints)
return qrCodeResult.getText()
}
然后,在Grails的functional测试中实现一个端到端的测试(Spock Specification):
void "能够生成钱包二维码"() {
setup:
RestBuilder rest = new RestBuilder()
when:
String jwt = TestUtils.login(serverPort, 'user', 'user')
response = rest.get("http://localhost:${serverPort}/地址") {
header('Authorization', "Bearer ${jwt}")
accept(byte[].class, 'image/*')
}
then:
response.status == 200
response.headers.getContentType() == MediaType.valueOf('image/png;charset=utf-8')
TestUtils.readQRCode(response.body) == '……'
}
基于Grails的RestBuilder可以很方便的完API测试,这里需要注意的就是accept头的设置。如此,关于二维码的测试就完成了。
附:感谢冯宇同学提供的支持和帮助。
网友评论