基于ruoyi-vue + hutools二维码功能实现,具体思路逻辑等待补充。代码如下
提供给前端调用的Controller
package com.ruoyi.web.controller.qrcode;
import com.ruoyi.common.constant.QRCodeConstants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.model.QRCodeBody;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.qrcode.QrCodeServiceUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.framework.web.service.TokenService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* @author 91989
* @title: QRCodeController
* @projectName xy-center-back
* @description: 验证码生成类
* @date 2022/2/24 11:43
*/
@RestController
@RequestMapping("/qrcode")
public class QRCodeController extends BaseController {
private static final Logger log = LoggerFactory.getLogger(QRCodeController.class);
@Autowired
private RedisCache redisCache;
@Autowired
private TokenService tokenService;
/**
* * @description: 二维码生成
* * @author Lin
* * @date 2022/2/24 14:23
*/
@GetMapping("/createQrcode/{codeContent}")
public AjaxResult getQRCode(@PathVariable String codeContent) {
String base64Code = null;
String qrcodeId = null;
try {
qrcodeId = IdUtils.fastUUID();
String url = "/v1/qrcode/createQrcode";
//拼接二维码请求地址+二维码ID+客户端ID(即请求生成二维码的客户端Id)
String qrContent = url + "?" + "qrcodeId=" + qrcodeId + "&" + "clientId=" + codeContent;
base64Code = QrCodeServiceUtils.createQRCode2Base64(qrContent);
QRCodeBody qrCodeBody = new QRCodeBody(qrcodeId, QRCodeConstants.QR_UN_SCAN);
qrCodeBody.setClientId(codeContent);
//生成唯一二维码ID 并记录状态
redisCache.setCacheObject(QRCodeConstants.QR_STATUS_KEY + qrcodeId, qrCodeBody, QRCodeConstants.QR_EXPIRATION, TimeUnit.MINUTES);
} catch (Exception e) {
log.error(e.toString());
}
return StringUtils.isEmpty(base64Code) ? AjaxResult.error() : AjaxResult.success(base64Code).put("qrcodeId", qrcodeId);
}
/**
* * @description: 前端轮询 二维码状态
* * @author Lin
* * @date 2022/2/24 15:16
*/
@GetMapping("/getQrcodeStatus/{qrcodeId}")
public AjaxResult getQRCodeStatus(@PathVariable String qrcodeId) {
QRCodeBody qrCodeBodyRedis = redisCache.getCacheObject(QRCodeConstants.QR_STATUS_KEY + qrcodeId);
if(StringUtils.isNotNull(qrCodeBodyRedis)){
Integer qrStatus = qrCodeBodyRedis.getQrcodeStatus();
String clientId = qrCodeBodyRedis.getClientId();
String token = qrCodeBodyRedis.getClientToken();
//返回二维码状态 请求终端Id token
return AjaxResult.success(qrStatus).put("clientId", clientId).put("token", token);
}
//如果获取不到redis键值,则表示二维码已经过期
return AjaxResult.success(QRCodeConstants.QR_EXPIRE);
}
/**
* * @description: 二维码标记已扫描
* * @author Lin
* * @date 2022/2/26 13:39
*/
@PostMapping("/isScanned")
public AjaxResult isScanned(@RequestBody QRCodeBody qrCodeBody) {
QRCodeBody qrCodeBodyRedis = redisCache.getCacheObject(QRCodeConstants.QR_STATUS_KEY + qrCodeBody.getQrcodeId());
qrCodeBodyRedis.setQrcodeStatus(QRCodeConstants.QR_SCAN_WAIT_CONFIRM);
redisCache.setCacheObject(QRCodeConstants.QR_STATUS_KEY + qrCodeBody.getQrcodeId(), qrCodeBodyRedis);
return AjaxResult.success();
}
/**
* * @description: 手机端确认二维码登录
* * @author Lin
* * @date 2022/2/26 13:39
*/
@PostMapping("/confirm")
public AjaxResult confirm(@RequestBody QRCodeBody qrCodeBody) {
LoginUser user = getLoginUser();
QRCodeBody qrCodeBodyRedis = redisCache.getCacheObject(QRCodeConstants.QR_STATUS_KEY + qrCodeBody.getQrcodeId());
String token = tokenService.createToken(user);
qrCodeBodyRedis.setClientToken(token);
qrCodeBodyRedis.setQrcodeStatus(QRCodeConstants.QR_SCAN_CONFIRM);
redisCache.setCacheObject(QRCodeConstants.QR_STATUS_KEY + qrCodeBody.getQrcodeId(), qrCodeBodyRedis);
return AjaxResult.success("已授权登录", qrCodeBody.getClientId());
}
/**
* * @description: 二维码取消授权
* * @author Lin
* * @date 2022/2/26 13:39
*/
@PostMapping("/cancel")
public AjaxResult cancel(@RequestBody QRCodeBody qrCodeBody) {
QRCodeBody qrCodeBodyRedis = redisCache.getCacheObject(QRCodeConstants.QR_STATUS_KEY + qrCodeBody.getQrcodeId());
qrCodeBodyRedis.setQrcodeStatus(QRCodeConstants.QR_SCAN_CONFIRM_CANCEL);
redisCache.setCacheObject(QRCodeConstants.QR_STATUS_KEY + qrCodeBody.getQrcodeId(), qrCodeBodyRedis);
return AjaxResult.success();
}
}
二维码信息实体
package com.ruoyi.common.core.domain.model;
/**
* @author 91989
* @title: QRCodeBody
* @projectName xy-center-back
* @description: TODO
* @date 2022/2/26 9:05
*/
public class QRCodeBody {
public String getQrcodeId() {
return qrcodeId;
}
public void setQrcodeId(String qrcodeId) {
this.qrcodeId = qrcodeId;
}
private String qrcodeId;
public String getClientId() {
return clientId;
}
public void setClientId(String clientId) {
this.clientId = clientId;
}
//用于区分各客户端的token
private String clientId;
public String getClientToken() {
return clientToken;
}
public void setClientToken(String clientToken) {
this.clientToken = clientToken;
}
//用于区分各客户端的token
private String clientToken;
public Integer getQrcodeStatus() {
return qrcodeStatus;
}
public void setQrcodeStatus(Integer qrcodeStatus) {
this.qrcodeStatus = qrcodeStatus;
}
private Integer qrcodeStatus;
public QRCodeBody(String qrcodeId,Integer qrcodeStatus) {
this.qrcodeId = qrcodeId;
this.qrcodeStatus = qrcodeStatus;
}
public QRCodeBody() {
}
}
二维码状态常量
package com.ruoyi.common.constant;
/**
* @author 91989
* @title: QRCodeConstants
* @projectName xy-center-back
* @description: 二维码相关常量信息
* @date 2022/2/25 15:13
*/
public class QRCodeConstants {
//二维码未被扫描
public static final int QR_UN_SCAN = 1;
//二维码已被扫描,等待确认
public static final int QR_SCAN_WAIT_CONFIRM = 2;
//二维码 用户已确认
public static final int QR_SCAN_CONFIRM = 3;
//二维码 用户已取消确认
public static final int QR_SCAN_CONFIRM_CANCEL = 4;
//二维码已过期
public static final int QR_EXPIRE = 5;
//二维码状态 redisKey 前缀
public static final String QR_STATUS_KEY = "qr_status:";
//二维码有效期
public static final Integer QR_EXPIRATION = 15;
}