实体@valid 验证
实体对象
BO:视图层传输过来的对象
属性上面添加 注解验证
@NotBlank(message = "id不能为空") private String id; @Length(Max = 12, message = "名称不能超过12位") private String name; @Email //邮箱校验 private String email; @Min(value = 0 ,message = "") @Max(value = 1 ,message= "") private integer sex; @JsonForamt(timezone = "GTM+8" , pattern = "yyyy-MM-dd") //日期格式化 传入的字符串类型转换成 date private Date birthday;
方法上面 返回BindingResult 存有验证结果
public Map<String, String> getErrors(BindingResult result){
Map<String, String> map = new HashMap<>();
List<FieldError> errorList = result.getFieldErrors();
for (FieldError error :errorList){
//发生验证错误时对应的某个属性
String field = error.getField();
//验证消息
String msg = error.getDefaultMessage();
map.put(field,msg);
}
return map;
}
定义拦截器
1 创建一个类,实现 HandlerInterceptor 接口
import org.springframework.web.servlet.HandlerInterceptor;
public class verifyInterceptors implements HandlerInterceptor {}
2.重写方法
-
preHandle() 在请求访问到Controller 之前 执行
-
返回值 true 代表请求通过, false 请求被拦截
-
-
postHandle() 在请求访问到Controller 之 渲染视图之前 执行
-
afterCompletion() 在请求访问到Controller 之前,渲染视图之后 执行
3. 实现 WebMvcConfigurer 接口 写配置类
实现 addInterceptors() 完成注册
构建,拦截器的bean
配置拦截bean和路径
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Bean//构建拦截器Bean
public verifyInterceptors verifyInterceptors() {return new verifyInterceptors();}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(verifyInterceptors())//添加拦截器
.addPathPatterns("/user/verify");//添加拦截路径
}
}
.. @Bean //注入多个 @Bean .... registry.addInterceptor(a())//添加拦截器 ... registry.addInterceptor(b())//添加拦截器
自定义异常 异常拦截
1. 继承RunTimeException 接口
@Data
public class LfException extends RuntimeException{
private REnum rEnum; //实现自己的枚举
public LfException(REnum rEnum){
super("异常状态码为:" + rEnum.status() +
";具体异常信息为:" + rEnum.msg() );
this.rEnum = rEnum;
}
}
2.统一的封装
public class MyException {
//REnum 是自己实现的枚举 包装了异常信息
public static void display(REnum rEnum){
throw new LfException(rEnum);
}
}
3.统一异常拦截处理
统一异常拦截处理 针对异常的类型进行捕获,然后返回 json 信息到前端
import com.lf.result.R;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 统一异常拦截处理 针对异常的类型进行捕获,然后返回json信息到前端
*/
@ControllerAdvice //交给spring管理
public class MyExceptionHandler {
@ExceptionHandler(LfException.class) // 只要是自定的异常都会进入这个方法
@ResponseBody //返回类型
public R returnMyException(LfException e){ //拦截到后 会获取异常信息
e.printStackTrace(); //打印异常信息
return R.exception(e.getREnum());
}
}
设置cookie 与会话信息
使用UUID来添加 token
String userToken = UUID.randomUUID().toString().trim();
向前端保存 cookie
使用URLEncoder.encode(); //设置字符集
Cookie.setDomain() 设置域名信息
public void setCookie(HttpServletRequest request,
HttpServletResponse response,
String keyName,
String value,
Integer maxAge){
try {
value = URLEncoder.encode(value, "utf-8");
Cookie cookie = new Cookie(keyName, value);
cookie.setMaxAge(maxAge);//过期时间
cookie.setDomain("*");
cookie.setPath("/");
response.addCookie(cookie);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
API
Mapper
updateByPrimarykeySelective() 和updateByPrimaryKey()区别
| id | name | day |
|---|---|---|
| 1 | lf | |
//更新操作时 数据 只有 day 属性 则不会修改 id 和name terminalMapper.updateByPrimaryKeySelective(); //更新时候 数据 只有 day 会把 id 和name 也更新为空 terminalMapper.updateByPrimaryKey();
restTemplate 发起远程调用
String URL = "httpl..." +jsonUtils.objectToJson(AA);// aa对象转换json ResponseEntity<bb> BB= restTemplate.getForEntity(URL,bb.class);//bb 是返回对象 bb .. = BB.getBody();//获取结果集
VO类 BO类
返回给前端的对象,单不需要全部的数据, 只把需要的数据封装成VO类型
BeanUtils.copyProperties(user,userVO);//只会从 user 复制 userVO 拥有的属性
视图层传输过来的对象对应BO类
流
base64 转换成 Stream
//获取传入的 base64 字符串 String file64 =...; //base64字符串 转换为byte 数组 byte[] bytes = new BASE64Decoder().decodeBuffer(file64.trim());//trim() 是string 截取 前后空格 //转换为输入流 ByteArrayInputStream inpuStream = new ByteArrayInputStream(bytes);
文件流使用
File file = new File("/xxx/xx");
if( !file.exists() ){//当文件路径不存在时调用创建路径方法
file.mkdirs();
}
文件传输
import org.springframework.web.multipart.MultipartFile;
例如
@Override
public R uploadFace(String userId, MultipartFile file) throws Exception{
if( file != null){
//获取上传的文件名
String filename = file.getOriginalFilename();
//判断文件名非空
if(StringUtils.isNotBlank(filename)){
String[] split = filename.split("\.");//字符串 串 从\、进行截取
//获得后缀 如 png.jpg.jpeg
String suffix = split[split.length-1];
}else {
return R.ok("文件名为空");
}
}else {
return R.ok("文件不能为空");
}
..上传操作
return R.ok();
}
OSS
创建Bucket 列表
使用 Access Key
java SDK —— 简单上传 —— 网络流... 用的比较多
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
String endpoint = "yourEndpoint";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "yourAccessKeyId";
String accessKeySecret = "yourAccessKeySecret";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 填写网络流地址。
InputStream inputStream = new URL("https://www.aliyun.com/").openStream();
// 依次填写Bucket名称(例如examplebucket)和Object完整路径(例如exampledir/exampleobject.txt)。Object完整路径中不能包含Bucket名称。
ossClient.putObject("examplebucket", "exampledir/exampleobject.txt", inputStream);
// 关闭OSSClient。
ossClient.shutdown();
// return 返回exampledir 吧完整的 路径地址 返回个 controller
-
endpoint : Bucket —— 概览 ——访问域名—— 外网访问
-
accessKeyId : 阿里key
-
accessKeySecret: 阿里secret
-
inputStream : 可以 MultipartFile.getInputStream() ;
-
// 填写网络流地址。 InputStream inputStream = file.getInputStream() ;
-
-
examplebucket: Bucke名字
-
exampledir : 资源路径
# 阿里云相关配置 file.endpoint=*** file.examplebucket=*** file.exampledir=image/face
//属性对应的实体类
@Component
@PropertySource("classpath:file-dev.properties")
@ConfigurationProperties(prefix = "file")
@Data
public class FileResource {
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String examplebucket;
private String exampledir;
}
Maven
排除标签 排除依赖传递中的 不需要的依赖
<dependency>
<exclusions>
<exclusion>
<groupId>
....
</groupId>
</exclusion>
</exclusions>
</dependency>
RabbitMQ
异步任务,
SpringCloud
注册中心 Eureka
-
导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
-
配置 application.yml
server: port: 7000 eureka: instance: # eureka 实例的hostname,可以是hostname,也可以自定义配置hostname hostname: eureka client: # 是否要把当前的eureka server注册到自己 register-with-eureka: false # 从注册中心获得检索服务实例,server没有必要,直接false即可 fetch-registry: false # 单实例配置自己的服务地址,高可用集群则配置多个地址 service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ server: enable-self-preservation: false # 关闭eureka的自我保护功能 eviction-interval-timer-in-ms: 5000 # 清理无效节点的时间,可以缩短为5s,默认60s -
启动类开启 EuurekaServer
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, MongoAutoConfiguration.class}) @EnableEurekaServer // 开启注册中心 public class Application { ..... }
生产者
-
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> -
配置yml文件
eureka: # 自定义eureka server的信息 server: hostname: eureka port: 7000 client: # 所有的微服务都必须注册到eureka中 register-with-eureka: true # 从注册中心获得检索服务实例 fetch-registry: true # 注册中心的服务地址 service-url: # defaultZone: http://${eureka.server.hostname}:${eureka.server.port}/eureka/ defaultZone: http://eureka-cluster-7001:7001/eureka/,http://eureka-cluster-7002:7002/eureka/,http://eureka-cluster-7003:7003/eureka/ instance: lease-renewal-interval-in-seconds: 3 # 调整微服务(eureka client)和注册中心(eureka server)的心跳时间 lease-expiration-duration-in-seconds: 5 # eureka 举例最近的一次心跳等待提出的时间,默认90s -
启动类开启 Eureka
..... @EnableEurekaClient // 开启eureka client,注册到server中 public class Application {...}
服务端调用 老方法
@Autowired
private DiscoveryClient discoveryClient; //注入服务,获得已经注册的相关服务信息
//发起调用
List<User> ...(Set id){
String serviceId = "Service-User";// 注册的服务名字Service-User
Lsit<ServiceInstance> list = discoveryClient.getInstances(serviceId);
ServiceInstance userService = list.get(0); //获取 服务的相关信息
//动态地址pinjie
String Url = "http;//" + userService.getHost() + ":" + userService.getPort() + "/.../...";
}
调用方式二
@LoadBalanced
-
默认轮询 算法
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
Eureka 自我保护
eureka: server: eureka-self-preservation: fasle/true #是否开启自我保护
补充
eureka:
server:
eviction-interval-timer-in-ms: 5000 #清理无效节点的时间 默认是60s
instance:
instance:
lease-renewal-interval-in-seconds: 3 # 调整微服务(eureka client)和注册中心(eureka server)的心跳时间
lease-expiration-duration-in-seconds: 5 # eureka 举例最近的一次心跳等待提出的时间,默认90s
Ribbon
服务间通信负载均衡工具,提供完善的超时重试机制
重试机制
导入依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
配置文件
ribbon:
ConnectTimeout: 5000 #5秒 创建连接的超时时间
ReadTimeout: 5000 # 请求超时时间 连接创建好之后,发起请求
MaxAutoRetries: 2 # 重试次数
MaxAutoRetriesNextServer: 2 #集群中有多个实例时, 设置重试的实例台数
A节点重试2 次失败后, 重试B节点的服务,失败后 结束重试
feign 组件 http 简化代码 不推荐使用
导入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
消费者,开启注解
启动类上添加@EnableFeignClients({"com.lf,,"}) //{"扫描的路径,扫描调用的接口ControllerApi"}
接口 类上添加 @FeignClient( value = "别名 微服务的名字")
@Autowried
UserApi userApi; //被調用的接口
....
userApi.queryByIds("传入需要拼接的地址");//自动获取映射地址 http://+微服务+端口 +传入的地址
服务降级 客户端、
@FeignClient(value = "name", fallbackFactory = 自己编写的类) public class ....
创建降级类 继承FallbackFactory<>
@Component
public class aa implements FallbackFactory<需要降级的Controller>{
@Override
public aa create(Throwable throwable){
return new 需要降级的Controller(){
...;//重写方法
@Override
queryByIds(String userIds){
//局部降级
}
...;
};
}
}
feign日志
logging: level: com....userControllerApi: debug #前期是全限定名 :日志打印级别 #配置日志 feign: client: config: #配置服务提供方的名称 service-user: loggerLevel: FULL #日志等级
等级
-
NONE
-
BASIC
-
HEADERS
-
FULL 全部
Hystrix 服务链路问题,防止雪崩
api模块中 调用方
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
使用注解 @HystrixCommand 在方法上
@HystrixCommand(fallbackMethod = "bb")
public void aa(){}
-
fallbackMethod = "" : 这是一个降级方法 触发降级后执行方法 bb
全局降级方法 @DefaultProperties(defaultFallback = "")
所有方法 触发降级 都执行方法 aa
@DefaultProperties(defaultFallback= "aa") @RestController public class ....
启动类上 添加 @EnableCircuitBreaker 熔断开启注解 hystrix 的
断路器

# 配置hystrix
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 2000 # 设置hystrix超时时间,超过2秒触发降级
circuitBreaker: # 配置断路器
enabled: true
requestVolumeThreshold: 10 # 触发熔断最小请求次数,默认:20
sleepWindowInMilliseconds: 15000 # 熔断后过几秒后尝试半开状态(请求重试),默认:5s
errorThresholdPercentage: 50 # 触发熔断的失败率(异常率/阈值),默认:50
zuul 网关
维护服务地址,用户请求访问微服务网关
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
启动类添加注解
@EnableZuulServer @EnableZuulProxy 二选一
@EnableEurekaClient
//@EnableZuulServer //服务
@EnableZuulProxy // @EnableZuulProxy是@EnableZuulServer的一个增强升级版,当zuul和eureka、ribbon等组件共同使用,则使用增强版即可
public class Application {}
-
配置路由规则
# 路由规则: http://[网关地址]:[端口号]/[prefix]/[微服务实例id(path)]/[请求地址路径]
zuul:
routes:
# 由于路由id和微服务实例id相同,我们可以简化转发的配置
service-article: /service-article/**
# service-article: # 配置微服务的路由id,微服务的实例id
# path: /service-article/** # 请求路径(前缀)
# service-id: service-article # 请求转发的微服务实例id
# url: http://192.168.1.2:8001 # 请求转发到指定的微服务所在的ip地址
prefix: /api # 请求前缀
-
自定义 zuul 过滤器 / 和拦截器一样
继承 ZuulFilter
import com.netflix.zuul.ZuulFilter;
@Component
public class MyFilter extends ZuulFilter {
/**
* 定义过滤器的类型
* pre: 在请求被路由之前执行
* route: 在路由请求的时候执行
* post: 请求路由以后执行
* error: 处理请求时发生错误的时候执行
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 过滤器执行的顺序,配置多个有顺序的过滤
* 执行顺序从小到大
* @return
*/
@Override
public int filterOrder() {
return 1;
}
/**
* 是否开启过滤器
* true:开启
* false:禁用
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器的业务实现
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("display pre zuul filter...");
return null; // 没有意义可以不用管。
}
}
扩展 限制ip 访问
自定义属性
# ip请求限制的参数配置
blackIp:
continueCounts: ${counts:10} # ip连续请求的次数
timeInterval: ${interval:10} # ip判断的事件间隔,单位:秒
limitTimes: ${times:15} # 限制的事件,单位:秒
拦截器
@Component
@RefreshScope //动态刷新 actuator 提供
public class BlackIPFilter extends ZuulFilter {
@Value("${blackIp.continueCounts}")
public Integer continueCounts;
@Value("${blackIp.timeInterval}")
public Integer timeInterval;
@Value("${blackIp.limitTimes}")
public Integer limitTimes;
@Autowired
private RedisOperator redis; //自定义的redis
@Override
public String filterType() {return "pre";}
@Override
public int filterOrder() {return 2;}
@Override
public boolean shouldFilter() {return true; }
@Override
public Object run() throws ZuulException {
System.out.println("执行【ip黑名单】过滤器...");
System.out.println("continueCounts: " + continueCounts);
System.out.println("timeInterval: " + timeInterval);
System.out.println("limitTimes: " + limitTimes);
// 获得上下文对象
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
// 获得ip
String ip = IPUtil.getRequestIp(request); //IPUtil 自定义工具
/**
* 需求:
* 判断ip在10秒内的请求次数是否超过10次
* 如果超过,则限制这个ip访问15秒,15秒以后再放行
*/
final String ipRedisKey = "zuul-ip:" + ip;
final String ipRedisLimitKey = "zuul-ip-limit:" + ip;
// 获得当前ip这个key的剩余时间
long limitLeftTime = redis.ttl(ipRedisLimitKey);
// 如果当前限制ip的key还存在剩余时间,说明这个ip不能访问,继续等待
if (limitLeftTime > 0) {
stopRequest(context);
return null;
}
// 在redis中累加ip的请求访问次数
long requestCounts = redis.increment(ipRedisKey, 1);
// 从0开始计算请求次数,初期访问为1,则设置过期时间,也就是连续请求的间隔时间
if (requestCounts == 1) {
redis.expire(ipRedisKey, timeInterval);
}
// 如果还能取得请求次数,说明用户连续请求的次数落在10秒内
// 一旦请求次数超过了连续访问的次数,则需要限制这个ip的访问
if (requestCounts > continueCounts) {
// 限制ip的访问时间
redis.set(ipRedisLimitKey, ipRedisLimitKey, limitTimes);
stopRequest(context);
}
return null;
}
private void stopRequest(RequestContext context) {
// 停止zuul继续向下路由,禁止请求通信
context.setSendZuulResponse(false);
context.setResponseStatusCode(200);
String result = JsonUtils.objectToJson(
GraceJSONResult.errorCustom(
ResponseStatusEnum.SYSTEM_ERROR_ZUUL));
context.setResponseBody(result);
context.getResponse().setCharacterEncoding("utf-8");
context.getResponse().setContentType(MediaType.APPLICATION_JSON_VALUE);
}
}
分布式配置中心 SpringCloudConfig
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
spring:
cloud:
config:
server:
git:
uri: https://github.com/leechenxiang/imooc-news-config.git #配置地址
actuator 动态刷新配置,健康检测
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
拦截器中添加
@RefreshScope 动态刷新
配置文件
# 配置动态刷新git配置的路径终端请求地址
management:
endpoints:
web:
exposure:
include: refresh
通过发起一个post的请求来刷新配置文件
http://.../服务端/refresh
消息总线 SpringCloud Bus
配置在服务端的自动刷新 ,方便管理Config
引入依赖 配置服务端
客户端 也需要导入 依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
消息驱动 SpringCloud Stream
统一封装消息的服务框架
service
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rabbit</artifactId> </dependency>
配置 MQ
rabbitmq: host: 192.168.1.204 port: 5672 username: admin password: admin virtual-host: imooc-news-dev cloud: stream: bindings: # 绑定通道和交换机 myOutput: # 定义生产者的通道 # 自定义交换机的名字,也就是代码里构建的消息,交给底层mq的交换机 destination: streamExchange myInput: # 定义消费者的通道 # 自定义交换机的名字,也就是消息从底层mq输入到消费端进行消费 destination: streamExchange group: boys # 消息分组,避免重复消费
创建接口
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;
/**
* 声明构建通道channel
*/
@Component
public interface MyStreamChannel {
String OUTPUT = "myOutput";
String INPUT = "myInput";
@Output(MyStreamChannel.OUTPUT)
MessageChannel output();
@Input(MyStreamChannel.INPUT)
SubscribableChannel input();
}
-
监听队列
@Component
@EnableBinding(MyStreamChannel.class)
public class MyStreamConsumer {
/**
* 监听并且实现消息的消费和相关业务处理
*/
// @StreamListener(MyStreamChannel.INPUT)
// public void receiveMsg(AppUser user) {
// System.out.println(user.toString());
// }
@StreamListener(MyStreamChannel.INPUT)
public void receiveMsg(String dumpling) {
System.out.println(dumpling);
}
}
-
开启绑定器
**
* 开启绑定器
* 绑定通道channel
*/
@Component
@EnableBinding(MyStreamChannel.class)
public class StreamServiceImpl implements StreamService {
@Autowired
private MyStreamChannel myStreamChannel;
@Override
public void sendMsg() {
AppUser user = new AppUser();
user.setId("10101");
user.setNickname("imooc");
// 消息通过绑定器发送给mq
myStreamChannel.output()
.send(MessageBuilder.withPayload(user).build());
}
@Override
public void eat(String dumpling) {
myStreamChannel.output()
.send(MessageBuilder.withPayload(dumpling).build());
}
}
链路追踪 Sleuth 不推荐 使用
所有的请求都会经过网关 到达微服务
网关模块中 service中 也需要添加2个依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zipkin</artifactId> </dependency>
-
服务端配置文件
spring:
zipkin:
# 配置zipkin采集的服务地址,数据会发送到这里
base-url: http://192.168.1.2:9411/
sender:
# 数据采集的传输通信方式,web http的形式
type: web
sleuth:
sampler:
# 数据采样比例(百分数),0~1
probability: 1
SpringCloud Alibaba
-
注册中间 Eueka 不在更新
-
更换为 Zookeeper Nacos
-
-
服务调用 Ribbon 不推荐 主要使用
-
LoadBalancer 负载均衡器
-
-
服务调用 Feign 不推荐
-
使用 OpenFeign
-
-
断路器 Hystrix 官方不在推荐
-
使用 sentienl 哨兵
-
-
网关 Zuul 不推荐
-
gateway
-
-
服务配置Config 不推荐
-
Nacos
-
-
服务总线 Bus
-
Nacos
-
Zookeeper 注册中心
推荐使用Nacos
-
分布式协调中间件
-
可用于注册/发现服务
-
可以实现分布式锁
-
节点与节点的监听/触发
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> </dependency>
配置yml
spring: cloud: zookeeper: connect-string: 192.168.1.157:2181
启动类类添加注解
@EnableDiscoveryClient //用于注册服务到 zookeeper 或consul ....
GateWay 微服务网关
-
Routes 路由
-
Fiters 过滤器
-
Predicates 断言
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
spring: application: name: springcloud-my-gateway cloud: gateway: discovery: locator: enabled: true # 开启动态路由,从注册中心根据微服务名称获得目标节点 routes: - id: teacherRoute # 路由id,可以自定义,保证全局唯一 uri: lb://service-teacher # lb 代表负载均衡,会动态寻址 # uri: http://192.168.1.5:8002 # 后端微服务节点的路由uri地址 predicates: # 匹配断言,符合条件的则放行(可以精确到具体的接口名) - Path=/teacher/** # uri+/teacher/**
断言 predicates
官方文档
Spring Cloud Gateway
predicates: #是可以有多中断言的 - Path=/teacher/** - RemoteAddr=192.168.1.1/24 #目标地址访问,不是这个ip不能访问 - After=2017-01-20T17:42:47.789-07:00[America/Denver] #时间节点之后 - Before=2017-01-20T17:42:47.789-07:00[America/Denver] #时间节点之前 - Method=GET,POST #请求方式 - Query=green #请求参数 ?key=value
自定义过滤器 global Filters
全局过滤器,所有接口路由
-
继承接口
public class MyFilter implements GlobalFilter, Ordered {}重写方法
/ 过滤器的顺序,数字越小优先级越大 @Override public int getOrder() { return 0; }@Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){//执行逻辑 // 判断header中是否有token,对用户请求进行判断过滤 HttpHeaders headers = exchange.getRequest().getHeaders(); ....; if(){ // 禁止通行,禁止向下继续路由 return exchange.getResponse().setComplete(); } // 放行 return chain.filter(exchange);}
Nacos
-
服务注册与发现
-
分布式配置管理
顶级pom
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.6.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency>
子工程
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
配置文件
spring: cloud: nacos: discovery: server-addr: 192.168.1.159:8848 # nacos 所在地址 # 打开监控 management: endpoints: web: exposure: include: '*'
-
动态配置管理
<!-- 引入nacos作为配置中心 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
配置文件 bootstrap.yml
spring: cloud: nacos: config: server-addr: 192.168.1.159:8848 # nacos 配置中心所在地址 file-extension: yaml # 指定动态配置的文件类型(扩展名) 默认是properties文件
-
controller 中添加@RefreshScope // 动态刷新nacos 配置文件
@RestController @RequestMapping("teacher") @RefreshScope // 动态刷新的注解 public class HelloController {}
Sentinel 流量控制
分布式事务 Seata
seata.io 官中
插件
Swagger2
1.引入依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
</dependency>
2.创建配置类
路径是 实现了对应接口的 实现类路径
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class Swagger2 {
// http://localhost:8088/swagger-ui.html 原路径
// http://localhost:8088/doc.html 新路径
// 配置swagger2核心配置 docket
@Bean
public Docket createRestApi() {
//开启扫描 "实现类的 路径"
Predicate<RequestHandler> apiPredicate = RequestHandlerSelectors.basePackage("com.lf.user.controller");
return new Docket(DocumentationType.SWAGGER_2) // 指定api类型为swagger2
.apiInfo(apiInfo()) // 用于定义api文档汇总信息
.select()
.apis(Predicates.or(apiPredicate))//扫描包 ,2,3
.paths(PathSelectors.any()) // 所有controller
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("lf自学编写-api接口") // 文档页标题
.contact(new Contact("lf",
"",
"807397634@qq.com")) // 联系人信息
.description("引以为傲的生活") // 详细信息
.version("1.0.0") // 文档版本号
.termsOfServiceUrl("") // 网站地址
.build();
}
}
3.接口添加注解
@Api(value = "controller标题" , tags = {"测试运行"})
public interface HelloControllerApi {
@ApiOperation(value= "hello方法的接口",notes = "hello方法的接口",httpMethod = "GET")
public R hello();
}

pagehelper 分页插件
是通过拦截器 拦截select查询语句加入 分页sql
example.orderBy("id").desc(); //可以更具id 进行排序
PageHelper.startPage(page,pageSize);//在执行查询语句之前
..... = userMapper.selectByExample(excample);
PageHelper.startPage(page,pageSize);//在执行查询语句之前
软件
MongoDB
noSql 数据库,内存级别查询,不支持事务,json数据存储,GridFS 小文件存储
导入依赖
<!-- 引入 mongodb 依赖 -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver</artifactId>
</dependency>
配置mongdb配置信息
spring:
data:
mongodb:
uri: mongodb://root:root@192.168.1.202:27017
database: imooc-news
配置GridFSConfig 放入spring容器 //实现文件上传 GridFs
@Component
public class GridFSWebConfig {
@Value("${spring.data.mongodb.database}")
private String mongodb;
@Bean
public GridFSBucket getGridFSBucket(MongoClient mongoClient){
MongoDatabase database = mongoClient.getDatabase(mongodb);
GridFSBucket bucket = GridFSBuckets.create(database);
return bucket;
}
}
实体类映射 字段
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
实体类 @Field
@Document("别名")//别名 是存入mongoDB中的 名字
public class userMO{
@Field(user_name)
private String userName;
MongoDB持久层操作
FriendLinkMO 实体类 String id值
public interface FriendLinkRepository extends MongoRepository<FriendLinkMO, String> {
}
调用
@Service .... @Autowired private FriendLinkRepository friendLinkRepository ;//注入这个接口 ....; friendLinkRepository.方法调用
主要使用
-
GridFS 存储小文件,例如,图片
-
历史数据的快照: 例如 购物 付款的商品信息(后续不会同步更新改动)
-
用户浏览记录
-
客服聊天记录
ECHARTS 图表 前端
elasticsearch搜索 分布式搜索引擎
Es核心术语
| 索引 index | 表 |
|---|---|
| 类型 type (弃用) | 表逻辑类型 |
| 文档 document | 行 |
| 字段fields | 列 |
| 映射 mapping | 表结构定义 |
| 近实时 NRT | Near real time 接近真实时间 |
| 节点 node | 每一个服务器 |
| shard replica | 数据分片 |
倒排索引

-
导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> -
下载 elastic
业务
双写一致
更新 数据库,和redis
-
删除redis
-
更新数据库
-
删除redis
admin
admin 不提供注册功能,默认存在一个基本账号
通过代码生成用户名,和密码,直接手动生成即可
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
String pwd = BCrypt.hashpw(newAdminBO.getPassword(), BCrypt.gensalt());
定时任务
创建配置类
@Configuration
@EnableScheduling // 开启定时任务
public class ....
@Scheduled(0/1 0/1 * * * ? ) //执行任务表达式
public void AA(){}
表达式 在线Cron表达式生成器
支持6位,不支持年
-
定时任务 基本是在全表扫描,对于大量的业务表,会造成负担 会使用MQ做优化
Redis get单个读取 mget 批量读取
在循环体中使用时,每次一次循环都会发起请求,增加redis压力
mget 批量请求
List a = new List(); List<> b = redisTemplate.mget(a);
底部
最后
以上就是仁爱发卡最近收集整理的关于微服务体系自媒体实战 学习笔记实体@valid 验证定义拦截器自定义异常 异常拦截设置cookie 与会话信息APIVO类 BO类流文件传输MavenRabbitMQSpringCloudSpringCloud Alibaba插件软件业务底部的全部内容,更多相关微服务体系自媒体实战内容请搜索靠谱客的其他文章。
发表评论 取消回复