之前咱们把用户登录,注册成功的信息都放到redis里面了,如果产品经理有一种场景,就是同一个用户在同一个时间以最后一个登录为准,那么前一个就需要重新登录,并且清空前一个用户缓存。这就用到了springboot的缓存机制。源码:https://github.com/limingios/wxProgram.git 中No.15和springboot
通过前端传递过来的userToken,和从redis里面获取到的userToken对比,如果不一致,前端传递过来的这个session奖杯提示用户被挤出,直接缓存失效。需要重新登录。
package com.idig8.controller.interceptor;import java.io.IOException;import java.io.OutputStream;import java.io.UnsupportedEncodingException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import com.idig8.utils.JSONResult;import com.idig8.utils.JsonUtils;import com.idig8.utils.RedisOperator;public class MiniInterceptor implements HandlerInterceptor { @Autowired
public RedisOperator redis; public static final String USER_REDIS_SESSION = "user-redis-session";
/**
* 拦截请求,在controller调用之前
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object arg2) throws Exception {
String userId = request.getHeader("headerUserId");
String userToken = request.getHeader("headerUserToken");
if (StringUtils.isNotBlank(userId) && StringUtils.isNotBlank(userToken)) {
String uniqueToken = redis.get(USER_REDIS_SESSION + ":" + userId); if (StringUtils.isEmpty(uniqueToken) && StringUtils.isBlank(uniqueToken)) {
System.out.println("请登录...");
returnErrorResponse(response, new JSONResult().errorTokenMsg("请登录...")); return false;
} else { if (!uniqueToken.equals(userToken)) {
System.out.println("账号被挤出...");
returnErrorResponse(response, new JSONResult().errorTokenMsg("账号被挤出...")); return false;
}
}
} else {
System.out.println("请登录...");
returnErrorResponse(response, new JSONResult().errorTokenMsg("请登录...")); return false;
}
/**
* 返回 false:请求被拦截,返回
* 返回 true :请求OK,可以继续执行,放行
*/
return true;
}
public void returnErrorResponse(HttpServletResponse response, JSONResult result)
throws IOException, UnsupportedEncodingException {
OutputStream out=null; try{
response.setCharacterEncoding("utf-8");
response.setContentType("text/json");
out = response.getOutputStream();
out.write(JsonUtils.objectToJson(result).getBytes("utf-8"));
out.flush();
} finally{ if(out!=null){
out.close();
}
}
}
/**
* 请求controller之后,渲染视图之前
*/
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
}
/**
* 请求controller之后,视图渲染之后
*/
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
}
}
每一个拦截器有需要实现HandlerInterceptor接口,这个接口有三个方法,每个方法会在请求调用的不同时期完成,因为我们需要在接口调用之前拦截请求判断是否登陆,所以这里需要使用preHandle方法,在里面是验证逻辑,最后返回true或者false,确定请求是否合法。
原来咱们在spring mvc的时候都是通过xml配置文件的方法,springboot为了简化,都是通过java来进行配置,刚创建的拦截器需要配置在webconfig里面
package com.idig8;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import com.idig8.controller.interceptor.MiniInterceptor;@Configurationpublic class WebMvcConfig extends WebMvcConfigurerAdapter {
@Value("${server.file.path}") private String fileSpace; @Override
public void addResourceHandlers(ResourceHandlerRegistry registry) { //资源的路径.swagger2的资源.所在的目录,
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/META-INF/resources/")
.addResourceLocations("file:"+fileSpace);
}
@Bean
public MiniInterceptor miniInterceptor() { return new MiniInterceptor();
} @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(miniInterceptor()).addPathPatterns("/user/**")
.addPathPatterns("/video/upload", "/video/uploadCover")
.addPathPatterns("/bgm/**");
super.addInterceptors(registry);
}
}
在通过userId获取用户的信息时,在header中添加用户的userId,userToken,针对登录后返回502进行提示并清空用户信息缓存。
// pages/mine/mine.jsconst app = getApp()var videoUtils = require('../../utils/videoUtils.js')
Page({ /**
* 页面的初始数据
*/
data: { faceImage: "../../resource/images/noneface.png", nickname: "昵称", fansCounts: 0, followCounts: 0, receiveLikeCounts: 0,
}, /**
* 用户注销
*/
logout: function(e) { var user = app.getGlobalUserInfo();
wx.showLoading({ title: '正在注销中。。。'
});
wx.request({ url: app.serverUrl + "/logout?userId=" + user.id, method: "POST", header: { 'content-type': 'application/json' // 默认值
}, success: function(res) { console.log(res.data); var status = res.data.status;
wx.hideLoading(); if (status == 200) {
wx.showToast({ title: "用户注销成功~!", icon: 'none', duration: 3000
}) // app.userInfo = null;
wx.removeStorageSync("userInfo");
wx.redirectTo({ url: '../userRegister/userRegister',
})
} else if (status == 500) {
wx.showToast({ title: res.data.msg, icon: 'none', duration: 3000
})
}
}
})
}, /**
* 头像上传
*/
uploadFace: function(e) { // var user = app.userInfo;
var user = app.getGlobalUserInfo(); var me = this;
wx.chooseImage({ count: 1, // 默认9
sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function(res) { // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片
var tempFilePaths = res.tempFilePaths if (tempFilePaths.length > 0) { console.log(tempFilePaths[0]);
wx.uploadFile({ url: app.serverUrl + "/user/uploadFace?userId=" + user.id, //仅为示例,非真实的接口地址
filePath: tempFilePaths[0], name: 'file', success: function(res) { var data = JSON.parse(res.data); console.log(data);
wx.hideLoading(); if (data.status == 200) {
wx.showToast({ title: "用户上传成功~!", icon: 'none', duration: 3000
})
me.setData({ faceUrl: app.serverUrl + data.data
})
} else if (data.status == 500) {
wx.showToast({ title: data.msg, icon: 'none', duration: 3000
})
}
}
})
}
}
})
}, /**
* 生命周期函数--监听页面加载
*/
onLoad: function(options) { var me = this; var userInfo = app.getGlobalUserInfo();
wx.showLoading({ title: '正在获取用户信息。。。'
});
wx.request({ url: app.serverUrl + "/user/queryByUserId?userId=" + userInfo.id, method: "POST", header: { 'content-type': 'application/json', // 默认值
'headerUserId': userInfo.id, 'headerUserToken': userInfo.userToken
}, success: function(res) { console.log(res.data); var status = res.data.status; if (status == 200) { var userInfo = res.data.data;
wx.hideLoading(); var faceImage = me.data.faceUrl; if (userInfo.faceImage != null && userInfo.faceImage != '' && userInfo.faceImage != undefined) {
faceImage = app.serverUrl + userInfo.faceImage;
}
me.setData({ faceImage: faceImage, fansCounts: userInfo.fansCounts, followCounts: userInfo.followCounts, receiveLikeCounts: userInfo.receiveLikeCounts, nickname: userInfo.nickname
})
} else if (status == 502){
wx.showToast({ title: res.data.msg, duration:3000, icon:'none', complete:function(){
wx.removeStorageSync("userInfo");
wx.navigateTo({ url: '../userLogin/userLogin',
})
}
})
}
}
})
}, uploadVideo: function(e) {
videoUtils.uploadVideo();
}, /**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function() {
}, /**
* 生命周期函数--监听页面显示
*/
onShow: function() {
}, /**
* 生命周期函数--监听页面隐藏
*/
onHide: function() {
}, /**
* 生命周期函数--监听页面卸载
*/
onUnload: function() {
}, /**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function() {
}, /**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function() {
}, /**
* 用户点击右上角分享
*/
onShareAppMessage: function() {
}
})
PS:通过拦截器的方式很好的保护后台的程序正常的运行。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。