上个小节我们在后端生成了二维码图片的Base64字符串,那么这节课我们要在Web页面上切换登陆方式的时候,加载出来这个二维码图片。
一、页面设计
在login.vue
页面中定义了一个DIV标签,里面包含的就是显示二维码内容。
<div v-if="qrCodeVisible">
<div class="qrCode-container">
<img :src="qrCode" height="153" class="qrCode" />
<img src="../assets/login/phone.png" height="148" />
</div>
<div class="row"><a class="link" @click="changeMode">用户名密码登陆</a></div>
</div>
在模型层中声明了跟二维码有关的若干变量。qrCodeVisible
变量默认为false,也就是说二维码DIV面板默认是不显示的,需要我们手动进行切换。
data: function() {
return {
……,
qrCodeVisible: false,
qrCode: '',
uuid: null,
qrCodeTimer: null,
loginTimer: null
};
},
在登陆页面上有个文字连接,点击这个连接,自动切换二维码面板上。这个文字连接的标签代码如下,需要我们声明点击事件的回调函数。
<div class="row"><a class="link" @click="changeMode">二维码登陆</a></div>
二、切换登陆方式
定义changeMode()
函数用来切换登陆面板,其实就是改变qrCodeVisible
变量的值。
changeMode: function() {
let that = this;
that.qrCodeVisible = !that.qrCodeVisible;
//加载二维码图片
if (that.qrCodeVisible) {
that.loadQRCode();
//创建刷新二维码定时器,默认为5分钟
that.qrCodeTimer = setInterval(function() {
that.loadQRCode();
}, 5 * 60 * 1000);
//创建轮询定时器,每隔5秒钟发起Ajax请求,检查Redis中UUID对应的值
that.loginTimer = setInterval(function() {
//调用Web方法,检查Redis中UUID对应的值,判定用户是否扫码登陆。该Web方法下面有定义。
that.$http('user/wechatLogin', 'POST', { uuid: that.uuid }, true, function(resp) {
if (resp.result) {
//判定登陆成功就自动销毁两个定时器
clearInterval(that.qrCodeTimer);
clearInterval(that.loginTimer);
//缓存用户权限
let permissions = resp.permissions;
localStorage.setItem('permissions', permissions);
//跳转页面
router.push({ name: 'Home' });
}
});
}, 5000);
} else {
//切换回账户密码登陆,销毁刷新二维码定时器
clearInterval(that.qrCodeTimer);
clearInterval(that.loginTimer);
}
},
//加载二维码图片的封装方法
loadQRCode: function() {
this.$http('user/createQrCode', 'GET', null, true, resp => {
this.qrCode = resp.pic;
this.uuid = resp.uuid;
});
}
三、检查登陆结果
上面浏览器发出的轮询Ajax请求发送给Web方法查询登陆情况,下面咱们把这个Web方法写一下,先从业务层看是写起。在UserService.java
接口中声明抽象方法。
public interface UserService {
……
public HashMap wechatLogin(String uuid);
}
在UserServiceImpl.java
类中实现抽象方法。
@Service
public class UserServiceImpl implements UserService {
……
@Override
public HashMap wechatLogin(String uuid) {
HashMap map = new HashMap();
boolean result = false;
if (redisTemplate.hasKey(uuid)) {
String value = redisTemplate.opsForValue().get(uuid).toString();
//判断Redis缓存的UUID对应的Value是否为非false,就算用户登陆了
if (!"false".equals(value)) {
result = true;
//删除Redis中的UUID,防止二维码被重刷
redisTemplate.delete(uuid);
//把Value的字符串转换成整数
int userId = Integer.parseInt(value);
map.put("userId", userId);
}
}
map.put("result", result);
return map;
}
}
创建WechatLoginForm.java
类,封装浏览器提交的Ajax数据。
@Schema(name = "WechatLoginForm", description = "微信小程序登陆Emos系统Form类")
@Data
public class WechatLoginForm {
@Schema(description = "uuid")
@NotBlank(message = "uuid不能为空")
private String uuid;
}
在UserController.java
类中定义Web方法,可以用Swagger测试一下。
@RestController
@RequestMapping("/user")
@Tag(name = "UserController", description = "用户Web接口")
public class UserController {
……
@PostMapping("/wechatLogin")
@Operation(summary = "微信小程序登陆")
public R wechatLogin(@Valid @RequestBody WechatLoginForm form) {
HashMap map = userService.wechatLogin(form.getUuid());
boolean result = (boolean) map.get("result");
if (result) {
int userId = (int) map.get("userId");
StpUtil.setLoginId(userId);
Set<String> permissions = userService.searchUserPermissions(userId);
map.remove("userId");
map.put("permissions", permissions);
String token=StpUtil.getTokenInfo().getTokenValue();
map.put("token",token);
}
return R.ok(map);
}
}