以前我們把用戶登陸,註冊成功的信息都放到redis裏面了,若是產品經理有一種場景,就是同一個用戶在同一個時間以最後一個登陸爲準,那麼前一個就須要從新登陸,而且清空前一個用戶緩存。這就用到了springboot的緩存機制。源碼:github.com/limingios/w… 中No.15和springboot前端
經過前端傳遞過來的userToken,和從redis裏面獲取到的userToken對比,若是不一致,前端傳遞過來的這個session獎盃提示用戶被擠出,直接緩存失效。須要從新登陸。java
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,肯定請求是否合法。ios
原來我們在spring mvc的時候都是經過xml配置文件的方法,springboot爲了簡化,都是經過java來進行配置,剛建立的攔截器須要配置在webconfig裏面git
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;
@Configuration
public 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進行提示並清空用戶信息緩存。github
// pages/mine/mine.js
const 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:經過攔截器的方式很好的保護後臺的程序正常的運行。web