1.导入maven依赖如下:
<!-- Java工具类包 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-http</artifactId> <version>4.0.10</version> </dependency> <!-- 生成二维码 --> <dependency> <groupId>com.google.zxing</groupId> <artifactId>core</artifactId> <version>3.3.2</version> </dependency>
hutool是一个工具类包,封装了大量java开发常用的工具类.
2.工具类:
package com.baidu.Util; import cn.hutool.core.util.ImageUtil; import com.google.zxing.*; import com.google.zxing.common.BitMatrix; import com.google.zxing.common.HybridBinarizer; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; public class QrCodeUtil { private static final int BLACK = -16777216; private static final int WHITE = -1; public QrCodeUtil() { } public static byte[] generatePng(String content, int width, int height) { ByteArrayOutputStream out = new ByteArrayOutputStream(); generate(content, width, height, "png", out); return out.toByteArray(); } public static File generate(String content, int width, int height, File targetFile) { BufferedImage image = generate(content, width, height); ImageUtil.write(image, targetFile); return targetFile; } public static void generate(String content, int width, int height, String imageType, OutputStream out) { BufferedImage image = generate(content, width, height); ImageUtil.write(image, imageType, out); } public static BufferedImage generate(String content, int width, int height) { BitMatrix bitMatrix = encode(content, width, height); return toImage(bitMatrix); } public static BitMatrix encode(String content, int width, int height) { return encode(content, BarcodeFormat.QR_CODE, width, height); } public static BitMatrix encode(String content, BarcodeFormat format, int width, int height) { MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); HashMap<EncodeHintType, Object> hints = new HashMap(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); try { BitMatrix bitMatrix = multiFormatWriter.encode(content, format, width, height, hints); return bitMatrix; } catch (WriterException var7) { throw new QrCodeException(var7); } } public static String decode(InputStream qrCodeInputstream) { return decode((Image)ImageUtil.read(qrCodeInputstream)); } public static String decode(File qrCodeFile) { return decode((Image)ImageUtil.read(qrCodeFile)); } public static String decode(Image image) { MultiFormatReader formatReader = new MultiFormatReader(); LuminanceSource source = new BufferedImageLuminanceSource(ImageUtil.toBufferedImage(image)); Binarizer binarizer = new HybridBinarizer(source); BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer); HashMap<DecodeHintType, Object> hints = new HashMap(); hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); Result result; try { result = formatReader.decode(binaryBitmap, hints); } catch (NotFoundException var8) { throw new QrCodeException(var8); } return result.getText(); } public static BufferedImage toImage(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); BufferedImage image = new BufferedImage(width, height, 1); for(int x = 0; x < width; ++x) { for(int y = 0; y < height; ++y) { image.setRGB(x, y, matrix.get(x, y)?-16777216:-1); } } return image; } }
package com.baidu.Util; import com.google.zxing.LuminanceSource; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; public final class BufferedImageLuminanceSource extends LuminanceSource { private final BufferedImage image; private final int left; private final int top; public BufferedImageLuminanceSource(BufferedImage image) { this(image, 0, 0, image.getWidth(), image.getHeight()); } public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) { super(width, height); int sourceWidth = image.getWidth(); int sourceHeight = image.getHeight(); if(left + width <= sourceWidth && top + height <= sourceHeight) { for(int y = top; y < top + height; ++y) { for(int x = left; x < left + width; ++x) { if((image.getRGB(x, y) & -16777216) == 0) { image.setRGB(x, y, -1); } } } this.image = new BufferedImage(sourceWidth, sourceHeight, 10); this.image.getGraphics().drawImage(image, 0, 0, (ImageObserver)null); this.left = left; this.top = top; } else { throw new IllegalArgumentException("Crop rectangle does not fit within image data."); } } public byte[] getRow(int y, byte[] row) { if(y >= 0 && y < this.getHeight()) { int width = this.getWidth(); if(row == null || row.length < width) { row = new byte[width]; } this.image.getRaster().getDataElements(this.left, this.top + y, width, 1, row); return row; } else { throw new IllegalArgumentException("Requested row is outside the image: " + y); } } public byte[] getMatrix() { int width = this.getWidth(); int height = this.getHeight(); int area = width * height; byte[] matrix = new byte[area]; this.image.getRaster().getDataElements(this.left, this.top, width, height, matrix); return matrix; } public boolean isCropSupported() { return true; } public LuminanceSource crop(int left, int top, int width, int height) { return new BufferedImageLuminanceSource(this.image, this.left + left, this.top + top, width, height); } public boolean isRotateSupported() { return true; } public LuminanceSource rotateCounterClockwise() { int sourceWidth = this.image.getWidth(); int sourceHeight = this.image.getHeight(); AffineTransform transform = new AffineTransform(0.0D, -1.0D, 1.0D, 0.0D, 0.0D, (double)sourceWidth); BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, 10); Graphics2D g = rotatedImage.createGraphics(); g.drawImage(this.image, transform, (ImageObserver)null); g.dispose(); int width = this.getWidth(); return new BufferedImageLuminanceSource(rotatedImage, this.top, sourceWidth - (this.left + width), this.getHeight(), width); } }
package com.baidu.Util; import cn.hutool.core.exceptions.ExceptionUtil; import cn.hutool.core.util.StrUtil; public class QrCodeException extends RuntimeException { private static final long serialVersionUID = 469027218631691847L; public QrCodeException(Throwable e) { super(ExceptionUtil.getMessage(e), e); } public QrCodeException(String message) { super(message); } public QrCodeException(String messageTemplate, Object... params) { super(StrUtil.format(messageTemplate, params)); } public QrCodeException(String message, Throwable throwable) { super(message, throwable); } public QrCodeException(Throwable throwable, String messageTemplate, Object... params) { super(StrUtil.format(messageTemplate, params), throwable); } }
package com.baidu.Util; import java.math.BigDecimal; import java.text.DecimalFormat; import java.util.regex.Pattern; public final strictfp class MathUtil { private MathUtil() { } // 默认运算精度 private static int DEF_SCALE = 10; /** * 提供数据类型转换为BigDecimal * * @param object 原始数据 * @return BigDecimal */ public static final BigDecimal bigDecimal(Object object) { if (object == null) { throw new NullPointerException(); } BigDecimal result; try { result = new BigDecimal(String.valueOf(object).replaceAll(",", "")); } catch (NumberFormatException e) { throw new NumberFormatException("Please give me a numeral.Not " + object); } return result; } /** * 提供(相对)精确的加法运算。 * * @param num1 被加数 * @param num2 加数 * @return 两个参数的和 */ public static final Double add(Object num1, Object num2) { BigDecimal result = bigDecimal(num1).add(bigDecimal(num2)); return result.setScale(DEF_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue(); } /** * 提供(相对)精确的减法运算。 * * @param num1 被减数 * @param num2 减数 * @return 两个参数的差 */ public static final Double subtract(Object num1, Object num2) { BigDecimal result = bigDecimal(num1).subtract(bigDecimal(num2)); return result.setScale(DEF_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue(); } /** * 提供(相对)精确的乘法运算。 * * @param num1 被乘数 * @param num2 乘数 * @return 两个参数的积 */ public static final Double multiply(Object num1, Object num2) { BigDecimal result = bigDecimal(num1).multiply(bigDecimal(num2)); return result.setScale(DEF_SCALE, BigDecimal.ROUND_HALF_UP).doubleValue(); } /** * 提供(相对)精确的除法运算,当发生除不尽的情况时,精度为10位,以后的数字四舍五入。 * * @param num1 被除数 * @param num2 除数 * @return 两个参数的商 */ public static final Double divide(Object num1, Object num2) { return divide(num1, num2, DEF_SCALE); } /** * 提供(相对)精确的除法运算。 当发生除不尽的情况时,由scale参数指定精度,以后的数字四舍五入。 * * @param num1 被除数 * @param num2 除数 * @param scale 表示表示需要精确到小数点以后几位。 * @return 两个参数的商 */ public static final Double divide(Object num1, Object num2, Integer scale) { if (scale == null) { scale = DEF_SCALE; } num2 = num2 == null || Math.abs(new Double(num2.toString())) == 0 ? 1 : num2; if (scale < 0) { throw new IllegalArgumentException("The scale must be a positive integer or zero"); } BigDecimal result = bigDecimal(num1).divide(bigDecimal(num2), scale, BigDecimal.ROUND_HALF_UP); return result.doubleValue(); } /** * 提供精确的小数位四舍五入处理。 * * @param num 需要四舍五入的数字 * @param scale 小数点后保留几位 * @return 四舍五入后的结果 */ public static final Double round(Object num, int scale) { if (scale < 0) { throw new IllegalArgumentException("The scale must be a positive integer or zero"); } BigDecimal result = bigDecimal(num).divide(bigDecimal("1"), scale, BigDecimal.ROUND_HALF_UP); return result.doubleValue(); } /** * 获取start到end区间的随机数,不包含start+end * * @param start * @param end * @return */ public static final BigDecimal getRandom(int start, int end) { return new BigDecimal(start + Math.random() * end); } /** * 格式化 * * @param obj * @param pattern * @return */ public static final String format(Object obj, String pattern) { if (obj == null) { return null; } if (pattern == null || "".equals(pattern)) { pattern = "#"; } DecimalFormat format = new DecimalFormat(pattern); return format.format(bigDecimal(obj)); } /** 是否数字 */ public static final boolean isNumber(Object object) { Pattern pattern = Pattern.compile("\\d+(.\\d+)?$"); return pattern.matcher(object.toString()).matches(); } public static final void main(String[] args) { System.out.println(add(1.000001, 2.10)); }
QrCodeUtil是生成二维码的核心工具类,需要引入QrCodeException异常类和BufferedImageLuminanceSource资源类;MathUtil是封装的一些简单计算的工具类,主要是用来计算二维码在照片上的宽高和位置
3.代码部分:
package com.baidu.controller; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ImageUtil; import cn.hutool.core.util.URLUtil; import com.baidu.Util.MathUtil; import com.baidu.Util.QrCodeUtil; import com.baidu.entity.User; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; /** * Created by dangsl on 2018/4/21. */ @RequestMapping("image") @Controller public class QrCodeController { @RequestMapping(value = "getImage",method = RequestMethod.GET) public ResponseEntity<byte[]> getImage(){ //要转化二维码的链接 User user = new User(); user.setId("960832482708553728"); user.setNickName("祭司"); String url = "http://xxxxxxxxxx/user/login.html?recommendId=" + user.getId(); //微信昵称 String userName = user.getNickName(); //最终图片宽高 int w = 520,h = 853; //二维码高度 int codeW = MathUtil.divide(w,3).intValue(); //生成二维码 BufferedImage generateCode = QrCodeUtil.generate(url, codeW, codeW); //获取背景图片 BufferedImage backgroundImage = ImageUtil.read(URLUtil.url("http://XXXXXXXXXXX/976295506168774656")); //将二维码当作图片水印放置在背景图片上 BufferedImage pressImage = ImageUtil.pressImage(backgroundImage, generateCode, 0, codeW-40, 0.9f); //将“我是 ”和微信昵称当作文字水印放置在背景图片上 BufferedImage pressText = ImageUtil.pressText(pressImage, "我是 "+userName, Color.BLACK, new Font("宋体", 0, 27), 0, codeW+112, 0.9f); //输出结果 ByteArrayOutputStream os = new ByteArrayOutputStream(); ImageUtil.write(pressText, FileUtil.file("E:\\weixin"+"/qrcode.png")); // 保存到本地指定目录 ImageUtil.writeJpg(pressText,os); byte[] bytes = os.toByteArray(); // 输出到前台展示 HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.IMAGE_PNG); return new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK); } }