• java(spring boot)实现二维码生成(可以插入中间log和底部文字)


    1.创建一个spring boot项目(非必须):

    项目结构:
    在这里插入图片描述
    2.导入maven依赖:

    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    
    		<dependency>
    			<groupId>com.google.zxing</groupId>
    			<artifactId>core</artifactId>
    			<version>3.4.0</version>
    		</dependency>
    		<dependency>
    			<groupId>com.google.zxing</groupId>
    			<artifactId>javase</artifactId>
    			<version>3.4.0</version>
    		</dependency>
    

    3.编码实现:

    QrcodeUtil工具类:

    /**
     * 二维码工具类
     * 
     * @author jinghx
     *
     */
    public class QrcodeUtil {
    	private QrcodeUtil() {
    
    	}
    
    	/**
    	 * 默认编码方式
    	 */
    	public static final String DEFAULT_CHARSET = "UTF-8";
    	/**
    	 * 默认二维码图片格式
    	 */
    	public static final String DEFAULT_SUBFIX = "PNG";
    
    	/**
    	 * 生成二维码默认宽度
    	 */
    	public static final int DEFAULT_WIDTH = 250;
    	/**
    	 * 生成二维码默认高度
    	 */
    	public static final int DEFAULT_HEIGHT = 300;
    	/**
    	 * 默认二维码中间log宽度
    	 */
    	public static final int DEFAULT_LOG_WIDTH = 50;
    	/**
    	 * 默认二维码中间log高度
    	 */
    	public static final int DEFAULT_LOG_HEIGHT = 50;
    	/**
    	 * 生成二维码默认保存位置
    	 */
    	public static final String DEFAULT_QRCODE_PATH = System.getProperty("user.dir") + "\" + "qrCode." + DEFAULT_SUBFIX;
    	/**
    	 * log默认路径
    	 */
    	public static final String DEFAULT_LOG_PATH = QrcodeUtil.class.getClassLoader().getResource("log/log.jpg")
    			.getPath();
    
    	/**
    	 * 由字符串生成二维码BufferedImage对象
    	 * 
    	 * @param content 字符串内容
    	 * @param width   二维码宽度,如果为空或小于等于0采用默认宽度
    	 * @param height  二维码高度,如果为空或小于等于0采用默认高度
    	 * @return
    	 */
    	private static BufferedImage createQrCodeBufferedImage(String content, Integer width, Integer height)
    			throws Exception {
    		BufferedImage resultImage = null;
    		if (!StringUtils.isEmpty(content)) {
    			Map<EncodeHintType, Object> hints = new HashMap<>();
    			hints.put(EncodeHintType.CHARACTER_SET, DEFAULT_CHARSET);// 指定字符编码为UTF-8
    			hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);// 指定二维码的纠错等级为中级
    			hints.put(EncodeHintType.MARGIN, 2);// 设置图片的边距
    
    			QRCodeWriter writer = new QRCodeWriter();
    			width = width != null && width > 0 ? width : DEFAULT_WIDTH;
    			height = height != null && height > 0 ? height : DEFAULT_HEIGHT;
    
    			BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
    			// 写到字节数据中
    			// MatrixToImageWriter.writeToStream(bitMatrix, DEFAULT_SUBFIX, os);
    			// resultImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
    			// ImageIO.write(resultImage, DEFAULT_SUBFIX, os);
    
    			// 写到文件中
    			// MatrixToImageWriter.writeToPath(bitMatrix, DEFAULT_SUBFIX,
    			// Paths.get(DEFAULT_PATH));
    
    			resultImage = new BufferedImage(bitMatrix.getWidth(), bitMatrix.getHeight(), BufferedImage.TYPE_INT_RGB);
    			for (int x = 0; x < width; x++) {
    				for (int y = 0; y < height; y++) {
    					resultImage.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF008000 : 0xFFFFFFFF);// 0xFF000000 黑色 0xFF008000 绿色
    				}
    			}
    		}
    		return resultImage;
    	}
    
    	/**
    	 * 由字符串生成base64格式的简单二维码
    	 * 
    	 * @param content      字符串内容
    	 * @param width        二维码宽度,如果为空或小于等于0采用默认宽度
    	 * @param height       二维码高度,如果为空或小于等于0采用默认高度
    	 * @param isSaveToPath 是否保存到文件中
    	 * @return
    	 */
    	public static String productQrCodeString(String content, Integer width, Integer height, boolean isSaveToPath) {
    		String resultImage = "";
    		if (!StringUtils.isEmpty(content)) {
    			try {
    				BufferedImage image = createQrCodeBufferedImage(content, width, height);
    				if (image != null) {
    					ByteArrayOutputStream os = new ByteArrayOutputStream();
    					ImageIO.write(image, DEFAULT_SUBFIX, os);
    					resultImage = "data:image/" + DEFAULT_SUBFIX + ";base64,"
    							+ new String(Base64.getEncoder().encode(os.toByteArray()));
    					if (isSaveToPath) {
    						ImageIO.write(image, DEFAULT_SUBFIX, new FileOutputStream(DEFAULT_QRCODE_PATH));
    					}
    				}
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    		return resultImage;
    	}
    
    	/**
    	 * 由字符串生成base64格式的复杂二维码
    	 * 
    	 * @param content        字符串内容
    	 * @param width          二维码宽度,如果为空或小于等于0采用默认宽度
    	 * @param height         二维码高度,如果为空或小于等于0采用默认高度
    	 * @param isSaveToPath   是否保存到文件中
    	 * @param logPath        log图片的路径
    	 * @param isFixedLogSize 是否固定log图片大小
    	 * @param text           二维码底部文本内容
    	 * @return
    	 */
    	public static String productQrCodeWithLog(String content, Integer width, Integer height, boolean isSaveToPath,
    			String logPath, boolean isFixedLogSize, String text) {
    		String resultImage = "";
    		if (!StringUtils.isEmpty(content)) {
    			try {
    				width = width != null && width > 0 ? width : DEFAULT_WIDTH;
    				height = height != null && height > 0 ? height : DEFAULT_HEIGHT;
    				BufferedImage image = createQrCodeBufferedImage(content, width, height);
    				if (image != null) {
    					ByteArrayOutputStream os = new ByteArrayOutputStream();
    					insertImageAndText(image, width, height, StringUtils.isEmpty(logPath) ? DEFAULT_LOG_PATH : logPath,
    							isFixedLogSize, text);
    					ImageIO.write(image, DEFAULT_SUBFIX, os);
    					resultImage = "data:image/" + DEFAULT_SUBFIX + ";base64,"
    							+ new String(Base64.getEncoder().encode(os.toByteArray()));
    					if (isSaveToPath) {
    						ImageIO.write(image, DEFAULT_SUBFIX, new FileOutputStream(DEFAULT_QRCODE_PATH));
    					}
    				}
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    		return resultImage;
    	}
    
    	/**
    	 * 插入LOGO
    	 *
    	 * @param source         二维码图片
    	 * @param width          二维码宽度,如果为空或小于等于0采用默认宽度
    	 * @param height         二维码高度,如果为空或小于等于0采用默认高度
    	 * @param imgPath        LOGO图片地址
    	 * @param isFixedLogSize 是否固定二维码中间log图标大小
    	 * @param text           二维码底部文本内容
    	 * @throws Exception
    	 */
    	private static void insertImageAndText(BufferedImage source, Integer width, Integer height, String imgPath,
    			boolean isFixedLogSize, String text) throws Exception {
    		File file = new File(imgPath);
    		if (!file.exists()) {
    			System.err.println("" + imgPath + "   该文件不存在!");
    			return;
    		}
    		Image src = ImageIO.read(new File(imgPath));
    		int lwidth = src.getWidth(null);
    		int lheight = src.getHeight(null);
    		if (isFixedLogSize || lwidth >= width || lheight >= height) { // 固定LOGO大小
    			if (lwidth > width) {
    				lwidth = DEFAULT_LOG_WIDTH;
    			}
    			if (lheight > height) {
    				lheight = DEFAULT_LOG_HEIGHT;
    			}
    			Image image = src.getScaledInstance(lwidth, lheight, Image.SCALE_SMOOTH);
    			BufferedImage tag = new BufferedImage(lwidth, lheight, BufferedImage.TYPE_INT_RGB);
    			Graphics g = tag.getGraphics();
    			g.drawImage(image, 0, 0, null); // 绘制缩小后的图
    			g.dispose();
    			src = image;
    		}
    		// 插入LOGO
    		Graphics2D graph = source.createGraphics();
    		int x = (width - lwidth) / 2;
    		int y = (height - lheight) / 2;
    		graph.drawImage(src, x, y, lwidth, lheight, null);
    		Shape shape = new RoundRectangle2D.Float(x, y, lwidth, lheight, 6, 6);
    		graph.setStroke(new BasicStroke(3f));
    		graph.draw(shape);
    
    		if (!StringUtils.isEmpty(text)) {
    			int fontStyle = 1;
    			int fontSize = 12; //
    			// 计算文字开始的位置(居中显示)
    			// x开始的位置:(图片宽度-字体大小*字的个数)/2
    			int startX = (width - (fontSize * text.length())) / 2;
    			// y开始的位置:图片高度-(图片高度-图片宽度)/2
    			int startY = height - (height - width) / 2;
    			graph.setColor(Color.BLUE);
    			graph.setFont(new Font(null, fontStyle, fontSize)); // 字体风格与字体大小 graph.drawString(text, startX, startY);
    			graph.drawString(text, startX, startY);
    		}
    
    		graph.dispose();
    	}
    
    	/**
    	 * 解码二维码内容
    	 * 
    	 * @param file
    	 * @return
    	 * @throws Exception
    	 */
    	public static String decode(File file) throws Exception {
    		BufferedImage image;
    		image = ImageIO.read(file);
    		if (image == null) {
    			return null;
    		}
    		BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image);
    		BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
    		Result result;
    		Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>();
    		hints.put(DecodeHintType.CHARACTER_SET, DEFAULT_CHARSET);
    		result = new MultiFormatReader().decode(bitmap, hints);
    		String resultStr = result.getText();
    		return resultStr;
    	}
    
    	public static void main(String[] args) throws Exception {
    		System.out.println(decode(new File(DEFAULT_QRCODE_PATH)));
    	}
    }
    

    编写一个测试用的Controller类:

    @RestController
    @RequestMapping("/qrcode")
    public class QrCodeController {
    
    	/**
    	 * 生成简单的字符串二维码
    	 * 
    	 * @param content
    	 * @return
    	 */
    	@PostMapping("/simpleCode")
    	public String productQrCode(String content) {
    		return QrcodeUtil.productQrCodeString(content, null, null, true);
    	}
    
    	/**
    	 * 生成带有log和底部字符串的二维码
    	 * 
    	 * @param content
    	 * @return
    	 */
    	@PostMapping("/codePlus")
    	public String productQrCodeWithLogAndText(String content, String bottomText) {
    		return QrcodeUtil.productQrCodeWithLog(content, null, null, true, null, true, bottomText);
    	}
    
    }
    

    编写一个简单的html页面qrCode.html,实时查看二维码生成效果:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>生成二维码</title>
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    </head>
    <body>
    	<div style="float: left">
    		<div>
    			<input id="strContent" type="text" width="500px"
    				placeholder="输入二维码想显示的内容">
    			<button onclick="getSimpleQrcode()">点击显示简单二维码</button>
    		</div>
    		<div>
    			<img id="simpleQrCode" />
    		</div>
    
    	</div>
    	<div style="float: left; padding-left: 20px;">
    		<div>
    			<input id="logContent" type="text" width="500px"
    				placeholder="输入二维码想显示的内容"> <input id="bottomText"
    				type="text" width="300px" placeholder="二维码底部文字,可不填">
    			<button onclick="getComplexQrcode()">点击显示带log二维码</button>
    		</div>
    		<div>
    			<img id="complexQrCode" />
    		</div>
    	</div>
    </body>
    <script type="text/javascript">
    	/**
    	 * 通过ajax请求获取base64编码格式的二维码
    	 */
    	function getpQrcode(url, param, imgId) {
    		$.ajax({
    			url : url,
    			cache : false,
    			type : 'POST',
    			data : param,
    			async : true,
    			dataType : 'text',
    			error : function(event, XMLHttpRequest, ajaxOptions, thrownError) {
    				console.log(event);
    				console.log(XMLHttpRequest);
    				console.log(ajaxOptions);
    				console.log(thrownError);
    			},
    			success : function(data) {
    				$("#" + imgId).prop('src', data);
    			}
    		});
    	}
    	/**
    	 *简单二维码
    	 */
    	function getSimpleQrcode() {
    		let url = "qrcode/simpleCode";
    		let param = {
    			'content' : $("#strContent").prop('value')
    		};
    		let imgId = "simpleQrCode";
    		getpQrcode(url, param, imgId);
    	}
    	/**
    	 *复杂二维码
    	 */
    	function getComplexQrcode() {
    		let url = "qrcode/codePlus";
    		let param = {
    			'content' : $("#logContent").prop('value'),
    			'bottomText' : $("#bottomText").prop('value')
    		};
    		let imgId = "complexQrCode";
    		getpQrcode(url, param, imgId);
    	}
    </script>
    </html>
    

    整个工程就是依赖google的二维码工具包来进行二维码的生成,代码的注释比较详细了,这里就不再做过多的赘述,运行工程:

    访问:http://localhost:8080/qrcode.html
    在这里插入图片描述
    可以在对应的input框中输入你想要生成的二维码内容,点击旁边的按钮即可生成(二维码颜色可以参考 颜色名称 RGB 对照表 设置):
    在这里插入图片描述
    同时工程目录下会保存一张最新生成的二维码图片:
    在这里插入图片描述

    一颗安安静静的小韭菜。文中如果有什么错误,欢迎指出。
  • 相关阅读:
    多线程环境下调用 HttpWebRequest 并发连接限制
    i—比 i++ 快?
    文件在不同文件系统间拷贝文件时间改变的问题
    Go websocket 聊天室demo2
    Go websocket 聊天室demo以及k8s 部署
    AcWing 1077. 皇宫看守
    AcWing 1073. 树的中心
    AcWing 1085. 不要62
    AcWing 1081 度的数量
    AcWing 1082. 数字游戏
  • 原文地址:https://www.cnblogs.com/c-Ajing/p/13448345.html
Copyright © 2020-2023  润新知