当前位置: 首页 > news >正文

JAVA WEB学习20

优化 2:Token 刷新机制(避免频繁登录)
用户登录后生成访问 token(短期,2 小时) + 刷新 token(长期,7 天),访问 token 过期后,前端用刷新 token 获取新的访问 token,无需重新登录。

  1. 扩展 JwtUtil(支持生成刷新 token)
    java
    运行
    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.security.Keys;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;

@Component
public class JwtUtil {
@Value("${jwt.secret:abcdefghijklmnopqrstuvwxyz1234567890}")
private String secret;

// 访问token有效期:2小时
@Value("${jwt.access-expire:7200000}")
private long accessExpire;// 刷新token有效期:7天
@Value("${jwt.refresh-expire:604800000}")
private long refreshExpire;// 生成访问token
public String generateAccessToken(String username) {return generateToken(username, accessExpire);
}// 生成刷新token
public String generateRefreshToken(String username) {return generateToken(username, refreshExpire);
}// 通用生成token方法
private String generateToken(String username, long expire) {SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());return Jwts.builder().claim("username", username).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + expire)).signWith(key).compact();
}// 解析token
public Claims parseToken(String token) {SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());return Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
}// 校验token
public boolean validateToken(String token) {try {Claims claims = parseToken(token);return !claims.getExpiration().before(new Date());} catch (Exception e) {return false;}
}// 获取用户名
public String getUsernameFromToken(String token) {Claims claims = parseToken(token);return claims.get("username", String.class);
}

}
2. 修改登录接口(返回双 token)
java
运行
@PostMapping("/login")
public Result<Map<String, String>> login(@RequestBody LoginDTO loginDTO) {
String accessToken = userService.login(loginDTO);
// 生成刷新token
String refreshToken = jwtUtil.generateRefreshToken(loginDTO.getUsername());
Map<String, String> resultMap = new HashMap<>();
resultMap.put("accessToken", accessToken);
resultMap.put("refreshToken", refreshToken);
return Result.success(resultMap);
}
3. 新增刷新 token 接口
java
运行
// 刷新token接口(无需拦截,因为refreshToken本身是长期有效)
@PostMapping("/refresh")
public Result<Map<String, String>> refresh(@RequestBody Map<String, String> params) {
String refreshToken = params.get("refreshToken");
// 校验刷新token
if (!jwtUtil.validateToken(refreshToken)) {
throw new RuntimeException("刷新token无效,请重新登录");
}
// 获取用户名,生成新的访问token
String username = jwtUtil.getUsernameFromToken(refreshToken);
String newAccessToken = jwtUtil.generateAccessToken(username);
Map<String, String> resultMap = new HashMap<>();
resultMap.put("accessToken", newAccessToken);
return Result.success(resultMap);
}
三、优化 3:前端整合 JWT(Vue 示例)
前端需存储 token、请求时携带 token、处理 token 过期自动刷新,这里用 Vue+Axios 演示核心逻辑:

  1. Axios 请求拦截器(携带 token)
    javascript
    运行
    // request.js
    import axios from 'axios';
    import { ElMessage } from 'element-plus';

const service = axios.create({
baseURL: 'http://localhost:8080',
timeout: 5000
});

// 请求拦截器:添加token
service.interceptors.request.use(
config => {
const token = localStorage.getItem('accessToken');
if (token) {
// 按约定格式携带token
config.headers['Authorization'] = Bearer ${token};
}
return config;
},
error => {
return Promise.reject(error);
}
);

// 响应拦截器:处理token过期
service.interceptors.response.use(
response => {
return response.data;
},
async error => {
const { response } = error;
// 401表示token过期
if (response && response.data.code === 401) {
const refreshToken = localStorage.getItem('refreshToken');
if (!refreshToken) {
// 无刷新token,跳转登录页
ElMessage.error('登录已过期,请重新登录');
window.location.href = '/login';
return Promise.reject(error);
}
// 用刷新token获取新的访问token
try {
const res = await axios.post('http://localhost:8080/user/refresh', {
refreshToken: refreshToken
});
// 存储新的accessToken
localStorage.setItem('accessToken', res.data.data.accessToken);
// 重新发起原请求
return service(error.config);
} catch (e) {
ElMessage.error('登录已过期,请重新登录');
window.location.href = '/login';
return Promise.reject(e);
}
}
ElMessage.error(error.message);
return Promise.reject(error);
}
);

export default service;
2. 登录 / 注册逻辑
javascript
运行
// userApi.js
import request from './request';

// 登录
export const login = (data) => {
return request({
url: '/user/login',
method: 'post',
data
});
};

// 注册
export const register = (data) => {
return request({
url: '/user/register',
method: 'post',
data
});
};

// 获取用户列表
export const getUserList = () => {
return request({
url: '/user/list',
method: 'get'
});
};
3. 登录页面调用
javascript
运行
// login.vue
import { login } from '@/api/userApi';

const handleLogin = async () => {
const res = await login({
username: 'admin',
password: '123456'
});
// 存储token到本地
localStorage.setItem('accessToken', res.data.accessToken);
localStorage.setItem('refreshToken', res.data.refreshToken);
// 跳转首页
router.push('/home');
};
四、优化 4:完善全局异常处理(更友好的提示)
修改GlobalExceptionHandler.java,细分异常类型,返回更精准的错误码:
java
运行
import com.example.common.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**

  • 全局异常处理器
    */
    @RestControllerAdvice
    public class GlobalExceptionHandler {
    // 处理业务异常(自定义)
    @ExceptionHandler(RuntimeException.class)
    public Result handleRuntimeException(RuntimeException e) {
    return Result.error(e.getMessage());
    }

    // 处理所有其他异常
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e) {
    e.printStackTrace();
    return Result.error("服务器内部错误,请联系管理员");
    }
    }
    五、配置文件完善(application.yml)
    yaml
    spring:
    datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/java_web_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456

JWT配置

jwt:

建议生产环境用32位以上随机字符串,可通过工具生成

secret: abcdefghijklmnopqrstuvwxyz1234567890abcdef

访问token有效期:2小时(毫秒)

access-expire: 7200000

刷新token有效期:7天(毫秒)

refresh-expire: 604800000

server:
port: 8080
总结
密码安全:用 BCrypt 替代 MD5 加密密码,自带盐值,安全性更高,是企业标准做法;
Token 刷新:双 token 机制(accessToken 短期 + refreshToken 长期),避免用户频繁登录,提升体验;
前端整合:通过 Axios 拦截器统一处理 token 的携带、过期刷新,实现前后端 token 闭环;
异常处理:细分异常类型,返回精准错误信息,方便前端处理和问题排查。

http://www.jsqmd.com/news/424148/

相关文章:

  • JAVA WEB学习19
  • 嵌入模型与Chroma向量数据库 - Chroma 集合查询操作 - AI大模型应用开发必备知识
  • 大家觉得windows系统的更新有必要每次都更新吗?会不会系统越高,越卡顿?
  • 通信工程毕业设计最新方向怎么选
  • 2026年杰家板材厂靠谱吗,探讨其行业认可度、环保性与交货及时性 - myqiye
  • 父系指数和母系指数
  • 探寻2026年粉末压机优质源头,这些厂家不容错过,伺服热压机/平板油压机/伺服油压机/粉末压机,粉末压机厂家哪家好 - 品牌推荐师
  • LangGraph4j 学习系列(2)-条件工作流
  • 2026年选购指南:主流摩擦系数仪厂家综合对比,摩擦系数仪/检测仪/试验机/分析仪/测试仪/测量仪,摩擦系数仪工厂选哪家 - 品牌推荐师
  • 聊聊江西初中毕业选院校的经验,江西新华电脑学院口碑怎么样? - 工业品牌热点
  • 2026年市面上优秀的自立袋销售厂家推荐,中封袋/四边封包装袋/八边封包装袋/三边封包装袋,自立袋生产商排行榜 - 品牌推荐师
  • 三菱FX5U伺服机器人程序开发指南
  • 2026年市场口碑佳的ISO认证公司TOP榜,助力企业品质提升,知识产权认证/3C认证,ISO认证公司哪家好 - 品牌推荐师
  • 分析江苏数控折弯机质量可靠的厂家排名,有哪些上榜? - 工业推荐榜
  • 论云原生架构在高并发系统中的设计与实践
  • 2026年全国上诉律师服务费用大汇总,专业上诉律师哪家权威怎么选 - 工业品网
  • YOLOv13涨点改进| CVPR 2026 |独家创新首发、特征融合改进篇 | 引入 LFSB 差分双维注意融合模块,通过交替特征融合与分离策略,能够精准区分目标特征,顶会助力YOLOv13有效涨点
  • free AI Music Generator All In One
  • 国产化编辑器怎样兼容Word复杂格式导入?
  • 讲讲泰艺包装有实力吗,在深圳地区口碑怎么样 - 工业品牌热点
  • CO-STAR提示词模板深度解析:从冠军框架到实战应用
  • 2026年广州热门除甲醛产品年度排名靠谱的品牌口碑佳 - mypinpai
  • 日本数学教育家“dy/dx不是分数”谬论使学生不能正确认识导数概念
  • 别再瞎找了!降AIGC软件 千笔·降AIGC助手 VS 学术猹,本科生专属神器!
  • Rust开发必备:深入解析标准库与第三方Derive宏的核心差异与应用实践
  • 农业系统如何集成Word文档样式解析组件?
  • 2026年水泵选购指南:热门型号与性能排名解析,酸碱中和实验室污水设备/大通量滤芯,水泵生产商排名 - 品牌推荐师
  • 导师推荐 9个降AI率软件降AIGC网站:本科生降AI率必备工具深度测评
  • 国防项目富文本工具支持Word截图粘贴吗?
  • 赶deadline必备! 10个AI论文工具测评:专科生毕业论文写作神器推荐