1. 导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. 端口配置
server:
port: 8080
3. 统一功能处理
3.1 拦截器
3.1.1 生成
package com.example.config;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@Component
public class RequestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 鉴权
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("username") == null) {
response.setStatus(401);
return false;
}
return true;
}
}
3.1.2 注册
package com.example.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private RequestInterceptor requestInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
}
3.2 统一数据返回
3.2.1 创建公共返回类
package com.example.model;
import lombok.Data;
@Data
public class Result {
private Integer code;
private String msg;
private Object data;
public static Result success(Object data) {
return new Result(200, "success", data);
}
public static Result fail(String msg) {
return new Result(404, msg, null);
}
}
3.2.2 实现
package com.example.config;
import com.example.model.Result;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.SneakyThrows;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.lang.reflect.Method;
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
private final static JsonMapper mapper = new JsonMapper();
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
// 获取执行方法
Method method = returnType.getMethod();
System.out.println(method.getName());
return true;
}
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body instanceof Result) {
// 包含统一响应格式或异常处理直接返回
return body;
} else if (body instanceof String) {
// String由于映射器原因,直接返回对象会报错,需要转换一下
return mapper.writeValueAsString(Result.success(body));
}
return Result.success(body);
}
}
3.3 统一异常处理
异常处理捕获后会从子到父依次匹配。
package com.example.config;
import com.example.model.Result;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ResponseBody
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler
public Object handler(Exception e) {
return Result.fail("内部错误");
}
@ExceptionHandler
public Object handler(NullPointerException e) {
return Result.fail("NullPointerException");
}
}
3.4 执行顺序
拦截器
目标方法 统一异常处理 统一数据返回
拦截器
4. token令牌
分布式系统下使用token校验可以省去通过网络去校验的方式,本地完成鉴权,实现更高效率。
使用JWT令牌实现。JWT全称: JSON Web Token
官网: https://jwt.io/
4.1 引入依赖
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-impl -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is
preferred -->
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
4.2 创建token工具类
package com.example.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import java.security.Key;
import java.util.Date;
import java.util.Map;
@Slf4j
public class JwtUtils {
private static final long JWT_EXPIRATION = 60 * 60 * 1000;
private static final String secretStr = "Le++o8NQWVXWo3+SJtAtnjBW9iA0OvPL0c0mMrol2fU=";
private static final Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretStr));
/**
* 生成token
*
* @param claim 用户特征信息
*/
public static String generateJwtToken(Map<String, Object> claim) {
String token = Jwts.builder().setClaims(claim)
.setExpiration(new Date(System.currentTimeMillis() + JWT_EXPIRATION))
.signWith(key)
.compact();
return token;
}
/**
* 校验token
*
* @return Claims为null表示校验失败
*/
public static Claims parseToken(String token) {
JwtParser build = Jwts.parserBuilder().setSigningKey(key).build();
Claims claims = null;
try {
claims = build.parseClaimsJws(token).getBody();
} catch (Exception e) {
log.error("解析token失败, token:{}", token);
return null;
}
return claims;
}
}
4.3 拦截器改为token校验
package com.example.config;
import com.example.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class RequestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 鉴权
String token = request.getHeader("token");
Claims claims = JwtUtils.parseToken(token);
if (claims == null) {
response.setStatus(401);
return false;
}
return true;
}
}