Spring Boot整合zxing实现二维码登录

zxing是google的一个二维码生成库,使用时需配置依赖:

implementation("com.google.zxing:core:3.4.1")
implementation("com.google.zxing:javase:3.4.1")

zxing的基本使用

我们可以通过MultiFormatWriter().encode()方法获取一个matrix对象:

val matrix = MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hint)

这个方法接受5个参数,按照顺序解释如下:

  1. 二维码的字符串内容
  2. 格式,如要生成二维码,则需传入BarcodeFormat.QR_CODE
  3. 二维码宽度(像素)
  4. 二维码高度(像素)
  5. 二维码的属性

其中,第5个参数需要传入一个HashMap对象:

private val hint = mapOf(
    // 误差校正等级
    EncodeHintType.ERROR_CORRECTION to ErrorCorrectionLevel.M,
    // 字符集
    EncodeHintType.CHARACTER_SET to "UTF-8",
    // 外边框像素
    EncodeHintType.MARGIN to 5
)

需要指定三个键,第一个键的值是误差校正等级,在ErrorCorrectionLevel枚举中,有如下选择:

  • L:可以校正7%
  • M:可以校正15%
  • Q:可以校正25%
  • H:可以校正30%

误差校正等级的存在,可以使二维码被遮挡时,仍然能够被正常扫描。一般来说,误差校正等级越大,二维码就越大

第二个键是字符集,一般用UTF-8即可

第三个键是外边框的像素大小

整合Spring Boot

首先我们需要有一个二维码生成的工具类,可以生成将二维码并将二维码输出至一个输出流:

package com.example.qrcode.util

import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.MultiFormatWriter
import com.google.zxing.client.j2se.MatrixToImageWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import java.io.OutputStream

object QRUtil {

    private val width = 400
    private val height = 400
    private val hint = mapOf(
        // 误差校正等级
        EncodeHintType.ERROR_CORRECTION to ErrorCorrectionLevel.M,
        // 字符集
        EncodeHintType.CHARACTER_SET to "UTF-8",
        // 外边框像素
        EncodeHintType.MARGIN to 5
    )

    /**
     * 创建二维码并写入到输出流
     * @param content 二维码内容
     * @param outputStream 输出流
     * */
    fun writeCodeIntoStream(content: String, outputStream: OutputStream){
        val matrix = MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hint)
        MatrixToImageWriter.writeToStream(matrix, "png", outputStream)
    }

}

接下来我们需要一个控制器类,提供电脑生成二维码的登录接口,手机扫描二维码使设备登录的接口,和手机扫描二维码后,电脑登陆成功,跳转的接口:

package com.example.qrcode.controller

import com.example.qrcode.util.QRUtil
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import jakarta.servlet.http.HttpSession
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.net.URL

@RestController
class QRLoginController {

    val idLogin = HashMap<String, Boolean>()

    @RequestMapping("/QR/login")
    fun login(request: HttpServletRequest, response: HttpServletResponse, session: HttpSession){
        if (idLogin.containsKey(session.id) && idLogin[session.id] == true){
            response.sendRedirect("/QR/login/down")
            return
        }
        response.setIntHeader("Refresh", 1)
        val strUrl = request.requestURL.toString()
        val url = URL(strUrl)
        val host = url.host
        val pro = url.protocol
        QRUtil.writeCodeIntoStream("$pro://$host/QR/login/${session.id}", response.outputStream)
    }

    @RequestMapping("/QR/login/{id}")
    fun loginByID(@PathVariable("id") id: String): String{
        idLogin[id] = true
        return "登录中"
    }

    @RequestMapping("/QR/login/down")
    fun loginDown(): String{
        return "登录成功"
    }

}

在/QR/login接口中,我们首先判断当前会话是否已经被人扫了二维码,如果是,则重定向到/QR/login/down接口中;而如果不是,则会通过设置响应头"Refresh"参数,使电脑浏览器端每个一秒刷新一下,并向电脑输出一个二维码,手机扫描这个二维码后,将会前往/QR/login/{id}接口,并通过可变的URL路径,将id传入。

在/QR/login/{id}接口中,将会将传入的id的登录状态设置为真。这样的话,电脑端访问的/QR/login接口就会跳转至/QR/login/down接口

要注意,这里面的实现方式不是正常的实现方式。正常的实现方式应通过前端的脚本语言实现登录状态的刷新。但是因为我们没有前端,所以采用了这种方法

由于手机扫描二维码时,不会指定访问端口,因此需要在application.properties中,配置服务器的端口:

server.port=80

测试一下

使用浏览器访问http://[你的IP地址]/QR/login,注意,这里不能通过127.0.0.1或localhost访问,因为需要手机和电脑两个设备访问

这时,浏览器会显示一个二维码(CSDN可能不让上传二维码,因此进行了手动打码):

接下来使用手机扫描这个二维码,会发现浏览器成功的跳转到了登录成功的页面:

 因此,我们的二维码登录就成功实现了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/450582.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PMP考试:如何高效学习PMBOK?

PMBOK&#xff08;项目管理知识体系指南&#xff09;是PMP考试的核心教材&#xff0c;学习PMBOK对于备考PMP考试至关重要。那么我将分享一些高效学习PMBOK的方法和技巧&#xff0c;帮助同学们更好地掌握项目管理知识。 一、制定学习计划 在学习PMBOK之前&#xff0c;制定一个详…

嵌入式系统中端口号的理解与分析

每当看到有人的简历上写着熟悉 tcp/ip, http 等协议时, 我就忍不住问问他们: 你给我说说, 端口是啥吧! 可惜, 很少有人能说得让人满意... 所以这次就来谈谈端口(port), 这个熟悉的陌生人. 在此过程中, 还会谈谈间接层, naming service 等概念, IoC, 依赖倒置等原则以及 TCP 协议…

【linux】02 :Linux基础命令

1.掌握linux系统的目录结构 linux只有一个顶级目录&#xff0c;称之为&#xff1a;根目录。 windows系统有多个顶级目录&#xff0c;即各个盘符。 2.linux路径的描述方式 /在Linux中的表示&#xff1a;出现在开头表示根目录&#xff0c;出现在后面表示层级关系。 3.什么是命…

项目管理工具及模板(甘特图、OKR周报、任务管理、头脑风暴等)

项目管理常用模板大全&#xff1a; 1. 项目组OKR周报 2. 项目组传统周报工作法 3. 项目甘特图 4. 团队名单 5. 招聘跟进表 6. 出勤统计 7. 年度工作日历 8. 项目工作年计划 9. 版本排期 10. 项目组任务管理 11. 项目规划模板 12. 产品分析报告 13. 头脑风暴 信息化项目建设全套…

vuetify3+vite,打包后mdi图标无法正常显示,及打包后首页白屏

1、图标无法正常显示 【因为我的vite.config.ts配置中使用了vite-plugin-css-injected-by-js这个插件】 为了优化我的项目&#xff0c;我使用了很多插件&#xff0c;vite-plugin-css-injected-by-js就是其中一个&#xff0c;项目本地运行是正常的&#xff0c;但是当我使用unia…

【梳理】k8s使用Operator搭建Flink集群(高可用可选)

文章目录 1. 架构图2. helm 安装operator3. 集群知识k8s上的两种模式&#xff1a;Native和Standalone两种CR 4. 运行集群实例Demo1&#xff1a;Application 集群Demo2&#xff1a;Session集群优劣 5. 高可用部署问题1&#xff1a;High availability should be enabled when sta…

【LeetCode】升级打怪之路 Day 18:二叉树题型 —— 树的深度、高度、路经

今日题目&#xff1a; 104. 二叉树的最大深度111. 二叉树的最小深度110. 平衡二叉树257. 二叉树的所有路径112. 路径总和 目录 Problem 1&#xff1a;树的深度LC 104. 二叉树的最大深度 【easy】LC 111. 二叉树的最小深度 【易错】 Problem 2&#xff1a;树的高度LC 110. 平衡二…

【阿里云系列】-如何实现两个VPC网络资源互通

背景 由于实际项目预算有限&#xff0c;两套环境虽然分别属于不同的专有网络即不同的VPC&#xff0c;但是希望借助一台运维机器实现对两个环境的监控和日常的运维操作 网络架构 如下是需要实现的外网架构图&#xff0c;其中希望实现UAT环境的一台windows的堡垒机可以访问生产…

如何考上东南大学计算机学院?

东南大学招生学院是计算机科学与工程学院、苏州联合研究生院&#xff0c;复试公平&#xff0c;不歧视双非考生&#xff0c;985院校中性价比较高&#xff0c;但近年热度在逐年上涨&#xff0c;需要警惕。 建议报考计算机科学与工程学院081200计算机科学与技术专业目标分数为380…

HarmonyOS开发:NEXT版本开发新体验

前言 年前&#xff0c;公司团队接洽了鸿蒙方团队&#xff0c;确认了生态合作&#xff0c;于是开通了白名单权限&#xff0c;授权了新的IDE和相关文档的使用和查看&#xff0c;历经一月有余&#xff0c;谈谈NEXT版本有哪些开发上的区别。 本文会从以下几个方面阐述&#xff1a;…

Unity2021.3.35f1配置安卓APK发布环境

1.在Unity3d中点击菜单【Edit】【Preferences】&#xff0c;在External Tools中可以看到Android平台需要配置JDK、SDK、NDK、Gradle。对应的版本需要在官方文档中查看 JDK&#xff1a;指Java开发环境 SDK&#xff1a;指安卓开发包&#xff0c;包括Build Tools、Commond-line T…

day1-C++

1>提示并输入一个字符串&#xff0c;统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数要求使用C风格字符串完成。 代码&#xff1a; #include <iostream> #include <string.h> using namespace std;int main() {string str ;int low 0, …

react 综合题

一、组件基础 1. React 事件机制 javascript 复制代码<div onClick{this.handleClick.bind(this)}>点我</div> React并不是将click事件绑定到了div的真实DOM上&#xff0c;而是在document处监听了所有的事件&#xff0c;当事件发生并且冒泡到document处的时候&a…

【数据结构】特殊的线性表——栈

&#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;个人主页&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f388; &#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;&#x1f9e7;数据结构专栏&#x1f388;&#x1f388;&#x1f388;&…

WPF —— 数据绑定(初级)

数据绑定&#xff1a;把数据以一个变量的方式绑定到一个标签上,以后可以通过对变量修改&#xff0c;达到修改属性的目的 之前修改某一个label标题&#xff0c;之前写法this.l1.content"李四" 数据绑定写法&#xff1a;label content {Bind path title} …

Redis中AOF数据持久化

AOF介绍 AOF&#xff08;Append Only File&#xff09;持久化&#xff1a;以独立日志的方式存储了 Redis 服务器的顺序指令序列&#xff0c;并只记录对内存进行修改的指令。 当Redis服务发生雪崩等故障时&#xff0c;可以重启服务并重新执行AOF文件中的指令达到恢复数据的目的…

Oracle之ADG与DG的区别?

在上云后的Oracle数据灾备场景中&#xff0c;我们经常听到DBA迁移工程师讲到“在这个项目中用ADG进行数据实时备份&#xff0c;ADG比DG更好&#xff01;”。究竟ADG作Oracle数据灾备的优势在什么地方&#xff1f; 一、ADG主要解决了DG时代读写不能并行的问题 DG时代的数据同步…

计算机设计大赛 深度学习花卉识别 - python 机器视觉 opencv

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &a…

es配置elk实现增量同步以及全量同步

需要配置这个文件 input {stdin {}jdbc {# mysql 数据库链接,center为数据库名,jdbc版本比较大的要加上&#xff1f;后面那串字符jdbc_connection_string > "jdbc:mysql://192.168.161.131:3307/mz-master"# 用户名和密码jdbc_user > "root"jdbc_pas…

bug--xxoobject has no attribute xxx

Python 创建类的实例后却不能调用写的方法&#xff0c;检查了半天原来是缩进的问题&#xff0c;def函数不应该和class并列 只能说这个英文空格太小了&#xff0c;看不出来。。。。