springboot+vue实现细粒度的session处理
编写逻辑
1.使用自定义的过滤器去实现servlet的Filter接口,重写doFilter方法
2. 在springboot的入口类上使用@ServletComponentScan注解引入自定义的过滤器
3. 在实现doFilter方法的时候,如果session没有过期,则放行,否则则返回session过期的提示信息给前端
4. 前端接收到session过期(一般都会在请求响应时做统一处理),则提示用户session过期,然后重定向到登录页面即可;
代码示例
-
以下代码参考了部分网友的写法:spring boot使用过滤器(以session校验为例)
-
后端代码:
A.自定义的Filter:
import com.alibaba.fastjson.JSONObject;
import com.itsource.base.common.SdmConst;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
@WebFilter(filterName = "sessionFilter",urlPatterns = {"/*"})
public class SessionFilter implements Filter {
//标示符:表示当前用户未登录(可根据自己项目需要改为json样式)
String EXPIRE_MSG = "{\"data\":{\"code\": \"100003\"}}";
//不需要登录就可以访问的路径(比如:注册登录等)
String[] includeUrls = new String[]{"/tsyslogin/actionTSysLogin.do","/tsysuser/queryTSysMenuTreeByUser.do"};
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpSession session = request.getSession(false);
String uri = request.getRequestURI();
System.out.println("filter url:"+uri);
//是否需要过滤
boolean needFilter = isNeedFilter(uri);
if (!needFilter) { //不需要过滤直接传给下一个过滤器
filterChain.doFilter(servletRequest, servletResponse);
} else { //需要过滤器
// session中包含user对象,则是登录状态
if(session!=null&&session.getAttribute(SdmConst.LOGIN_SESSION_KEY) != null){
// System.out.println("user:"+session.getAttribute("user"));
filterChain.doFilter(request, response);
}else{
String requestType = request.getHeader("X-Requested-With");
//判断是否是ajax请求
if(requestType!=null && "XMLHttpRequest".equals(requestType)){
}else{
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
PrintWriter out = response.getWriter();
JSONObject res = new JSONObject();
res.put("code", "100003");
out.append(res.toString());
}
}
}
}
/**
* @Author: xxxxx
* @Description: 是否需要过滤
* @Date: 2018-03-12 13:20:54
* @param uri
*/
public boolean isNeedFilter(String uri) {
for (String includeUrl : includeUrls) {
if(includeUrl.equals(uri)) {
return false;
}
}
return true;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
B.入口程序:
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.web.servlet.ServletComponentScan;
/**
* 注:为了避免扫描路径不一致,请将启动类放在Root Package 即 com.itsource
*/
@SpringBootApplication(exclude = MongoAutoConfiguration.class)
@MapperScan("**.itsource.**.mapper")
@ServletComponentScan
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
3.前端代码
import axios from 'axios';
// import qs from 'qs';
import router from '@/router';
import ErrorHandling from './error-handling';
import {Modal} from 'ant-design-vue';
import Loading from './loading-toast'
import {crypto} from '../utils';
import Vue from 'vue';
import {merge} from 'lodash';
const Error = new ErrorHandling();
/**
* Axios构造函数
* @method CreatAxios
* @param {Object} config
* @constructor
*/
function CreatAxios(config = {}) {
merge({
// baseURL: '/', // 因为我本地做了反向代理
timeout: 60 * 1000, // 超时处理
responseType: 'json', // 响应数据类型
withCredentials: true, // 是否允许带cookie这些
headers: {
// json 或者 x-www-form-urlencoded 自行选择
// 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
'Content-Type': 'application/json;charset=utf-8'
}
}, config);
const Axios = axios.create(config);
//POST传参序列化(添加请求拦截器)
Axios.interceptors.request.use(
config => {
Loading.open();
// 在发送请求之前做某件事
// 温馨提示,若提交能直接接受json 格式,可以不用 qs 来序列化的
// if (config.method === 'post') {
// // 序列化
// config.data = qs.stringify(config.data);
// }
// 开启上送数据加密
if ((config.hasOwnProperty('encrypt') ? config.encrypt : Vue.config.encrypt) && config.data) {
config.data = crypto.Encrypt(config.data)
}
return config;
},
error => {
Loading.close();
// error 的回调信息
Modal.error({
title: '请求失败',
cancelText: '确定',
content: error && error.data.error.message
});
return Promise.reject(error.data.error.message);
}
);
//返回状态判断(添加响应拦截器)
Axios.interceptors.response.use(
res => {
Loading.close();
//对响应数据做些事
if (res.data) {
//判断session是否过期
if (res.data.code === '100003') {
//
Modal.error({
title: '访问错误',
cancelText: '确定',
content: '用户登录过期,请重新登录!',
onOk: () => {
router.push({
path: '/login'
})
}})
return
}
//请求错误
if (res.data.code !== '000000') {
const err_msg = Error.business(res.data);
// 错误处理
Modal.error({
title: '请求错误',
cancelText: '确定',
content: err_msg,
onOk: () => {
// router.push({
// path: '/login'
// });
}
})
}
// 响应解密
if ((res.config.hasOwnProperty('encrypt') ? res.config.encrypt : Vue.config.encrypt) && res.config.data) {
res.data = crypto.Decrypt(res.data)
}
}
if (res.hasOwnProperty('data')) {
res = res.data
}
return res;
},
error => {
Loading.close();
const errMsg = Error.server(error.response);
Modal.error({
title: '服务器错误',
okText: '确定',
content: errMsg
});
return Promise.reject(error);
}
);
return Axios;
}
// 对axios的实例重新封装成一个plugin ,方便 Vue.use(xxxx)
export default CreatAxios;
以上只是个人的用法,在此做一个记录,仅供参考!

本文介绍了一种使用SpringBoot和Vue实现细粒度session管理的方法,通过自定义过滤器检查session状态,有效处理session过期情况,前端对接收的session过期信息进行处理并重定向至登录页面。
2万+





