引入相关依赖:
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.2.1</version>
</dependency>
工具类:
package com.jtj.qrcode.util;
import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @Classname CodeUtil
* @Description TODO 二维码工具类
* @Date 2019/7/10 19:49
* @Created by JTJ
*/
public class CodeUtil {
public static int width = 600;
public static int height = 600;
public static String format = "png";
public static String contents = "默认内容";
public static String defaultFilePath = "";
public static String[] checkList = new String[] {"png","jpg","gif","jepg"};
/**
* @Title: createLogoAndCode
* @Desc: 创建二维码
* @param logo contents path
* @return
*/
public static String createLogoAndCode(File logo, String contents, String path) {
String result = "success";
if (contents!=null) {
CodeUtil.contents = contents;
}
if(!checkFormat(logo)) {
return "logo文件出错!";
}
// 生成二维码
try {
BitMatrix bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height,
setCodeParams());
if(path!=null) {
//生成文件路径
Path filePath = new File(savePalce(path)).toPath();
MatrixToImageWriter.writeToPath(bitMatrix, format, filePath);
}
MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF);
/* 添加logo图片
* 问题:生成二维码正常,生成带logo的二维码logo变成黑白
* 原因:MatrixToImageConfig默认黑白,需要设置BLACK、WHITE
* 解决:https://ququjioulai.iteye.com/blog/2254382
*/
//判断是否需要logo
if(logo!=null) {
BufferedImage bufferedImage = groupImage(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig),logo);
//生成图片文件
ImageIO.write(bufferedImage, format, new File(defaultFilePath));
}else {
ImageIO.write(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), format, new File(defaultFilePath));
}
} catch (Exception e) {
result = "生成二维码出错!"+e.toString();
}
return result;
}
/**
* 绘制logo图片
* @param matrixImage
* @param logoFile
* @return
* @throws IOException
*/
public static BufferedImage groupImage(BufferedImage matrixImage, File logoFile) throws IOException {
//先读取二维码图片
Graphics2D g = matrixImage.createGraphics();
//再读取logo图片
BufferedImage logoImage = ImageIO.read(logoFile);
//设置logo大小,太大,会覆盖二维码,此处20%
int logoWidth = logoImage.getWidth() > matrixImage.getWidth()*2 /10 ? (matrixImage.getWidth()*2 /10) : logoImage.getWidth();
int logoHeight = logoImage.getHeight() > matrixImage.getHeight()*2 /10 ? (matrixImage.getHeight()*2 /10) : logoImage.getHeight();
//设置logo图片放置位置 放在中心
int x = (matrixImage.getWidth() - logoWidth) / 2;
int y = (matrixImage.getHeight() - logoHeight) / 2;
//开始合并绘制图片
g.drawImage(logoImage, x, y, logoWidth, logoHeight, null);
g.drawRoundRect(x, y, logoWidth, logoHeight, 15 ,15);
//线条设置
BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
g.setStroke(stroke);
//logo边框颜色
g.setColor(Color.WHITE);
g.drawRect(x, y, logoWidth, logoHeight);
//释放对象
g.dispose();
logoImage.flush();
matrixImage.flush();
return matrixImage;
}
/**
* @Title: setCodeParams
* @Desc: 设置二维码参数
* @param
* @return
*/
public static HashMap<EncodeHintType, Object> setCodeParams() {
// 封装二维码的参数
HashMap<EncodeHintType, Object> hashMap = new HashMap<>();
hashMap.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 字符集
hashMap.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); // 纠错等级
hashMap.put(EncodeHintType.MARGIN, 2); // 边距
return hashMap;
}
/**
* @Title: savePalce
* @Desc: 二维码保存地址
* @param
* @return
*/
public static String savePalce(String path) {
String codeName = UUID.randomUUID().toString() + new SimpleDateFormat("YYYY-MM-DD").format(new Date()).replace("-", "s");
defaultFilePath = path + codeName.trim() + "." + format;
return defaultFilePath;
}
/**
* @Title: readCode
* @Desc: 读取二维码信息
* @param file
* @return
*/
public static String readCode(File file) {
String result = "";
try {
MultiFormatReader formatReader = new MultiFormatReader();
BufferedImage image = ImageIO.read(file);
BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(image)));
Map<DecodeHintType, Object> hints = new HashMap<>();
hints.put(DecodeHintType.CHARACTER_SET, "utf-8");// 字符集
Result decodeResult = formatReader.decode(binaryBitmap, hints);
result = "解析之后的结果:" + decodeResult.toString() + "\n" + "二维码格式类型:" + decodeResult.getBarcodeFormat() + "\n"
+ "二维码文本内容:" + decodeResult.getText() + "!";
} catch (Exception e) {
result = "解析错误";
return result;
}
return result;
}
/**
* @Title: checkFormat
* @Desc: 验证文件后缀格式
* @param logoFile
* @return
*/
public static boolean checkFormat(File logoFile) {
//文件是否为空
if (null == logoFile) {
System.out.println("logo文件为空!");
return true;
}
String fileName = logoFile.getName();
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
for (String s : checkList) {
if (s.equalsIgnoreCase(suffix)) {
return true;
}
}
return false;
}
/**
* 实现 流文件 响应给浏览器
* @param content
* @param response
*/
public static void encodeQrcode(@PathVariable("content") String content, HttpServletResponse response) {
if (StringUtils.isEmpty(content)) return;
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
Map hints = new HashMap();
//设置字符集编码类型
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
//设置二维码四周的白色边框 ,默认是4,默认为4的时候白色边框实在是太粗了
hints.put(EncodeHintType.MARGIN, 0);
BitMatrix bitMatrix = null;
try {
bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 190, 190, hints);
BufferedImage image = MatrixToImageWriter.toBufferedImage(bitMatrix);
//输出二维码图片流
try {
OutputStream out = response.getOutputStream();
response.setContentType("image/png");
//为文件重新设置名字,采用数据库内存储的文件名称
response.addHeader("Content-Disposition", "attachment; filename=\"" + new String("code.png".getBytes("UTF-8"),"ISO8859-1") + "\"");
ImageIO.write(image, "png", out);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
} catch (WriterException e1) {
e1.printStackTrace();
}
}
}
测试controller:
//不保存二维码图片,以流的形式返回
@RequestMapping("/code")
public void getCode(HttpServletResponse response){
CodeUtil.encodeQrcode("邀请码",response);
}
测试html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>二维码</title>
</head>
<body>
<img src="/code/">
<a href="/code/">下载</a>
</body>
</html>
浏览器访问:http://localhost:8080/index.html
点击下载就会下载此二维码!服务器没有做图片的保存,看个人需要修改!