springcloud-网关(gateway)

springcloud-网关(gateway)

概述

\Spring Cloud Gateway旨在提供一种简单而有效的方式来路由到API,并为其提供跨领域的关注,如:安全、监控/指标和容错

常用术语

  • Route(路由): 网关的基本构件。它由一个ID、一个目的地URI、一个谓词(Predicate)集合和一个过滤器(Filter)集合定义。如果集合谓词为真,则路由被匹配。
  • Predicate(谓词): 这是一个 Java 8 Function Predicate。输入类型是 [Spring Framework ServerWebExchange]。这让你可以在HTTP请求中的任何内容上进行匹配,比如header或查询参数。
  • Filter(过滤器): 这些是 [GatewayFilter] 的实例,已经用特定工厂构建。在这里,你可以在发送下游请求之前或之后修改请求和响应。

网关工作原理

客户端向 Spring Cloud Gateway 发出请求。如果Gateway处理程序映射确定一个请求与路由相匹配,它将被发送到Gateway Web处理程序。这个处理程序通过一个特定于该请求的过滤器链来运行该请求。过滤器被分割的原因是,过滤器可以在代理请求发送之前和之后运行逻辑。所有的 "pre" (前)过滤器逻辑都被执行。然后发出代理请求。在代理请求发出后,"post" (后)过滤器逻辑被运行。

image-20231213121300712

业务架构图

Spring Cloud:Feign负载均衡及熔断&Gateway网关的路由及过滤器&Gateway跨域&Spring Cloud Config分布式配置中心&Spring Cloud Bus ...

开发流程

引入依赖

gateway框架需要引入loadbalancer,否则在访问的时候会出现503异常。

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

bootstrap.yml配置

配置nacos

如果不需要nacos的配置,可以不引入nacos的config依赖

<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
spring:application:name: ssc-cloud-gatewaycloud:nacos:discovery:server-addr: 192.168.201.81:7777namespace: ssc-cloud-idgroup: DEVregister-enabled: true
配置gateway
spring:cloud:gateway:discovery:locator:enabled: trueroutes:- id : ssc-order-id               #路由编号(自定义)
#          uri: https://www.bilibili.com/   #跳转地址(网页跳转),lb--负载调整(微服务)uri: lb://ssc-cloud-olderpredicates:- Path=/ssc-older/**       #url 的映射名称(让客户看到的)filters:- StripPrefix=1- id: ssc-paycenter-id               #路由编号(自定义)uri: lb://ssc-cloud-paycenterpredicates:- Path=/ssc-pay/**filters:- StripPrefix=1
路由配置规则
序号名称解释
1id⾃定义的路由 ID,保持唯⼀
2uri目标服务地址:以lb:// 开头则表示要去向的微服务名称
3predicates路由条件
4Filter(过滤器)过滤器是路由转发请求时所经过的过滤逻辑,可⽤于修改请求、响应内容。
predicates断言条件
  • Path

    实例: - Path=/ssc-older/

    routes:- id : ssc-older-id          uri: lb://ssc-cloud-olderpredicates:- Path=/ssc-older/**    
    

    解释: 当请求的路径为ssc-older开头的时,转发到ssc-cloud-older微服服务器上,ssc-cloud-older是navcos中微服务注册的名称。

    image-20231213175938386

  • Before

    - Before=2017-01-20T17:42:47.789-07:00[Asia/Shanghai]

    在某个时间之前的请求才会被转发到 http://localhost:9001 服务器上

  • After

    - After=2017-01-20T17:42:47.789- 07:00[Asia/Shanghai]

    在某个时间之后的请求才会被转发

  • Between

    - Between=2017-01-20T17:42:47.789-07:00[Asia/Shanghai],

    2017-01- 21T17:42:47.789-07:00[Asia/Shanghai]

    在某个时间段之间的才会被转发

  • Cookie

    - Cookie=sesionId,ssc-test

    名为ss-old的表单或者满⾜正则old的表单才会被匹配到 进⾏请求转发

    routes:- id : ssc-older-id          uri: lb://ssc-cloud-olderpredicates:- Cookie=sesionId,ssc-test   
    
  • Header

    - Header=X-Request-Id

    携带参数X-Request-Id的请求头才会匹配

  • Host

    - Host=www.ssc.older.com

    当主机名为www.ssc.older.com的时候直接转发到指定服务器。

  • Method

    - Method=GET

    只有GET⽅法才会匹配转发请求,还可以限定POST、PUT等。

    routes:- id : ssc-older-id          uri: lb://ssc-cloud-olderpredicates:- Method=GET,POST  
    
过滤器规则
过滤规则实例说明
PrefixPath- PrefixPath=/app在请求路径前加上app
PrefixPath- PrefixPath=/app在请求路径前加上app
SetPathSetPath=/app/{path}通过模板设置路径,转发的规则时会在路径前增加 app,{path}表示原请求路径
RedirectTo重定向
RemoveRequestHea去掉某个请求头信息\1. PrefixPath
StripPrefixPath=/ssc-pay/**去掉ssc-pay才是真实路径

网关的案例

使用网关进行用户鉴权过滤。

image-20231220095437516

鉴权微服务

image-20231220095804335

api模块

api模块为外界提供接口(openfeign调用),为网关调用需要基于reactor开发。

pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.wnhz.ssc.cloud.authority</groupId><artifactId>ssc-cloud-authority</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>com.wnhz.ssc.cloud.authority.api</groupId><artifactId>ssc-cloud-authority-api</artifactId><dependencies><dependency><groupId>com.playtika.reactivefeign</groupId><artifactId>feign-reactor-webclient</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.playtika.reactivefeign</groupId><artifactId>feign-reactor-cloud</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.playtika.reactivefeign</groupId><artifactId>feign-reactor-spring-configuration</artifactId><version>3.0.3</version></dependency></dependencies>
</project>
openfeign接口
@ReactiveFeignClient(value = "ssc-cloud-authority",url = "http://localhost:12121")
public interface IAuthorityFeign {@GetMapping("/api/authority/login")Mono<HttpResp> login(@RequestParam("username") String username,@RequestParam("password") String password);@PostMapping("/api/authority/verifyToken")Mono<HttpResp> verifyToken(String token);
}

业务接口(sevice)

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.wnhz.ssc.cloud.authority</groupId><artifactId>ssc-cloud-authority</artifactId><version>0.0.1-SNAPSHOT</version></parent><groupId>com.wnhz.ssc.cloud.authority.service</groupId><artifactId>ssc-cloud-authority-service</artifactId><dependencies><dependency><groupId>com.wnhz.ssc.cloud.springcloud</groupId><artifactId>ssc-cloud-springcloud</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi2-spring-boot-starter</artifactId></dependency><dependency><groupId>com.wnhz.ssc.cloud</groupId><artifactId>ssc-cloud-tools</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>com.wnhz.ssc.cloud</groupId><artifactId>ssc-cloud-ssm</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency></dependencies>
</project>
配置

image-20231220100840317

bootstrap.yml

image-20231220100632172

image-20231220100711263

spring:cloud:nacos:config:server-addr: ${spring.cloud.nacos.discovery.server-addr}namespace: ${spring.cloud.nacos.discovery.namespace}file-extension: yamlextension-configs:- data-id: db_ssc.yamlgroup: DEVrefresh: true- data-id: redis.yamlgroup: DEVrefresh: truediscovery:server-addr: 192.168.201.107namespace: ssc-cloud-idgroup: DEVapplication:name: ssc-cloud-authority
application
  • application-dev.yml

    server:port: 12121
    knife4j:enable: true
    logging:level:com.wnhz: debug
    
  • application.yml

    spring:profiles:active: dev
    
启动类
@EnableDiscoveryClient
@SpringBootApplication
public class AuthorityApp {public static void main(String[] args) {SpringApplication.run(AuthorityApp.class);}
}
dao
@Mapper
public interface ILoginDao extends BaseMapper<Login> {
}
异常

image-20231220101139895

/*** 鉴权异常*/
public class AuthorityException extends RuntimeException{public AuthorityException(String message) {super(message);}
}
/*** 用户名或密码错误异常*/
public class BadCredentialsException extends AuthorityException{public BadCredentialsException(String message) {super(message);}
}
service
  • 接口

    public interface ILoginService {Login loginCheck(String username, String password);List<Login> findByUsername(String username);
    }
    
  • 实现类

    package com.wnhz.ssc.cloud.authority.service.impl;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.wnhz.ssc.cloud.authority.dao.ILoginDao;
    import com.wnhz.ssc.cloud.authority.exception.BadCredentialsException;
    import com.wnhz.ssc.cloud.authority.exception.UsernameEmptyException;
    import com.wnhz.ssc.cloud.authority.exception.UsernameNotFoundException;
    import com.wnhz.ssc.cloud.authority.service.ILoginService;
    import com.wnhz.ssc.domain.entity.po.Login;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.util.StringUtils;import java.util.List;
    import java.util.Objects;@Service
    public class LoginServiceImpl implements ILoginService {@Autowiredprivate ILoginDao loginDao;@Overridepublic Login loginCheck(String username, String password) {if (!StringUtils.hasText(username)) throw new UsernameEmptyException("用户名为空异常");LambdaQueryWrapper<Login> lambdaQueryWrapper= new LambdaQueryWrapper<>();lambdaQueryWrapper.eq(Login::getUsername, username);List<Login> logins = findByUsername(username);Login login = logins.stream().filter(lg -> username.equals(lg.getUsername())).findFirst().get();if (Objects.isNull(login)) throw new BadCredentialsException("用户名|密码错误");return login;}/*** 判读用户名是否存在* @param username 用户名* @return 所有查询服务用户名的用户集合*/@Overridepublic List<Login> findByUsername(String username) {List<Login> logins = loginDao.selectList(new LambdaQueryWrapper<Login>().eq(Login::getUsername, username));if (Objects.isNull(logins) || logins.isEmpty()) throw new UsernameNotFoundException("用户名不存在异常");return logins;}
    }
    
controller
package com.wnhz.ssc.cloud.authority.controller;import com.wnhz.ssc.cloud.authority.service.ILoginService;
import com.wnhz.ssc.cloud.tools.exception.jwt.JwtException;
import com.wnhz.ssc.cloud.tools.exception.jwt.JwtExpiredException;
import com.wnhz.ssc.cloud.tools.jwt.JwtUtil;
import com.wnhz.ssc.common.result.HttpResp;
import com.wnhz.ssc.domain.entity.po.Login;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;@Api(tags = "鉴权模块api")
@RestController
@RequestMapping("/api/authority")
@Slf4j
public class AuthorityController {@Autowiredprivate ILoginService loginService;@Autowiredprivate StringRedisTemplate stringRedisTemplate;private final String REDIS_PREFIX="token:";/*** 用户登录** @param username* @param password* @return*/@ApiOperation(value = "login", notes = "用户登录验证")@GetMapping("/login")public HttpResp login(String username, String password) {try {Login login = loginService.loginCheck(username, password);log.debug("用户名登录成功:{}",login);Map<String, Object> map = new HashMap<>();map.put("username", username);String token = JwtUtil.getInstance().creatToken(map, 1000 * 30, login.getSign());stringRedisTemplate.opsForValue().set(REDIS_PREFIX+token, login.getSign(),10, TimeUnit.MINUTES);log.debug("token产生成功,并存入redis中:{}",token);return HttpResp.success(new String[]{"ssc_login_token", token});} catch (Exception e) {return HttpResp.failed(e.getMessage());}}/*** 验证token** @param token* @return*/@ApiOperation(value = "verifyToken", notes = "token验证")@GetMapping("/verifyToken")public Mono<HttpResp> verifyToken(String token) {String sign = stringRedisTemplate.opsForValue().get(REDIS_PREFIX+token);log.debug("从redis中获取token的值: {}", sign);if (Objects.isNull(sign)) {return Mono.just(HttpResp.failed("token不存在"));}try {JwtUtil.getInstance().verifyToken(token, sign);return Mono.just(HttpResp.success("token验证成功"));} catch (JwtExpiredException e) {//token已过期,判断是否续期return refreshToken(token, sign);} catch (JwtException e) {return Mono.just(HttpResp.failed(e.getMessage()));}}private Mono<HttpResp> refreshToken(String originalToken, String sign) {Long expireLeftTime = stringRedisTemplate.getExpire(REDIS_PREFIX+originalToken);log.debug("redis中token剩余时间:{}", expireLeftTime);if (expireLeftTime > 0) {//token续期String newToken = JwtUtil.getInstance().cloneToken(originalToken, expireLeftTime);stringRedisTemplate.delete(REDIS_PREFIX+originalToken);stringRedisTemplate.opsForValue().set(REDIS_PREFIX+newToken, sign);log.debug("新token产生成功,续期完成,token==> {}",newToken);return Mono.just(HttpResp.success(new String[]{"ssc_login_token", newToken}));} //token已经过期,redis也过期return Mono.just(HttpResp.failed("token已经过期"));}
}

全局网关

负责对鉴权控制

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>wnhz-ssc-cloud</artifactId><groupId>com.wnhz.ssc.cloud</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.wnhz.ssc.cloud.gateway</groupId><artifactId>ssc-cloud-gateway</artifactId><dependencies><dependency><groupId>com.wnhz.ssc.cloud.springcloud</groupId><artifactId>ssc-cloud-springcloud</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>com.wnhz.ssc.cloud.common</groupId><artifactId>ssc-cloud-common</artifactId><version>0.0.1-SNAPSHOT</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency><groupId>com.playtika.reactivefeign</groupId><artifactId>feign-reactor-spring-configuration</artifactId><version>3.0.3</version><scope>compile</scope></dependency><dependency><groupId>com.wnhz.ssc.cloud.authority.api</groupId><artifactId>ssc-cloud-authority-api</artifactId><version>0.0.1-SNAPSHOT</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><outputDirectory>../out</outputDirectory></configuration></plugin></plugins></build>
</project>

配置

bootstrap.yml
spring:main:web-application-type: reactiveapplication:name: ssc-cloud-gatewaycloud:nacos:discovery:server-addr: 192.168.201.81:7777namespace: ssc-cloud-idgroup: DEVregister-enabled: trueconfig:enabled: offgateway:discovery:locator:enabled: trueroutes:- id : ssc-order-id               #路由编号(自定义)
#          uri: https://www.bilibili.com/   #跳转地址(网页跳转),lb--负载调整(微服务)uri: lb://ssc-cloud-olderpredicates:- Path=/ssc-older/**       #url 的映射名称(让客户看到的)filters:- StripPrefix=1- id: ssc-paycenter-id               #路由编号(自定义)uri: lb://ssc-cloud-paycenterpredicates:- Path=/ssc-pay/**filters:- StripPrefix=1- id: ssc-authority-id               #路由编号(自定义)uri: lb://ssc-cloud-authoritypredicates:- Path=/ssc-auth/**filters:- StripPrefix=1

全局过滤器

package com.wnhz.ssc.cloud.gateway.filter;import com.fasterxml.jackson.databind.ObjectMapper;
import com.wnhz.ssc.cloud.authority.feign.IAuthorityFeign;
import com.wnhz.ssc.common.result.HttpResp;
import com.wnhz.ssc.common.result.RespCode;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
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.Mono;import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;@Component
@Slf4j
public class SscGlobalGatewayFilter implements GlobalFilter, Ordered {@Lazy@Autowiredprivate IAuthorityFeign authorityFeign;private final String LOGIN_TOKEN="ssc_login_token";@SneakyThrows@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();log.debug("我进入过滤中.....");ObjectMapper objectMapper = new ObjectMapper();DataBuffer dataBuffer = null;String requestURI =request.getURI().getPath() ;log.debug("请求uri:{}",requestURI);if(requestURI.endsWith("/authority/login")){//客户访问登录业务,直接跳转验证return chain.filter(exchange);}//1. Token不存在,客户未登录状态访问系统if(!isLogin(request)) {//如果客户没有登录log.debug("客户还没有登录,重定向到登录(baidu)页面");String redirectUrl = "https://www.baidu.com";log.debug("将客户请求重定向到指定页面: {}", redirectUrl);response.getHeaders().set(HttpHeaders.LOCATION, redirectUrl);//303状态码表示由于请求对应的资源存在着另一个URI,应使用GET方法定向获取请求的资源response.setStatusCode(HttpStatus.SEE_OTHER);response.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");return response.setComplete();}//2. token存在,调用验证微服务验证token是否有效String token = getToken(request);HttpResp block = authorityFeign.verifyToken(token).block();if(block.getCode()== RespCode.FAILED.getCode()){ //token验证失败response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");dataBuffer = response.bufferFactory().wrap(objectMapper.writeValueAsString(block).getBytes(StandardCharsets.UTF_8));return response.writeWith(Mono.just(dataBuffer));}return chain.filter(exchange);}@Overridepublic int getOrder() {return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;}/*** 客户未登录,没有token* @param request* @return*/private boolean isLogin(ServerHttpRequest request){HttpHeaders headers = request.getHeaders();log.debug("header===> {}", headers);List<String> loginToken = headers.get(LOGIN_TOKEN);if(Objects.nonNull(loginToken)){return true;}return false;}/*** 从请求中获取token* @param request*/private String getToken(ServerHttpRequest request){HttpHeaders headers = request.getHeaders();log.debug("header===> {}", headers);List<String> tokens = headers.get(LOGIN_TOKEN);String token = tokens.get(0);return token;}
}

启动类

package com.wnhz.ssc.cloud.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import reactivefeign.spring.config.EnableReactiveFeignClients;@SpringBootApplication
@EnableDiscoveryClient
@EnableReactiveFeignClients(basePackages = "com.wnhz.ssc.cloud.authority.feign")
public class GatewayApp {public static void main(String[] args) {SpringApplication.run(GatewayApp.class);}
}
HttpHeaders headers = request.getHeaders();log.debug("header===> {}", headers);List<String> tokens = headers.get(LOGIN_TOKEN);String token = tokens.get(0);return token;
}

}


### 启动类```java
package com.wnhz.ssc.cloud.gateway;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import reactivefeign.spring.config.EnableReactiveFeignClients;@SpringBootApplication
@EnableDiscoveryClient
@EnableReactiveFeignClients(basePackages = "com.wnhz.ssc.cloud.authority.feign")
public class GatewayApp {public static void main(String[] args) {SpringApplication.run(GatewayApp.class);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/693251.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Lightfm学习记录

推荐参考资料 官方文档仓库地址论文地址LightFM推荐系统框架学习笔记LightFM推荐模型库(利于入门)how-i-would-explain-building-lightfm-hybrid-recommenders-to-a-5-year-old(用处不大)协同推荐 lightfm 根据用户已读诗词推荐(可能有用)Recommendation System in Python: L…

C#开发AGV地图编辑软件

C#自己开发AGV地图编辑软件&#xff1a; 1、自由添加和删除站点、停车位、小车、运行路径。 2、编辑得地图以XML文件保存。 3、导入编辑好地图的XML文件。 4、程序都是源码&#xff0c;可以直接在此基础上进行二次开发。 下载链接&#xff1a;https://download.csdn.net/d…

隐匿的炸弹 — C语言的隐式声明

前言 &#xff08;1&#xff09;如果有嵌入式企业需要招聘湖南区域日常实习生&#xff0c;任何区域的暑假Linux驱动实习岗位&#xff0c;可C站直接私聊&#xff0c;或者邮件&#xff1a;zhangyixu02gmail.com&#xff0c;此消息至2025年1月1日前均有效 &#xff08;2&#xff0…

【Python】OpenCV-图像轮廓检测初学

图像轮廓检测初学 在图像处理领域中&#xff0c;轮廓检测是一项重要的任务&#xff0c;用于寻找并标定图像中的物体边缘。本文将介绍如何使用OpenCV库进行图像轮廓检测&#xff0c;并展示一个简单的示例代码。代码中的注释将详细解释每一步的操作。 1. 引言 图像轮廓检测是图…

基于PSO优化的CNN多输入时序回归预测(Matlab)粒子群算法优化卷积神经网络时序回归预测

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分代码&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&…

PHP分析二维数据表(长度|数字字段|空值|纯姓名|英文用户名|科学计数|是否等长|是否唯一)

先看图&#xff0c;后有完整代码 <?php $t "Excel数据转Sql查询系统字段半智能分析"; $s "Excel复制过来的二维结构表内容,分析查询条件&#xff01;"; $x "字段|最大长度|长度有|数字字段|空值存在|纯姓名|英文用户名|科学计数|是否等长|是否…

无痛法门,助力学习

**注&#xff1a;**本文摘自一位网友“我就是贺生啊”&#xff0c;博主觉得很有道理&#xff0c;便想记录下来分享给大家。仅个人想法&#xff0c;谨慎参考&#xff0c;也欢迎大家说出自己的想法。 引言 在我们学习新知识的时候&#xff0c;会觉得很痛苦&#xff0c;制定学习…

【git】提交信息写错了,使用 amend 或者 reset 修改最近一次的提交信息 ,修改上上次/以前的提交信息

如果你的提交信息写错了&#xff0c;比如下面&#xff0c;你想修改【初始化项目】这5个字 修改最近一次的提交新的两个办法 &#xff08;1&#xff09;使用 reset 把这个提交重置&#xff0c;然后重新提交&#xff0c;reset 的使用方法请参考这篇文章。但是 reset 这种方法只能…

Django学习笔记-HTML实现MySQL的图片上传

1.django项目编写index.html代码 创建form表单,路由指向upload,请求方式post,enctype设置"multipart/form-data", post请求添加{% csrf_token %},编写两个input,上传和提交 2.添加upload路由 3.views中创建upload 1).获取上传的文件,没有上传则返回"没有指定…

2024年度最高人气的编程语言

本期共享的是 —— 年度地球人气最高的编程语言。 根据我们对人力资源专家和开发者的年度调查&#xff0c;目前市场需求量最大的 10 种编程技术是&#xff1a; Python&#xff08;42.1% 的受访者对具备该技能的候选人有大量需求&#xff09;JS&#xff08;41.6%&#xff09;Ja…

IMX6ULL裸机之UART串口通信(中断)

由于正点原子的UART串口通信裸机例程&#xff0c;采用的是查询方式来进行串口通信&#xff0c;并未使用中断&#xff0c;导致CPU利用率较低&#xff0c;于是产生做本实验的动力。 查阅资料 通过《IMX6ULL参考手册》&#xff0c;得知其串口中断有 从55.4.5 Receiver中可以看出…

解决pycharm中PIL安装失败

问题&#xff1a;在调用pil时显示pil标红 我在设置中下载每次失败&#xff0c;显示 ERROR: Could not find a version that satisfies the requirement PIL (from versions: none) ERROR: No matching distribution found for PIL我尝试了很久&#xff0c;查看了一些博客 &a…

【笔记】【开发方案】APN 配置参数 bitmask 数据转换(Android KaiOS)

一、参数说明 &#xff08;一&#xff09;APN配置结构对比 平台AndroidKaiOS文件类型xmljson结构每个<apn>标签是一条APN&#xff0c;包含完成的信息层级数组结构&#xff0c;使用JSON格式的数据。最外层是mcc&#xff0c;其次mnc&#xff0c;最后APN用数组形式配置&am…

Java使用企业邮箱发送预警邮件

前言&#xff1a;最近接到一个需求&#xff0c;需要根据所监控设备的信息&#xff0c;在出现问题时发送企业微信进行预警。 POM依赖 <!-- 邮件 --> <dependency><groupId>com.sun.mail</groupId><artifactId>jakarta.mail</artifactId>…

【C++】C++11下线程库

C11下线程库 1. thread类的简单介绍2.线程函数参数3.原子性操作库(atomic)4.mutex的种类5. RAII风格加锁解锁5.1Lock_guard5.2unique_lock 6.condition_variable 1. thread类的简单介绍 在C11之前&#xff0c;涉及到多线程问题&#xff0c;都是和平台相关的&#xff0c;比如wi…

Android | ArcGIS入门

一、概述 ArcGIS是由Esri开发的地理信息系统&#xff08;GIS&#xff09;软件。它用于制图、空间分析和数据可视化。ArcGIS允许用户以各种格式创建、管理、分析和共享地理信息。它通常用于城市规划、环境管理和应急响应等领域。该软件包括一系列工具&#xff0c;用于创建地图、…

新年新方案,制造业数字化经营管理平台方案全新升级

伴随着工业4.0和中国智造2025成为制造业领域的两大重要趋势&#xff0c;“推动制造业智能化改造数字化转型”已经到了“不得不”的阶段。 数字化转型能够为制造企业带来降本增效、扩能提质、优化流程、提升竞争力等优势&#xff0c;是建设现代化产业体系的必经之路。 然而&…

CVE-2016-3088(ActiveMQ任意文件写入漏洞)

漏洞描述 1、漏洞编号&#xff1a;CVE-2016-3088 2、影响版本&#xff1a;Apache ActiveMQ 5.x~5.13.0 在 Apache ActiveMQ 5.12.x~5.13.x 版本中&#xff0c;默认关闭了 fileserver 这个应用&#xff08;不过&#xff0c;可以在conf/jetty.xml 中开启&#xff09;&#xff1b;…

【python】linux系统python报错“ssl module in Python is not available”

一、问题现象 1.1 执行pip命令报错 pip安装时遇到openssl问题&#xff0c;没办法安装第三方库 “WARNING: pip is configured with locations that require TLS/SSL, however the ssl module in Python is not available. ” 1.2 导入import ssl 报错 直接执行python&…

C/C++ BM14 链表的奇偶重排

文章目录 前言题目解决方案一1.1 思路阐述1.2 源码 解决方案二2.1 思路阐述2.2 源码 总结 前言 这道题算是链表思路的一种常规题&#xff0c;看透题目本质做起来还是不难。 题目 描述 给定一个单链表&#xff0c;请设定一个函数&#xff0c;将链表的奇数位节点和偶数位节点分…