<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
dependencies>
第二步:在sca-ui工程中创建一个springboot启动类,类全名为com.jt.DemoUIApplication.
package com.jt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoUIApplication {
public static void main(String[] args) {
SpringApplication.run(DemoUIApplication.class, args);
}
}
第三步:在sca-ui工程的resources目录下创建一个static目录,并在此目录中创建一个index.html页面
第四步:启动sca-ui工程,在浏览器中输入http://localhost:8080/index.html进行测试.
JAVA_HOME环境变量定义错误,例如:
说明,这里一定要注意JAVA_HOME单词的拼写,JAVA_HOME中定义的JDK是存在的,还有后面的路径不能有分号“;”.
MySQL版本比较低(建议mysql5.7或mariadb10.5及以上版本),例如:
当执行nacos-mysql.sql文件时,出现如下错误:
sql文件不存在,例如
SQL文件应用错误,例如:
服务启动时,端口被占用了。例如:
磁盘写权限问题(nacos服务启动时会在当前磁盘目录写日志),例如:
服务调用时,连接异常,例如:
客户端404异常,例如:
服务访问问题,例如:
依赖注入异常,例如:
客户端请求方式与服务端不匹配,例如:
依赖版本问题,例如:
服务配置读取问题,例如:
SocketTimeoutException,例如:
NullPointerException,例如:
负载均衡类的配置问题,例如:
端口被占用,例如
UnknownHostException,例如
Fien接口对象依赖注入异常,例如:
数据读取超时,例如:
服务访问时的404异常,例如:
Feign接口方法中@PathVariable注解参数定义问题,例如:
读数据超时,例如:
依赖注入异常,例如:
方案1:修改sca-consumer配置文件(application.yml),添加如下语句,例如:
sca-provider: #这个是要进行远程调用的服务id(服务名)
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡算法
对于方案1写法,在写的过程没有提示,编写困难,但是将来的可运维性会比较好,我们这部分配置写到配置中心,不需要重启服务即可实现配置的动态发布,动态更新。
方案2:修改sca-consumer的启动类,在启动类中添加如下方法,例如:
@Bean
public IRule ribbonRule() {
return new RandomRule();
}
对于方案2的写法,编写相对简单,编写过程都有提示,但是将来的可运维性比较差,项目打包以后,我们无法再修改负载均衡算法。
在ProviderCacheController,进行本地缓存设计应用,例如:
private CopyOnWriteArrayList<String> cache=new CopyOnWriteArrayList<>();
@GetMapping("/provider/cache02")
public List<String> doUseLocalCache02(){
if(!useLocalCache){//假如useLocalCache的值为false,表示不开启本地cache.
log.info("select data from database");
return Arrays.asList("A","B","C");//假设这些数据来自数据库
}
if(cache.isEmpty()){
synchronized (this) {
if (cache.isEmpty()) {
//模拟从数据库获取数据
log.info("select data from database");
List<String> data = Arrays.asList("A", "B", "C");
//将数据放入cache中
cache.addAll(data);
}
}
}
log.info("select data from cache");
return cache;
}
package com.jt.provider.interceptor;
public class TimeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("==preHandle==");
//1.获取当前时间
LocalTime now = LocalTime.now();//LocalTime为jdk8中的一个获取当前时间的api
//2.获取当前的小时并进行逻辑判断
int hour = now.getHour();//8:10~8
System.out.println("hour="+hour);
if(hour<9||hour>18){
throw new RuntimeException("请在9~18时间范围内访问");//return false
}
return true;//false请求到此结束,true表示放行,会去执行后续的拦截器或controller对象
}
}
第三步:配置拦截器,例如:
package com.jt;
@Configuration
public class SpringWebConfig implements WebMvcConfigurer {
/**
* 注册拦截器(添加到spring容器),并指定拦截规则
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TimeInterceptor())
.addPathPatterns("/provider/sentinel01");
}
}
第四步:打开浏览器,对/provider/sentinel01路径进行访问,对访问结果进行访问。
web:
request: # 注意假如属性名是两个单词,要用"-"进行连接,例如black-urls
black-urls: # 系统底层解析这部分时,会自动以"-"作为分隔符,将内容存储到list集合
- /nacos/provider/echo/a
- /nacos/provider/echo/b
第二步:在项目中添加一个全局过滤器,例如:
package com.jt.filter;
import org.apache.http.HttpHeaders;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
/**
* 基于此全局过滤器对请求url进行黑白名单识别
* @ConfigurationProperties 注解描述类时,用于告诉系统底层
* 要从配置文件中读取指定配置信息(prefix属性用于指定读取哪部分
* 前缀对应的信息)
*/
@ConfigurationProperties(prefix = "web.request")
@Component
public class BlackUrlGlobalFilter implements GlobalFilter, Ordered {//Authentication(认证)
private List<String> blackUrls=new ArrayList<>();
/**
* 当系统底层读取@ConfigurationProperties(prefix = "web.request")
* 注解中描述的内容时,会自动基于名字调用此set方法
*/
public void setBlackUrls(List<String> blacks) {
this.blackUrls = blacks;
}
/**
* 此方法为一个处理请求的方法
* @param exchange 基于此对象获取请求和响应
* @param chain 过滤链对象
* @return SpringWebFlux中的Mono对象(一个Publisher对象),
* 是springframework5.0后推出的新特性,
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange,
GatewayFilterChain chain) {
//1.获取请求和响应对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//2.获取请求url
String urlPath=request.getURI().getPath();//nacos/provider/echo/gateway
System.out.println("blackPath="+blackUrls);
System.out.println("urlPath="+urlPath);
//3.对请求url进行黑白名单分析
//黑名单则请求到此结束
if(blackUrls.contains(urlPath)){
//设置响应状态码
response.setStatusCode(HttpStatus.UNAUTHORIZED);//401
//设置请求头中响应数据内容类型
response.getHeaders()
.add(HttpHeaders.CONTENT_TYPE,"text/html;charset=utf-8");
//构建一个数据buffer对象
DataBuffer dataBuffer=
response.bufferFactory()
.wrap("请求url是黑名单".getBytes());
//将数据封装到Mono对象
return response.writeWith(Mono.just(dataBuffer));
}
//白名单则放行(执行下一步,假如有下个过滤器,就执行下一个过滤器)
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1;
}
}
package com.jt.callback;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.fastjson.JSON;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.Map;
@Component
public class GatewayRequestBlockHandler implements BlockRequestHandler {
@Override
public Mono<ServerResponse> handleRequest(
ServerWebExchange serverWebExchange,
Throwable throwable) {
Map<String,Object> map=new HashMap<>();
map.put("state",429);
map.put("message","two many request");
String jsonStr= JSON.toJSONString(map);
// return ServerResponse.ok()
// .body(Mono.just(jsonStr), String.class);
return ServerResponse.status(HttpStatus.TOO_MANY_REQUESTS)
.contentType(MediaType.TEXT_PLAIN)
.body(Mono.just(jsonStr), String.class);
}
}
第一步:业务描述(通过sca-ui工程向网关工程发送ajax请求,并进行响应处理)
第二步:创建sca-ui工程的html页面,然后通过触发按钮发送ajax请求,例如
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div>
<h2>The Index Pageh2>
<button onclick="doBuy()">Buybutton>
<span id="result">span>
div>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script>
//前端如何排错(日志,debugger,排除)
function doBuy(){
console.log("==doBuy==");
//1.基于axios框架发送异步ajax请求
let url="http://localhost:9000/nacos/provider/echo/1"
let span=document.getElementById("result");
axios.get(url)
.then(function (response) {//请求ok,执行then
console.log(response.data);
//2.将响应结果更新到页面上
span.innerHTML = response.data
})
.catch(function (error) {
debugger //设置断点
//console.log(error);
if(error.response.status==429){
span.innerHTML = error.response.statusText;
}
});
}
script>
body>
html>
第三步:在sca-gateway的配置文件或配置中心中添加跨域配置,例如:
spring:
cloud:
gateway:
globalcors: #跨域配置
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
第五步:按项目架构设计启动服务,进行测试。
http://localhost:8080/index.html
第一步:在sca-gateway项目中添加配置依赖,例如:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
dependency>
第二步:修改application.yml配置文件名称为bootstrap.yml,并添加配置中心配置。
spring:
cloud:
nacos:
config:
server-addr: localhost:8848
file-extension: yml
第三步:在nacos的public命名空间中创建sca-gateway.yml配置,内容如下:
说明,此配置添加后,可以将bootstrap.yml中网关部分的配置注释掉。
第四步:启动nacos,sentinel,provider,gateway服务,然后进行访问测试。
为什么要做单点登录设计?(业务简化,代码复用,不需要每个服务都登录一次)
你知道哪些SSO系统解决方案?(基于用户登录状态信息的存储进行方案设计)
单点登录系统中你的服务是如何设计的,工程结构是怎样的?
项目中使用的连接池什么?(HikariCP)
Java中连接池设计需要遵循的数据源规范是谁?(javax.sql.DataSource)
连接池这块你能想到的设计模式有哪些?(单例,享元,桥接,slf4j门面)
SpringBoot工程中如何基于Junit5进行单元测试?
基于idea的为类自动生成序列化id?
第一步:修改idea中的配置。
第二步:在User类上按alt+enter,例如:
@Autowired注解描述的Mapper对象有红色波浪线,但运行没有错误,如何去除红色波浪线。
没有PasswordEncoder对象,例如:
远程调用服务404异常,例如:
远程调用服务没启动或服务名不正确,例如
服务名的定义和使用不规范,例如:
Feign接口依赖注入异常,例如:
客户端传参不匹配,例如:
AuthenticationManager对象没有配置(SecurityConfig),例如:
响应的令牌不正确,例如:
400异常,请求参数不合法(参数个数,类型,格式)。
401异常,认证失败?(提交的数据不正确)
403异常,没有资源访问权限?(说明用户为已认证用户,但是没有资源的访问权限)
415异常,数据协议有问题?(比方说,你要json数据,但是数据格式定义的是text)
调用的服务没有启动,例如:
503异常,例如