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

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

Groovy 复制代码
implementation("com.google.zxing:core:3.4.1")
implementation("com.google.zxing:javase:3.4.1")

zxing的基本使用

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

Kotlin 复制代码
val matrix = MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hint)

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

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

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

Kotlin 复制代码
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

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

Kotlin 复制代码
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)
    }

}

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

Kotlin 复制代码
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中,配置服务器的端口:

Kotlin 复制代码
server.port=80

测试一下

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

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

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

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

相关推荐
Jabes.yang16 分钟前
Java求职面试: 互联网医疗场景中的缓存技术与监控运维应用
java·redis·spring security·grafana·prometheus·oauth2·互联网医疗
摇滚侠29 分钟前
Spring Boot 3零基础教程,yml配置文件,笔记13
spring boot·redis·笔记
初级炼丹师(爱说实话版)31 分钟前
内存泄漏与内存溢出
java
CryptoRzz41 分钟前
越南k线历史数据、IPO新股股票数据接口文档
java·数据库·后端·python·区块链
!if1 小时前
springboot mybatisplus 配置SQL日志,但是没有日志输出
spring boot·sql·mybatis
学Java的bb1 小时前
MybatisPlus
java·开发语言·数据库
讓丄帝愛伱1 小时前
Mybatis Log Free插件使用
java·开发语言·mybatis
重生之我要当java大帝1 小时前
java微服务-尚医通-编写医院设置接口上
java·数据库·微服务
夫唯不争,故无尤也1 小时前
Tomcat 内嵌启动时找不到 Web 应用的路径
java·前端·tomcat
心之伊始1 小时前
Netty线程模型与Tomcat线程模型对比分析
java·开发语言