2.网关中配置过滤器原理
3.资料学习
学习内容: 1.实例中各部分方法的实际意义
2.原理来源于那些基础知识
3.java8新知识学习
学习产出: 1 网关中配置过滤器实例
1.1网关中配置过滤器java代码实现
import com.alibaba.fastjson.JSON;
import com.heima.admin.utils.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component
@Slf4j
@Order(0) // 越小越优先执行
//GlobalFilter处理链接web请求
public class AuthorizeFilter implements GlobalFilter {
List urlList = Arrays.asList(
"/v2/api-docs",
"/login/in"
);
@Override
public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//1 判断用户是否登录
//2 是登陆则放行
// if (url.contains("/login/in")) {
// return chain.filter(exchange);
// }
String url = request.getURI().getPath();
for (String urls : urlList){
//测试此字符串是否以指定的后缀结尾
if (url.endsWith(urls)) {
//调用网关过滤器
return chain.filter(exchange);//放行
}
}
//3 从 head 获取token
String token = request.getHeaders().getFirst("token");
//3.1 无 token 返回提示信息和401 拦截
if (StringUtils.isBlank(token)) {
//如果不存在,向客户端返回错误提示信息
Map resultMap = new HashMap<>();
resultMap.put("host", request.getRemoteAddress().getHostName());
resultMap.put("code", HttpStatus.UNAUTHORIZED.value());
resultMap.put("errorMessage", "需要登录");
return writeMessage(exchange, resultMap);
}
try {
//3.2 有 token 校验token合法性, 无效则返回提示信息和401
//获取payload body信息
Claims claims = AppJwtUtil.getClaimsBody(token);
//-1 0 -》有效 1 2 -》 无效
//是否过期
int verifyToken = AppJwtUtil.verifyToken(claims);
if (verifyToken > 0) { // 无效 拦截
Map resultMap = new HashMap<>();
resultMap.put("host", request.getRemoteAddress().getHostName());
resultMap.put("code", HttpStatus.UNAUTHORIZED.value());
resultMap.put("errorMessage", "登录已过期,请重新登录");
return writeMessage(exchange, resultMap);
}
//4 有效:解析jwt令牌,获取的用户id body信息就是token json形式信息
Integer id = claims.get("id", Integer.class);
//5 把用户的id 转发到各个微服务中
//mutate变异,创建出ServerHttpRequest建设者-->建设者操纵请求头(加入userId)-->建设完成【这个和pojos类里面的建设者模式一样】
ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
httpHeaders.add("userId", String.valueOf(id));
}).build();
//服务交换给各个wei服务
exchange.mutate().request(serverHttpRequest);
} catch (Exception e) {
// e.printStackTrace();
// 记录日志
log.error("jwt verifyToken is fail,url:{}", url);
Map resultMap = new HashMap<>();
resultMap.put("host", request.getRemoteAddress().getHostName());
resultMap.put("code", HttpStatus.UNAUTHORIZED.value());
resultMap.put("errorMessage", "登录失败,请重新登录");
return writeMessage(exchange, resultMap);
}
//6 放行
return chain.filter(exchange);
}
private Mono writeMessage(ServerWebExchange exchange, Map resultMap) {
//获取响应对象
ServerHttpResponse response = exchange.getResponse();
//设置状态码
response.setStatusCode(HttpStatus.UNAUTHORIZED);
//response.setStatusCode(HttpStatus.OK);
//设置返回类型 json
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
//设置返回数据
DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONBytes(resultMap));
//响应数据回浏览器
return response.writeWith(Flux.just(buffer));
}
}
1.2网关中配置过滤器yml文件
server:
port: 6001
spring:
application:
name: 模块名字
cloud:
nacos:
discovery:
server-addr: 192.168.200.129:8848
gateway:
globalcors:
cors-configurations:
'[
public static String getToken(Long id) {
Map claimMaps = new HashMap<>();
claimMaps.put("id", id);
long currentTime = System.currentTimeMillis();
return Jwts.builder().setId(UUID.randomUUID().toString())
.setIssuedAt(new Date(currentTime)) //签发时间
.setSubject("system") //说明
.setIssuer("heima") //签发者信息
.setAudience("app") //接收用户
.compressWith(CompressionCodecs.GZIP) //数据压缩方式
.signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式
.setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000)) //过期时间戳
.addClaims(claimMaps) //cla信息 自定义信息
.compact();
}
private static Jws getJws(String token) {
return Jwts.parser().setSigningKey(generalKey()).parseClaimsJws(token);
}
public static Claims getClaimsBody(String token) {
try {
return getJws(token).getBody();
} catch (ExpiredJwtException e) {
return null;
}
}
public static JwsHeader getHeaderBody(String token) {
return getJws(token).getHeader();
}
public static int verifyToken(Claims claims) {
if (claims == null) {
return 1;
}
try {
claims.getExpiration().before(new Date());
// 需要自动刷新TOKEN
if ((claims.getExpiration().getTime() - System.currentTimeMillis()) > REFRESH_TIME * 1000) {
return -1;
} else {
return 0;
}
} catch (ExpiredJwtException ex) {
return 1;
} catch (Exception e) {
return 2;
}
}
public static SecretKey generalKey() {
byte[] encodedKey = base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
public static void main(String[] args) {
System.out.println(AppJwtUtil.getToken(1102L));
Jws jws = AppJwtUtil.getJws("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAADWLQQqEMAwA_5KzhURNt_qb1KZYQSi0wi6Lf9942NsMw3zh6AVW2DYmDGl2WabkZgreCaM6VXzhFBfJMcMARTqsxIG9Z888QLui3e3Tup5Pb81013KKmVzJTGo11nf9n8v4nMUaEY73DzTabjmDAAAA.4SuqQ42IGqCgBai6qd4RaVpVxTlZIWC826QA9kLvt9d-yVUw82gU47HDaSfOzgAcloZedYNNpUcd18Ne8vvjQA");
Claims claims = jws.getBody();
System.out.println(claims.get("id"));
}
}
2 网关中配置过滤器原理
2.1 GlobalFilter
package org.springframework.cloud.gateway.filter;
import reactor.core.publisher.Mono;
import org.springframework.web.server.ServerWebExchange;
//GlobalFilter处理链接web请求的方法
public interface GlobalFilter {
Mono filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
2.2 GatewayFilterChain网关过滤器链
2.3 网关过滤器∧ λ /'læmdə/ lambda 兰姆达 表达式
2.4 设计模式之建设者模式
https://blog.csdn.net/u010342008/article/details/45565531
2.5 Spring Cloud Gateway网关原理
https://www.cnblogs.com/lucky-yqy/p/13965296.html
2.6 lambda各种用法
由匿名内部类而来,中间存在不完全简写体,最简体。
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
public class LambdaDemo {
@Test
public void test1() {
//匿名内部类
Runnable r1 = new Runnable() {
public void run() {
System.out.println("我爱北京天安门你");
}
};
r1.run();
//lambda表达式
Runnable r2 = () -> System.out.println("我爱北京天安门你");
r2.run();
}
@Test
public void Test2() {
Comparator com1 = new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
System.out.println(com1.compare(15, 16));
//lambda表达式
Comparator com2 = (o1, o2) -> Integer.compare(o1, o2);
System.out.println(com2.compare(17, 16));
//方法引用
Comparator com3 = Integer::compare;
System.out.println(com3.compare(18, 16));
}
@Test
public void Test3() {
Consumer con = new Consumer() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
con.accept("谎言和誓言的区别是什么?");
//lambda
//Consumer con2 =(s )-> {System.out.println(s);};
//Consumer con2 =s -> {System.out.println(s);};
Consumer con2 = s -> System.out.println(s);
con2.accept("谎言和誓言的区别是什么?");
}
@Test
public void Test4() {
Comparator com = new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
System.out.println(o1);
System.out.println(o2);
return Integer.compare(o1, o2);
}
};
System.out.println(com.compare(13, 4));
//
Comparator com2 = (o1, o2) -> {
System.out.println(o1);
System.out.println(o2);
return Integer.compare(o1, o2);
};
System.out.println(com2.compare(23, 7));
}
@Test
public void Test5(){
Comparator com =new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
System.out.println(com.compare(13,4));
//类型不同不可省略类型
Comparator com2=(o1,o2) -> o1.compareTo(o2);
System.out.println(com2.compare(13,4));
}
}
2.7 Optional操作
import org.junit.Test;
import java.math.BigDecimal;
import java.util.Optional;
public class OptionalDemo {
@Test
public void test1() {
PaymentChange paymentChange = new PaymentChange();
BigDecimal bigAbmout = Optional.ofNullable(paymentChange.getPaymentChangeMoney()).orElseGet(() -> BigDecimal.ZERO).setScale(2, BigDecimal.ROUND_HALF_UP);
}
@Test
public void test2() {
PaymentChange paymentChange = new PaymentChange();
BigDecimal bigAbmout = Optional.ofNullable(paymentChange.getPaymentChangeMoney()).orElse(BigDecimal.ZERO);
}
}
import java.math.BigDecimal;
public class PaymentChange {
public BigDecimal getPaymentChangeMoney() {
return new BigDecimal("222222222222222222222222222222222");
}
}
2.8 stream流式操作
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
public class StreamDemo {
//传统for循环
//迭代器
//增强for循环
//流式
@Test
public void test1() {
//类型转换1
List studentList = new ArrayList<>();
List studentNos = new ArrayList();
for (Student student : studentList) {
studentNos.add(student.getStudentNo());
}
//Stream
List studentNos2 = studentList.stream().map(Student::getStudentNo).collect(Collectors.toList());
}
@Test
public void test2() {
//类型转换2
List studentList = new ArrayList<>();
for (Student student : studentList) {
if ("0001".equals(student.getStudentNo())) {
System.out.println(student.getName());
}
}
//Stream
Map collect = studentList.stream()
.collect(Collectors.toMap(Student::getStudentNo, Student::getName));
System.out.println(collect.get("0001"));
}
@Test
public void test3() {
//过滤
List studentList = new ArrayList<>();
List manList = new ArrayList();
for (Student student : studentList) {
if (student.getSex().equals(1)) {
manList.add(student);
}
}
//Stream+Lambda
List manList2 = studentList.stream()
.filter(s -> s.getSex()
.equals(1)).collect(Collectors.toList());
}
@Test
public void test4() {
//排序
List studentList = new ArrayList<>();
List manList = new ArrayList();
for (Student student : studentList) {
if (student.getAge() > studentList.get(0).getAge()) {
manList.add(student);
}
}
//Stream+Lambda
studentList.stream().
sorted(Comparator.comparing(Student::getAge).reversed()).collect(Collectors.toList());
}
@Test
public void test5() {
//去重
List studentList = new ArrayList<>();
List collect2 = studentList.stream().distinct().collect(Collectors.toList());
//也可以根据某一属性去重
studentList.stream()
.collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet(Comparator.comparingLong(Student::getAge))), ArrayList::new));
}
@Test
public void test6() {
//快速找到集合中想要匹配的数据
List studentList = new ArrayList<>();
//是否存在学号为0001的人
boolean match = studentList.stream().anyMatch(detail -> "0001".equals(detail.getStudentNo()));
}
@Test
public void test7() {
List studentList = new ArrayList<>();
//跳过前面n个元素
List skipList = studentList.stream().skip(2).collect(Collectors.toList());
//取前n个元素
List limitList = studentList.stream().limit(2).collect(Collectors.toList());
}
@Test
public void test8() {
List list = new ArrayList<>();
list.stream().collect(Collectors.toList());
//把流中元素收集到List
list.stream().collect(Collectors.toSet());
//把流中元素收集到Set
list.stream().collect(Collectors.toCollection(ArrayList::new));
//把流中元素收集到创建的集合
list.stream().collect(Collectors.counting());
//计算流中元素的个数
list.stream().collect(Collectors.summingInt(Student::getAge));
//对流中元素的整数属性求和
list.stream().collect(Collectors.averagingInt(Student::getAge));
//计算流中元素Integer属性的平均值
list.stream().collect(Collectors.summarizingInt(Student::getAge));
//收集流中Integer属性的统计值。如:平均值
list.stream().collect(Collectors.groupingBy(Student::getAge));
//根据某属性值对流分组,属性为K,结果为V
//最大值maxBy和最小值 minBy
}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
String name;
String studentNo;
String sex;
Integer age;
}
3 java8新知识学习
3.1 Java Lambda 表达式
https://www.runoob.com/java/java8-lambda-expressions.html
3.2 Java optional 操作
https://www.runoob.com/java/java8-optional-class.html
https://www.cnblogs.com/zhangboyu/p/7580262.html
3.3 Java streams操作
https://www.runoob.com/java/java8-streams.html



