环境:jdk17,springboot3.1.12

功能

  1. 配置文件
  2. jwt拦截,进行登录
  3. 切面类制作
  4. 异常捕获

依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--mysql驱动 2023-4-18-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!--mybatisPlus 2023-8-8-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.5</version>
</dependency>

<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>

<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

配置文件

application.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
spring.application.name=demo1
server.port=9090
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=196691
spring.mvc.pathmatch.matching-strategy=ant_path_matcher

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus.mapper-locations=classpath:mapper/*.xml

spring.servlet.multipart.max-file-size=20MB
spring.servlet.multipart.max-request-size=20MB

结果封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.zou.common;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
private int code;
private String msg;
private T data;

public static <T> Result<T> success(String msg) {
return new Result<>(200, msg, null);
}

public static <T> Result<T> success(String msg, T data) {
return new Result<>(200, msg, data);
}

public static <T> Result<T> error(String msg) {
return new Result<>(500, msg, null);
}
}

jwt拦截

jwt工具类:负责生成,解析token,从token获取用户信息

jwt拦截器:对所有请求进行拦截,校验失败抛出异常

webConfig:接口拼接/api前缀,拦截器 注册,跨域处理

JwtUtil

创建jwt工具类 JwtUtil

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package com.zou.common;

import com.zou.pojo.User;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;

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

@Configuration
@Slf4j
public class JwtUtil {
//密钥
private static final String secret = "zouwen";
//springboot3换了xml依赖,导致生成的秘钥要256位,如果是上面长度只要32位会报错。
private static final SecretKey secret1 = Keys.secretKeyFor(SignatureAlgorithm.HS256);
//过期时间
private static final long expirationTime = 1000*60*60;
/**
* 生成token==>传入用户,过期时间,密钥
* @param user
* @return
*/
public String generateToken(User user) {
log.info("jwt开始生成token,获取到的用户:"+user);
return Jwts.builder()
.claim("username",user.getUsername())
.setExpiration(new Date(System.currentTimeMillis()+expirationTime))
.signWith(SignatureAlgorithm.HS256,secret1)
.compact();
}
/**
* 校验token
* @param token
* @return
*/
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secret1).parseClaimsJws(token);
// Jwts.parserBuilder().setSigningKey(secret1).build().parseClaimsJws(token);
log.info("jwt验证秘钥成功");
return true;
} catch (Exception e) {
log.error("jwt验证秘钥失败");
return false;
}
}
/**
* 从token获取用户对象
* @param BearerToken
* @return
*/
public User getUserFromToken(String BearerToken){
String token = BearerToken.substring(7);
log.warn("jwt开始解析token");
Claims claims = Jwts.parserBuilder()
.setSigningKey(secret1)
.build()
.parseClaimsJws(token)
.getBody();
// 解析创建user对象并返回
String username = (String) claims.get("username");
User user = new User();
user.setUsername(username);
return user;
}
}

JwtInterceptor

创建jwt拦截器 JwtInterceptor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.zou.Interceptor;

import com.zou.common.JwtUtil;
import com.zou.exception.CustomException;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Enumeration;

@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
@Resource
private JwtUtil jwtUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

log.error("经过jwt拦截器预处理");
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
return true;
}
// 获取请求路径
String requestPath = request.getRequestURI();
log.info("jwt拦截器拦截请求路径为:"+requestPath);
String header = request.getHeader("User-Agent");
log.info("jwt拦截器拦截请求头为:"+header);
Enumeration<String> headerNames = request.getHeaderNames();
log.info("所有请求头的名称"+headerNames);
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
System.out.println(headerName);
}
String authorizationHeader = request.getHeader("Authorization");
log.warn("jwt拦截器拿到请求头"+authorizationHeader);
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
// 提取token
String token = authorizationHeader.substring(7);
log.info("token为为:"+token);
// 对token进行验证和处理
// ... 进行你的操作,例如解析、校验等
boolean b = jwtUtil.validateToken(token);
if(!b){
log.error("检测到token有值,但是校验失败");
throw new CustomException("token验证失败---->jwt");
}
} else {
// 未找到有效的Authorization字段
log.warn("无效的token");
return false;

}
return true; // 返回true表示允许继续处理该请求
}
}

WebConfig

创建WebConfig实现WebMvcConfigurer接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.zou.config;

import com.zou.Interceptor.JwtInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.method.HandlerTypePredicate;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Slf4j
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
//接口统一拼接/api
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.addPathPrefix("/api", HandlerTypePredicate.forBasePackage("com.zou.controller"));
}

//加上自定义拦截器,哪些请求需要携带token,哪些请求不需要
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor).addPathPatterns("/api/**")
.excludePathPatterns("/api/user/register")
.excludePathPatterns("/api/user/login")
.excludePathPatterns("/api/file/upload")
.excludePathPatterns("/api/file/**")
.order(Ordered.HIGHEST_PRECEDENCE);;
}

//跨域处理
@Override
public void addCorsMappings(CorsRegistry registry) {
log.warn("经过cors");
//添加映射路径
registry.addMapping("/**")
//是否发送Cookie
.allowCredentials(true)
//设置放行哪些原始域 SpringBoot2.4.4下低版本使用.allowedOrigins("*")
.allowedOriginPatterns("*")
//放行哪些请求方式
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
//.allowedMethods("*") //或者放行全部
//放行哪些原始请求头部信息
.allowedHeaders("*")
//暴露哪些原始请求头部信息
.exposedHeaders("*");
}
}

异常

全局异常

创建GlobalException用来处理全局异常,通过ControllerAdvice可以获取所有异常,然后把自定义异常注入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.zou.exception;

import com.zou.common.Result;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

@ControllerAdvice("com.example.controller")
@Slf4j
public class GlobalException {

//全局异常处理器
@ExceptionHandler(Exception.class)
@ResponseBody
public Result error(Exception e, HttpServletRequest request) {
log.error("异常信息",e);
return Result.error("系统异常");
}
//自定义异常处理器
@ExceptionHandler(CustomException.class)
@ResponseBody
public Result error(CustomException e, HttpServletRequest request) {
return Result.error(e.getMsg());
}

}

自定义异常

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.zou.exception;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

//自定义异常
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CustomException extends RuntimeException{
private String msg;
}

切面

自定义注解

拦截所有方法,作用域

1
2
3
4
5
6
7
8
9
10
package com.zou.common;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoLog {
String value() default "";
}

切面类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.zou.config;

import com.zou.common.AutoLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Slf4j
@Component
public class LogAspect {
@Around("@annotation(autoLog)")
public Object doAround(ProceedingJoinPoint joinPoint, AutoLog autoLog) throws Throwable{
log.info("我是门卫");
return joinPoint.proceed();
}
}

使用

1
2
3
4
5
6
@AutoLog
@GetMapping("/getinfo")
public Result getInfo(@RequestHeader("Authorization") String token){
User info = userService.getInfo(token);
return Result.success("获取用户信息成功",info);
}

用户信息

controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.zou.controller;
import com.zou.common.AutoLog;
import com.zou.common.Result;
import com.zou.pojo.User;
import com.zou.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

@Autowired
private UserService userService;


/**
* 获取所有
* @return
*/
@GetMapping("/getall")
public Result getAll() {

return userService.getAll();
}

/**
* 注册
* @param user
* @return
*/
@PostMapping("/register")
public Result register(User user){
return userService.register(user);
}

/**
* 登录
* @param user
* @return
*/
@PostMapping("/login")
public Result login(User user){
return userService.login(user);
}

/**
* 获取用户信息
* @param token
* @return
*/
@AutoLog
@GetMapping("/getinfo")
public Result getInfo(@RequestHeader("Authorization") String token){
return userService.getInfo(token);
}

}

service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package com.zou.service.Impl;
import com.zou.common.JwtUtil;
import com.zou.common.Result;
import com.zou.mapper.UserMapper;
import com.zou.pojo.User;
import com.zou.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private JwtUtil jwtUtil;
@Autowired
private UserMapper userMapper;

/**
* 获取所有用户
* @return
*/
@Override
public Result getAll() {
List<User> all = userMapper.getAll();
for (User user : userMapper.getAll()) {
System.out.println(user);
}
return Result.success("查询所有用户成功",all);
}

/**
* 注册
* @param user
* @return
*/
@Override
public Result register(User user) {
//1.判断用户名是否存在
User byUsername = userMapper.getByUsername(user);
if(byUsername != null){
return Result.error("注册失败,用户名重复");
}
//2.用户正常注册,插入数据库
Boolean register = userMapper.register(user);
if(register){
return Result.success("注册用户成功");
}else {
return Result.error("注册用户失败");
}
}

/**
* 登录
* @param user
* @return
*/
@Override
public Result login(User user) {
//1.查询用户是否存在
User byUsername = userMapper.getByUsername(user);
if(byUsername != null){
//2.比对密码
if(byUsername.getPassword().equals(user.getPassword())){
//生成token返回前端
String token = jwtUtil.generateToken(user);
return Result.success("用户登录成功",token);
}else{
return Result.error("密码错误");
}

}else {
//用户不存在,提示用户不存在
return Result.error("用户不存在");
}
}

/**
* 获取用户信息
* @param token
* @return
*/

@Override
public Result getInfo(String token) {
User userFromToken = jwtUtil.getUserFromToken(token);
User byUsername = userMapper.getByUsername(userFromToken);
return Result.success("获取用户信息成功",byUsername);
}
}

mapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zou.mapper.UserMapper">
<insert id="register" parameterType="com.zou.pojo.User">
insert into user (id,username,password) values(#{id},#{username},#{password})
</insert>
<select id="getAll" resultType="com.zou.pojo.User">
select * from user
</select>
<select id="getByUsername" resultType="com.zou.pojo.User" parameterType="com.zou.pojo.User">
select * from user where username = #{username}
</select>
</mapper>