当前位置: 首页 > news >正文

【SpringBoot】28 API接口防刷(Redis + 拦截器)

Gitee仓库

https://gitee.com/Lin_DH/system

介绍

常用的 API 安全措施包括:防火墙、验证码、鉴权、IP限制、数据加密、限流、监控、网关等,以确保接口的安全性。

常见措施

1)防火墙
防火墙是网络安全中最基本的安全设备之一,主要用于防止未经授权的网络访问和攻击。
防火墙主要用于过滤和控制网络流量,以保护网络安全。
防火墙可以防止的攻击行为包括:

  • 无效数据包:防火墙可以识别和过滤无效的数据包,如错误的 IP 地址、伪造的数据包、无法识别的协议等。
  • DOS 和 DDOS 攻击:防火墙可以使用不同的技术来检测和阻止 DOS 和 DDOS 攻击,如阻止大量 TCP / UDP 连接、IP 地址过滤、流量限制等。
  • 病毒和蠕虫攻击:防火墙可以使用特定的病毒和蠕虫检测技术,如签名检测、行为检测、模式识别等,来防止这些恶意软件的传播。
  • 网络钓鱼和欺骗攻击:防火墙可以检测、防止网络钓鱼、欺骗攻击,如防止虚假登录页面、欺骗的网站等。
  • 恶意流量攻击:防火墙可以检测和防止恶意流量攻击,如过滤带有恶意载荷的数据包和防止被黑客利用的端口。
  • 网络侦察攻击:防火墙可以使用一些技术来防止网络侦察攻击,如防止扫描、端口扫描、漏洞利用等。

2)验证码
在特定接口上,要求用户在访问前先进行验证码验证,以确保发送该请求的为真实用户。

3)鉴权
要求用户在访问 API 时,进行身份认证,并根据用户的权限进行授权,只允许有权限的用户访问特定的接口。
4)IP限制
仅限特定 IP 范围对 API 的访问,例如允许内网或者加入 IP 白名单的能够访问特定 API 。
5)数据加密
对敏感数据进行加密传输,使用 HTTPS 协议保证数据传输的安全性。
以往很多接口都是使用 HTTP 协议(Hyper Text Transport Protocol,超文本传输协议),用于传输客户端和服务器端的数据。
HTTP 协议使用虽然简单方便,但也存在着问题:

  • 使用明文通讯,传输内容容易被窃听
  • 不验证通讯方的身份,容易遭到伪装
  • 无法证明报文的完整性,报文容易被篡改
    为了解决 HTTP 协议的一系列问题,出现了 HTTPS 协议。HTTPS 协议是在 HTTP 协议上添加了加密机制。
    SSL(Secure Socket Layer,安全套接层)
    TLS(Transport Layer Security,传输层安全)
    HTTPS = HTTP + 加密 + 认证 + 完整性保护
    为了安全性考虑,接口的协议需要使用 HTTPS 协议。

6)限流
设置访问频率限制,例如每分钟、每小时、每天只允许请求访问一定次数,超出限制则返回错误信息或者封禁 IP。
7)监控
监控 API 的访问日志,统计用户对接口的调用情况,对流量激增、某个IP频繁请求同一接口,则自动发送邮件等通知,及时采取相应的安全措施。
8)网关
在 API 和客户端之间引入 API 网关,对请求进行过滤、鉴权、限流等操作,保护后端 API 的安全。

IP限制方式(拦截器)

代码实现

第一步:定义 IP 限制拦截器

IPInterceptor.java

import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;/*** IP拦截器* @author DUHAOLIN* @date 2024/11/13*/
@Component
public class IPInterceptor implements HandlerInterceptor {//IP白名单private static final List<String> ALLOWED_IPS = Arrays.asList("127.0.0.1", "0:0:0:0:0:0:0:1");@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String ipAddress = request.getRemoteAddr();//不允许访问的IP返回"Access denied"错误信息,并且设置响应的状态码为403(Forbidden)if (!ALLOWED_IPS.contains(ipAddress)) {response.setStatus(HttpServletResponse.SC_FORBIDDEN);response.getWriter().write("Access denied");return false;}return true;}}

效果图

在这里插入图片描述

限制次数方式(Redis + 拦截器)

Windows安装Redis

Redis 下载链接:https://pan.baidu.com/s/1BMt4cIxjKTtyL3T0_iSC2w 密码:rkne
打开 CMD 命令窗口,在 Redis 安装目录执行如下命令:redis-server.exe redis.windows.conf
在这里插入图片描述

依赖

pom.xml

        <!-- Redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- 分布式锁工具 --><dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>${redission.version}</version></dependency>

配置文件

application.yml

spring:redis:host: localhostport: 6379timeout: 10

代码实现

第一步:添加解析 Redis Key 前缀的接口

KeyPrefix.java

package com.lm.system.redis;/*** @author DUHAOLIN* @date 2024/11/13*/
public interface KeyPrefix {int expireSeconds();String getPrefix();
}

第二步:添加解析 Redis 基础前缀的抽象类

BasePrefix.java

package com.lm.system.redis;/*** @author DUHAOLIN* @date 2024/11/13*/
public abstract class BasePrefix implements KeyPrefix {public BasePrefix() {}public BasePrefix(String prefix) {this(0, prefix);}private int expireSeconds;private String prefix;public BasePrefix(int expireSeconds, String prefix) {this.expireSeconds = expireSeconds;this.prefix = prefix;}@Overridepublic int expireSeconds() {return 0; //默认永不过期}@Overridepublic String getPrefix() {String simpleName = this.getClass().getSimpleName();return simpleName + ":" + prefix;}}

第三步:添加解析用户Key的实现类

AccessKey.java

package com.lm.system.common;import com.lm.system.redis.BasePrefix;/*** @author DUHAOLIN* @date 2024/11/13*/
public class AccessKey extends BasePrefix {public AccessKey() {}public AccessKey(String prefix) {super(0, prefix);}public AccessKey(int expireSeconds, String prefix) {super(expireSeconds, prefix);}public static AccessKey withExpire(int expireSeconds) {return new AccessKey(expireSeconds, "prefix");}@Overridepublic int expireSeconds() {return super.expireSeconds();}@Overridepublic String getPrefix() {return super.getPrefix();}}

第四步:在需要限流的接口上,添加 @AccessLimit 注解。
注:

  • 其他 User 实体类等可以查看 Gitee 仓库(https://gitee.com/Lin_DH/system)。
  • Redis 不能和 cache 缓存一起使用,ServiceImpl中 users 方法使用需要了,需要注释掉 @Cacheable 注解。

UserController.java

    @GetMapping("users")@ApiOperation("获取所有用户信息")@AccessLimit(seconds = 10, maxCount = 3)public String users() {List<User> users = userService.queryAllUser();return ResultBody.build(HttpStatus.OK).setData(users).setCount(users.size()).getReturn();}

第五步:启动类添加 @EnableCaching 注解

SystemApplication.java

package com.lm.system;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching;@EnableCaching
@SpringBootApplication
@MapperScan("com.lm.system.mapper")
public class SystemApplication extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(SystemApplication.class, args);}@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(SystemApplication.class);}}

第六步:添加 Redis 操作接口

RedisService.java

package com.lm.system.redis;import org.redisson.api.RReadWriteLock;import java.util.List;
import java.util.Map;
import java.util.Set;/*** @author DUHAOLIN* @date 2024/11/13*/
public interface RedisService {/*** 保存属性*/void set(String key, Object value, long time);/*** 保存属性*/void set(String key, Object value);/*** 获取属性*/Object get(String key);/*** 删除属性*/Boolean del(String key);/*** 批量删除属性*/Long del(List<String> keys);/*** 设置过期时间*/Boolean expire(String key, long time);/*** 获取过期时间*/Long getExpire(String key);/*** 判断是否有该属性*/Boolean hasKey(String key);/*** 按delta递增*/Long incr(String key, long delta);/*** 按delta递减*/Long decr(String key, long delta);/*** 获取Hash结构中的属性*/Object hGet(String key, String hashKey);/*** 向Hash结构中放入一个属性*/Boolean hSet(String key, String hashKey, Object value, long time);/*** 向Hash结构中放入一个属性*/void hSet(String key, String hashKey, Object value);/*** 直接获取整个Hash结构*/Map<Object, Object> hGetAll(String key);/*** 直接设置整个Hash结构*/Boolean hSetAll(String key, Map<String, Object> map, long time);/*** 直接设置整个Hash结构*/void hSetAll(String key, Map<String, ?> map);/*** 删除Hash结构中的属性*/void hDel(String key, Object... hashKey);/*** 判断Hash结构中是否有该属性*/Boolean hHasKey(String key, String hashKey);/*** Hash结构中属性递增*/Long hIncr(String key, String hashKey, Long delta);/*** Hash结构中属性递减*/Long hDecr(String key, String hashKey, Long delta);/*** 获取Set结构*/Set<Object> sMembers(String key);/*** 向Set结构中添加属性*/Long sAdd(String key, Object... values);/*** 向Set结构中添加属性*/Long sAdd(String key, long time, Object... values);/*** 是否为Set中的属性*/Boolean sIsMember(String key, Object value);/*** 获取Set结构的长度*/Long sSize(String key);/*** 删除Set结构中的属性*/Long sRemove(String key, Object... values);/*** 获取List结构中的属性*/List<Object> lRange(String key, long start, long end);/*** 获取List结构的长度*/Long lSize(String key);/*** 根据索引获取List中的属性*/Object lIndex(String key, long index);/*** 向List结构中添加属性*/Long lPush(String key, Object value);/*** 向List结构中添加属性*/Long lPush(String key, Object value, long time);/*** 向List结构中批量添加属性*/Long lPushAll(String key, Object... values);/*** 向List结构中批量添加属性*/Long lPushAll(String key, Long time, Object... values);/*** 从List结构中移除属性*/Long lRemove(String key, long count, Object value);/*** 尝试获取分布式锁* @param key* @param timeOut* @param expireTime* @return* @throws InterruptedException*/boolean tryLock(String key, long timeOut, long expireTime) throws InterruptedException;/*** 解锁* @param key* @return*/void unLock(String key);/*** 获取分布式读写锁对象* @param lockKey* @return*/RReadWriteLock getReadWriteLock(String lockKey);
}

第七步:添加 Redis 操作实现类

RedisServiceImpl.java

package com.lm.system.redis;import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;/*** @author DUHAOLIN* @date 2024/11/13*/
@Service
public class RedisServiceImpl implements RedisService {@Resourceprivate RedisTemplate<String, Object> redisTemplate;@Resourceprivate RedissonClient redissonClient;@Overridepublic void set(String key, Object value, long time) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);}@Overridepublic void set(String key, Object value) {redisTemplate.opsForValue().set(key, value);}@Overridepublic Object get(String key) {return redisTemplate.opsForValue().get(key);}@Overridepublic Boolean del(String key) {return redisTemplate.delete(key);}@Overridepublic Long del(List<String> keys) {return redisTemplate.delete(keys);}@Overridepublic Boolean expire(String key, long time) {return redisTemplate.expire(key, time, TimeUnit.SECONDS);}@Overridepublic Long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}@Overridepublic Boolean hasKey(String key) {return redisTemplate.hasKey(key);}@Overridepublic Long incr(String key, long delta) {return redisTemplate.opsForValue().increment(key, delta);}@Overridepublic Long decr(String key, long delta) {return redisTemplate.opsForValue().increment(key, -delta);}@Overridepublic Object hGet(String key, String hashKey) {return redisTemplate.opsForHash().get(key, hashKey);}@Overridepublic Boolean hSet(String key, String hashKey, Object value, long time) {redisTemplate.opsForHash().put(key, hashKey, value);return expire(key, time);}@Overridepublic void hSet(String key, String hashKey, Object value) {redisTemplate.opsForHash().put(key, hashKey, value);}@Overridepublic Map<Object, Object> hGetAll(String key) {return redisTemplate.opsForHash().entries(key);}@Overridepublic Boolean hSetAll(String key, Map<String, Object> map, long time) {redisTemplate.opsForHash().putAll(key, map);return expire(key, time);}@Overridepublic void hSetAll(String key, Map<String, ?> map) {redisTemplate.opsForHash().putAll(key, map);}@Overridepublic void hDel(String key, Object... hashKey) {redisTemplate.opsForHash().delete(key, hashKey);}@Overridepublic Boolean hHasKey(String key, String hashKey) {return redisTemplate.opsForHash().hasKey(key, hashKey);}@Overridepublic Long hIncr(String key, String hashKey, Long delta) {return redisTemplate.opsForHash().increment(key, hashKey, delta);}@Overridepublic Long hDecr(String key, String hashKey, Long delta) {return redisTemplate.opsForHash().increment(key, hashKey, -delta);}@Overridepublic Set<Object> sMembers(String key) {return redisTemplate.opsForSet().members(key);}@Overridepublic Long sAdd(String key, Object... values) {return redisTemplate.opsForSet().add(key, values);}@Overridepublic Long sAdd(String key, long time, Object... values) {Long count = redisTemplate.opsForSet().add(key, values);expire(key, time);return count;}@Overridepublic Boolean sIsMember(String key, Object value) {return redisTemplate.opsForSet().isMember(key, value);}@Overridepublic Long sSize(String key) {return redisTemplate.opsForSet().size(key);}@Overridepublic Long sRemove(String key, Object... values) {return redisTemplate.opsForSet().remove(key, values);}@Overridepublic List<Object> lRange(String key, long start, long end) {return redisTemplate.opsForList().range(key, start, end);}@Overridepublic Long lSize(String key) {return redisTemplate.opsForList().size(key);}@Overridepublic Object lIndex(String key, long index) {return redisTemplate.opsForList().index(key, index);}@Overridepublic Long lPush(String key, Object value) {return redisTemplate.opsForList().rightPush(key, value);}@Overridepublic Long lPush(String key, Object value, long time) {Long index = redisTemplate.opsForList().rightPush(key, value);expire(key, time);return index;}@Overridepublic Long lPushAll(String key, Object... values) {return redisTemplate.opsForList().rightPushAll(key, values);}@Overridepublic Long lPushAll(String key, Long time, Object... values) {Long count = redisTemplate.opsForList().rightPushAll(key, values);expire(key, time);return count;}@Overridepublic Long lRemove(String key, long count, Object value) {return redisTemplate.opsForList().remove(key, count, value);}@Overridepublic boolean tryLock(String key, long timeOut, long expireTime) throws InterruptedException {RLock lock = redissonClient.getLock(key);return lock.tryLock(timeOut, expireTime, TimeUnit.SECONDS);}/*** 解锁* @param key* @return*/@Overridepublic void unLock(String key){RLock lock = redissonClient.getLock(key);lock.unlock();}@Overridepublic RReadWriteLock getReadWriteLock(String lockKey) {return redissonClient.getReadWriteLock(lockKey);}
}

第八步:添加访问频率限制拦截器

AntiBrushInterceptor.java

package com.lm.system.interceptor;import com.lm.system.annotation.AccessLimit;
import com.lm.system.common.AccessKey;
import com.lm.system.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;/*** 访问频率限制拦截器* @author DUHAOLIN* @date 2024/11/13*/
@Slf4j
public class AntiBrushInterceptor implements HandlerInterceptor {private final RedisService redisService;public AntiBrushInterceptor(RedisService redisService) {this.redisService = redisService;}private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//判断请求是否属于方法请求if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;//获取方法中的注解,判断是否有该注解AccessLimit accessLimit = handlerMethod.getMethodAnnotation(AccessLimit.class);if (accessLimit == null) {return true;}int seconds = accessLimit.seconds();int maxCount = accessLimit.maxCount();boolean needLogin = accessLimit.needLogin();String key = request.getRequestURI();if (needLogin) {//判断是否登录key += "_userId001"; //已登录,获取userId}//从redis中获取用户的访问次数AccessKey accessKey = AccessKey.withExpire(seconds);String realKey = accessKey.getPrefix() + key;Integer count = (Integer) redisService.get(realKey);//访问次数处理if (count == null) {//首次访问redisService.set(realKey, 1, 60);}else if (count < maxCount) {//加1redisService.incr(realKey, 1);}else {//超出访问次数log.info("进入服务降级,时间{}", LocalDateTime.now().format(FORMATTER));response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());response.getWriter().write("Too Many Requests. Number of visits: " + maxCount);return false;}}return true;}
}

效果图

前三次访问正常,第四次开始返回错误信息。
在这里插入图片描述

项目结构图

在这里插入图片描述

参考链接

如何防范API经常被人频繁调用【https://baijiahao.baidu.com/s?id=1791472081681790682&wfr=spider&for=pc】
API接口防刷的9种方案【https://baijiahao.baidu.com/s?id=1802852256970678261&wfr=spider&for=pc】
Spring Boot 项目的 API 接口防刷【https://www.iocoder.cn/Fight/Spring-Boot-project-API-anti-brush-interface/?self】

相关文章:

【SpringBoot】28 API接口防刷(Redis + 拦截器)

Gitee仓库 https://gitee.com/Lin_DH/system 介绍 常用的 API 安全措施包括&#xff1a;防火墙、验证码、鉴权、IP限制、数据加密、限流、监控、网关等&#xff0c;以确保接口的安全性。 常见措施 1&#xff09;防火墙 防火墙是网络安全中最基本的安全设备之一&#xff0c…...

IT运维专家给年轻人一些职业上的建议

运维工作在现代企业中是非常重要的一环,保证系统的稳定性、可用性以及安全性对企业的正常运营至关重要。以下是我给年轻人的一些职业发展建议,希望能够帮助你们在运维领域找到方向并取得成功。 1. 夯实基础,扎实技术功底 精通操作系统与网络:运维工作需要深入理解操作系统…...

Django基础之路由

一.前言 前面我们说了django的安装于基础配置&#xff0c;基础知识点我就细分下来&#xff0c;每天和大家讲一点&#xff0c;今天就要和大家说django的基础知识点了&#xff0c;我们今天先来讲路由&#xff0c;内容不多&#xff0c;希望大家记住 二.传统路由 路由就是前面一个…...

Python实例化中默认值的行为及应用

Python实例化中默认值的行为及应用 适合初学者阅读 本文要点 使用可变对象作为默认参数会导致所有实例共享同一对象&#xff0c;引发意外的数据修改。不可变对象作为默认参数时&#xff0c;每次实例化都会创建新的对象&#xff0c;不会共享数据。推荐使用None作为默认值&…...

【WRF后处理】WRF模拟效果评价及可视化:MB、RMSE、IOA、R

【WRF后处理】模拟效果评价及可视化 准备工作模型评价指标Python实现代码Python处理代码:导入站点及WRF模拟结果可视化图形及评价指标参考在气象和环境建模中(如使用 WRF 模型进行模拟),模型性能评价指标是用于定量评估模拟值与观测值之间偏差和拟合程度的重要工具。 本博客…...

ShenNiusModularity项目源码学习(4:身份认证)

ShenNiusModularity项目有两套启动方式&#xff0c;一种是ShenNius.Admin.Mvc项目启动&#xff0c;该项目为MVC模式&#xff0c;带前台页面&#xff0c;也有后台服务&#xff0c;另一种是ShenNius.Admin.Hosting&#xff0c;该项目启动后仅提供后台服务&#xff0c;供其它前台项…...

python+django自动化部署日志采用‌WebSocket前端实时展示

一、开发环境搭建和配置 # channels是一个用于在Django中实现WebSocket、HTTP/2和其他异步协议的库。 pip install channels#channels-redis是一个用于在Django Channels中使用Redis作为后台存储的库。它可以用于处理#WebSocket连接的持久化和消息传递。 pip install channels…...

flink学习(6)——自定义source和kafka

概述 SourceFunction:非并行数据源(并行度只能1) --接口 RichSourceFunction:多功能非并行数据源(并行度只能1) --类 ParallelSourceFunction:并行数据源(并行度能够>1) --接口 RichParallelSourceFunction:多功能并行数据源(并行度能够>1) --类 【建议使用的】 ——…...

开发常见问题及解决

1.DBeaver 报Public Key Retrieval is not allowed 在使用DBeaver连接数据库时出现“Public Key Retrieval is not allowed”错误&#xff0c;主要是因为数据库连接配置的安全策略导致的。以下是详细的解释和解决方法&#xff1a; 错误原因 这个错误通常出现在连接MySQL数据…...

python excel接口自动化测试框架!

今天采用Excel继续写一个接口自动化测试框架。 设计流程图 这张图是我的excel接口测试框架的一些设计思路。 首先读取excel文件&#xff0c;得到测试信息&#xff0c;然后通过封装的requests方法&#xff0c;用unittest进行测试。 其中&#xff0c;接口关联的参数通过正则进…...

mybatis:You have an error in your SQL syntax;

完整报错You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near false, false, false, false, false, false, false, false, false, false, false, at line 1 SQL: INSERT INTO user …...

使用 Maven 开发 IntelliJ IDEA 插件

使用 Maven 开发 IntelliJ IDEA 插件的完整流程 1. 创建 Maven 项目 1.1 使用 IntelliJ 创建 Maven 项目 打开 IntelliJ IDEA&#xff0c;点击 File > New > Project。选择 Maven&#xff0c;填写项目名称和 GroupId&#xff0c;例如&#xff1a; GroupId: com.exampl…...

Windows修复SSL/TLS协议信息泄露漏洞(CVE-2016-2183) --亲测

漏洞说明&#xff1a; 打开链接&#xff1a;https://docs.microsoft.com/zh-cn/troubleshoot/windows-server/windows-security/restrict-cryptographic-algorithms-protocols-schannel 可以看到&#xff1a; 找到&#xff1a;应通过配置密码套件顺序来控制 TLS/SSL 密码 我们…...

uniapp生命周期:应用生命周期和页面生命周期

文章目录 1.应用的生命周期2.页面的生命周期 1.应用的生命周期 生命周期的概念&#xff1a;一个对象从创建、运行、销毁的整个过程被称为生命周期 生命周期函数&#xff1a;在生命周期中每个阶段会伴随着每一个函数的出发&#xff0c;这些函数被称为生命周期函数 所有页面都…...

基于SSM的婴幼儿用品商城系统+LW示例参考

1.项目介绍 功能模块&#xff1a;管理员&#xff08;产品管理、产品分类、会员管理、订单管理、秒杀活动、文章管理、数据统计等&#xff09;、普通用户&#xff08;登录注册、个人中心、购物车、我的收藏、各类信息查看等&#xff09;技术选型&#xff1a;SSM&#xff0c;jsp…...

【工具变量】城市供应链创新试点数据(2007-2023年)

一、测算方式&#xff1a;参考C刊《经济管理》沈坤荣和乔刚老师&#xff08;2024&#xff09;的做法&#xff0c;使用“供应链创新与应用试点”的政策虚拟变量&#xff08;TreatPost&#xff09;表征。若样本城市为试点城市&#xff0c;则赋值为 1&#xff0c;否则为 0&#xf…...

【carla生成车辆时遇到的问题】carla显示的坐标和carlaworld中提取的坐标y值相反

项目需要重新运行了一下generate_car.py的脚本&#xff0c;发现死活生成不了&#xff0c;研究了半天&#xff0c;发现脚本里面生成车辆的坐标值y和carla_ros_bridge_with_example_ego_vehicle.launch脚本打开的驾驶操控界面里面的y值正好是相反数! y1-y2 因为&#xff0c;我运行…...

Jira使用笔记二 ScriptRunner 验证问题创建角色

背景 最近在对公司Jira工作流改造&#xff0c;收到这么一个要求&#xff1a;某些问题类型只有某些角色可以创建。本来是想通过Jira内建的权限控制来处理的。结果点到权限页面&#xff0c;心都凉透了。 好吧&#xff0c;那只能上脚本了。最终使用ScriptRunner的Simple scripte…...

Java线程的使用

Java中的线程是用来实现多任务并发执行的机制。在Java中&#xff0c;主要有两种方式来创建和使用线程&#xff1a;实现Runnable接口和继承Thread类。 实现Runnable接口&#xff1a; 创建一个类&#xff0c;实现Runnable接口&#xff0c;并重写run()方法。在run()方法中定义线程…...

自动化测试工具Ranorex Studio(四十三)-RANOREXPATH编辑器5

代码示例 下面的代码示例将讲解如何使用Ranorex API来编写代码模块&#xff0c;或者是使用用户代码来扩展录制的模块。 在代码中使用对象库 使用对象库等待UI元素 建立Adapter来访问更多的属性和方法 为对象库元素建立一组Adapter 使用Validate类 强制一个测试用例失败 设置aut…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义&#xff08;Task Definition&…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台

淘宝扭蛋机小程序系统的开发&#xff0c;旨在打造一个互动性强的购物平台&#xff0c;让用户在购物的同时&#xff0c;能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机&#xff0c;实现旋转、抽拉等动作&#xff0c;增…...

Rust 开发环境搭建

环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行&#xff1a; rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu ​ 2、Hello World fn main() { println…...

git: early EOF

macOS报错&#xff1a; Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/.git/ remote: Enumerating objects: 2691797, done. remote: Counting objects: 100% (1760/1760), done. remote: Compressing objects: 100% (636/636…...

Sklearn 机器学习 缺失值处理 获取填充失值的统计值

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 使用 Scikit-learn 处理缺失值并提取填充统计信息的完整指南 在机器学习项目中,数据清…...

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…...