2024-09-05



import redis
 
# 假设已经有了Redis连接对象`redis_conn`
 
class FansService:
    def __init__(self, redis_conn):
        self.redis_conn = redis_conn
 
    def add_fans(self, user_id, fans_id):
        """为用户添加粉丝"""
        key = f"user:{user_id}:fans"
        self.redis_conn.sadd(key, fans_id)
 
    def remove_fans(self, user_id, fans_id):
        """为用户移除粉丝"""
        key = f"user:{user_id}:fans"
        self.redis_conn.srem(key, fans_id)
 
    def get_fans(self, user_id):
        """获取用户的粉丝ID列表"""
        key = f"user:{user_id}:fans"
        return self.redis_conn.smembers(key)
 
    def get_followers(self, user_id):
        """获取用户的关注者ID列表"""
        key = f"user:{user_id}:followers"
        return self.redis_conn.smembers(key)
 
# 使用示例
# 假设`redis_conn`是已经连接到Redis的对象
redis_conn = redis.StrictRedis(host='localhost', port=6379, db=0)
fans_service = FansService(redis_conn)
 
# 添加粉丝
fans_service.add_fans('user123', 'fans456')
 
# 获取粉丝列表
fans_list = fans_service.get_fans('user123')
print(fans_list)  # 输出粉丝ID的集合

这个代码示例展示了如何使用Redis的Set数据结构来实现用户粉丝的关注与取关功能。代码中的FansService类封装了与粉丝关系相关的操作,通过Redis连接对象与Redis服务器进行交互。使用时,首先创建FansService的实例,然后调用相应的方法来管理用户的粉丝关系。

2024-09-05

在Spring Boot中实现不同项目之间的远程调用,通常可以通过以下几种方式:

  1. RESTful API: 使用Spring Boot的@RestController创建RESTful API,客户端可以通过HTTP请求进行调用。
  2. WebSocket: 使用Spring Boot的@EnableWebSocketMessageBroker注解启用WebSocket,可以实现双向通信。
  3. 使用消息队列: 如Kafka、RabbitMQ等,发送方发送消息到队列,接收方从队列中消费消息。

以RESTful API为例,下面是一个简单的服务提供者和消费者的示例:

服务提供者(生产者):




@RestController
public class MyServiceController {
 
    @GetMapping("/service")
    public String serviceMethod() {
        // 业务逻辑
        return "Service Response";
    }
}

服务消费者(消费者):




@RestController
public class ConsumerController {
 
    private RestTemplate restTemplate;
 
    public ConsumerController(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }
 
    @GetMapping("/consume")
    public String consumeService() {
        String response = restTemplate.getForObject("http://provider-url/service", String.class);
        return response;
    }
}

在这个例子中,MyServiceController 提供了一个REST接口,ConsumerController 使用 RestTemplate 来调用提供者的接口。

确保在服务消费者的application.properties或application.yml中配置好服务提供者的URL,例如:




spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=dbuser
spring.datasource.password=dbpass

或者在使用 RestTemplate 时,可以通过代码显式设置服务提供者的URL:




@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder.rootUri("http://provider-url/").build();
}

以上代码仅展示了RESTful API的简单使用,实际使用时需要考虑安全性、负载均衡、超时处理、错误处理等问题。

2024-09-05

在 Go 语言中,函数可以接收可变数量的参数。这通过在参数列表中使用 ...T 语法实现,其中 T 是类型名。

以下是一些示例:

  1. 传递不定数量的 int 参数:



package main
 
import (
    "fmt"
)
 
func sum(nums ...int) {
    fmt.Print(nums, " ")
    total := 0
    for _, num := range nums {
        total += num
    }
    fmt.Println(total)
}
 
func main() {
    sum(1, 2)
    sum(1, 2, 3)
}

在上述代码中,sum 函数接收一个 int 类型的可变参数。当我们调用 sum 函数时,我们可以传递任意数量的 int 参数。

  1. 传递不定数量的 string 参数:



package main
 
import (
    "fmt"
)
 
func join(s ...string) {
    fmt.Print(s, " ")
    result := ""
    for _, str := range s {
        result += str
    }
    fmt.Println(result)
}
 
func main() {
    join("Hello", ", ", "World")
    join("Hello", "World")
}

在上述代码中,join 函数接收一个 string 类型的可变参数。当我们调用 join 函数时,我们可以传递任意数量的 string 参数。

  1. 传递不定数量的任何类型的参数:



package main
 
import (
    "fmt"
)
 
func printAll(args ...interface{}) {
    fmt.Print(args, " ")
    for _, arg := range args {
        fmt.Print(arg, " ")
    }
    fmt.Println()
}
 
func main() {
    printAll(1, "Hello", true)
    printAll("Hello", true, 1)
}

在上述代码中,printAll 函数接收一个 interface{} 类型的可变参数。interface{} 类型是一个特殊的类型,可以用来表示任何类型的值。当我们调用 printAll 函数时,我们可以传递任意数量的任何类型的参数。

注意:在 Go 语言中,函数只能有一个可变参数,并且它必须是函数签名的最后一个参数。

2024-09-05

SQLite 原生并不直接支持 JSON 数据类型,但可以通过内置的 JSON 函数来处理 JSON 数据。

以下是一个简单的例子,演示如何在 SQLite 中存储和查询 JSON 数据:

  1. 创建一个表并使用 JSON 类型的列。
  2. 插入 JSON 数据时,直接将 JSON 字符串插入即可。
  3. 查询 JSON 数据时,可以使用 JSON_EXTRACT 函数来提取 JSON 字段。



CREATE TABLE example (
    id INTEGER PRIMARY KEY,
    data JSON
);
 
INSERT INTO example (data) VALUES ('{"name": "John", "age": 30}');
 
SELECT JSON_EXTRACT(data, '$.name') AS name FROM example;

在这个例子中,data 列用于存储 JSON 数据,JSON_EXTRACT 函数用于从 JSON 字符串中提取特定的字段。

注意:

  • 请确保您使用的 SQLite 版本支持 JSON 函数(版本 3.35.0 开始内置支持)。
  • 上述 SQL 语句可能需要在支持 JSON 的 SQLite 环境中运行,例如通过命令行或者一个支持 SQLite 的编程语言库。
2024-09-05

Spring Cloud Gateway 负责将请求路由到后端服务,并提供一些内置的负载均衡策略。下面是如何使用Spring Cloud Gateway进行负载均衡的简单示例:




@Configuration
public class GatewayConfig {
 
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("path_route", r -> r.path("/get")
                        .filters(f -> f.addRequestHeader("Hello", "World"))
                        .uri("lb://SERVICE-NAME"))
                .build();
    }
}

在这个配置中,lb://SERVICE-NAME 指定了Spring Cloud Gateway应该将请求通过负载均衡发送到名为 SERVICE-NAME 的服务。

Spring Cloud Gateway中负载均衡的实现依赖于Spring WebFlux中的ReactorLoadBalancerClient。在实际的请求处理过程中,Gateway中的LoadBalancerClientFilter会与ReactorLoadBalancerClient交互,从而根据提供的服务ID选择正确的服务实例,并进行负载均衡。

如果你想深入了解源码,可以查看LoadBalancerClientFilter的实现,它负责从LoadBalancer获取服务实例,并将请求委托给选定的服务实例。




public class LoadBalancerClientFilter implements GlobalFilter, Ordered {
    // ...
 
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // ...
        ServiceInstance instance = loadBalancer.choose(serviceId, hints);
        if (instance == null) {
            log.trace("LoadBalancerClientFilter [{}]: no instances available for: {}",
                    serviceId, exchange.getRequest().getURI());
            return Mono.error(new NotFoundException("No instances available for "+ serviceId));
        }
 
        // Use the chosen instance to set the URL before filtering continues.
        URI requestUrl = loadBalancer.reconstructURI(instance, exchange.getRequest());
 
        // ...
 
        return chain.filter(exchange);
    }
    // ...
}

在这个代码片段中,loadBalancer.choose(serviceId, hints) 方法负责选择一个服务实例,而loadBalancer.reconstructURI(instance, exchange.getRequest()) 方法则用于构建新的请求URL,该URL将请求委托给选定的服务实例。

要进一步分析源码,你可以查看ReactorLoadBalancer接口及其实现类,如BlockingLoadBalancerClientReactiveLoadBalancer等。这些类负责处理服务发现和实例选择逻辑。

2024-09-05

在Oracle中,connect_by_root是一个非常有用的函数,可以在使用START WITH ... CONNECT BY子句的递归查询中获取根级别的值。然而,在早期的Oracle版本中,可能没有直接的方式来替代connect_by_root

如果你需要在不支持connect_by_root的版本中实现类似的功能,你可以使用一个临时表或者一个WITH子句来手动追踪根级别的值。

以下是一个使用WITH子句的例子,它模拟了connect_by_root的行为:




WITH RECURSIVE_TABLE AS (
  SELECT
    column_a,
    column_b,
    column_a AS root_column_a
  FROM
    your_table
  WHERE
    condition_a
  UNION ALL
  SELECT
    rt.column_a,
    your_table.column_b,
    rt.root_column_a
  FROM
    RECURSIVE_TABLE rt
  JOIN
    your_table
  ON
    rt.column_b = your_table.condition_b
)
SELECT
  *
FROM
  RECURSIVE_TABLE;

在这个例子中,root_column_a用来存储根级别的column_a值。在递归查询的每一步,我们将root_column_a设置为上一级的column_a值。这样,root_column_a对于每个结果集中的行将保持为其最初(根)的值。

请注意,这个例子假设你的数据库支持WITH子句(Oracle 9i及其更高版本),并且已经替换了your_tablecolumn_acolumn_bcondition_acondition_b为你的具体表名和列名。

如果你的环境不支持WITH子句,你可能需要使用一个临时表或者是一个自定义函数来实现相同的逻辑。这种情况相对复杂,并且需要根据你的具体需求来实现。

2024-09-05

Python3的uuid模块提供了一个生成UUID的函数,以及一组处理UUID的类。

  1. 生成一个随机的UUID



import uuid
 
print(uuid.uuid4())
  1. 生成一个基于时间戳和主机ID的UUID



import uuid
 
print(uuid.uuid1())
  1. 将UUID转换为字符串



import uuid
 
uuid_obj = uuid.uuid4()
print(str(uuid_obj))
  1. 将字符串转换为UUID



import uuid
 
uuid_str = "076bf41e-8179-489e-89a5-b8456ced29c2"
uuid_obj = uuid.UUID(uuid_str)
print(uuid_obj)
  1. 比较两个UUID



import uuid
 
uuid_a = uuid.uuid4()
uuid_b = uuid.uuid4()
 
print(uuid_a == uuid_b)
print(uuid_a < uuid_b)
  1. 获取UUID的16个字节形式



import uuid
import binascii
 
uuid_obj = uuid.uuid4()
bytes_uuid = uuid_obj.bytes
print(bytes_uuid)
print(binascii.hexlify(bytes_uuid))

以上就是Python3中uuid模块的基本使用方法。

2024-09-05

在CentOS 7上部署Tomcat并发布WAR包的步骤如下:

  1. 安装Java环境



sudo yum install java-1.8.0-openjdk-devel
  1. 添加Tomcat用户



sudo useradd -r -m -U -d /opt/tomcat -s /bin/false tomcat
  1. 下载并安装Tomcat



cd /tmp
wget https://downloads.apache.org/tomcat/tomcat-9/v9.0.62/bin/apache-tomcat-9.0.62.tar.gz
sudo tar xf apache-tomcat-9.0.62.tar.gz -C /opt/
sudo ln -s /opt/apache-tomcat-9.0.62 /opt/tomcat
sudo chown -RH tomcat:tomcat /opt/tomcat
sudo sh -c 'chmod +x /opt/tomcat/bin/*.sh'
  1. 创建systemd服务文件



sudo tee /etc/systemd/system/tomcat.service <<EOF
[Unit]
Description=Tomcat 9 servlet container
After=network.target
 
[Service]
Type=forking
 
User=tomcat
Group=tomcat
 
Environment="JAVA_HOME=/usr/lib/jvm/jre"
Environment="CATALINA_PID=/opt/tomcat/temp/tomcat.pid"
Environment="CATALINA_HOME=/opt/tomcat"
Environment="CATALINA_BASE=/opt/tomcat"
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"
Environment="JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom"
 
ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh
 
[Install]
WantedBy=multi-user.target
EOF
  1. 重载systemd以读取新的服务文件并启动Tomcat服务



sudo systemctl daemon-reload
sudo systemctl start tomcat
sudo systemctl enable tomcat
  1. 发布WAR包

    将你的WAR包上传到Tomcat的webapps目录下。例如,如果你的WAR包名为myapp.war,可以使用scp或其他方式上传到服务器的/opt/tomcat/webapps/目录。

  2. 自动部署

    Tomcat会自动部署WAR包。你可以通过浏览器访问http://<服务器IP>:8080/myapp来查看你的应用是否运行正常。

注意:确保你的WAR包是正确的,并且不包含任何对你的生产环境不利的操作。在部署之前,建议在开发或测试环境中进行充分的测试。

2024-09-05

在Spring Boot 3中,跨域问题可以通过配置一个WebFilter来解决,这个过滤器会处理HTTP请求并添加必要的跨域头。以下是一个简单的实现示例:




import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
 
@Component
public class CorsFilter implements WebFilter {
 
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        // 添加跨域响应头
        exchange.getResponse().getHeaders().set("Access-Control-Allow-Origin", "*");
        exchange.getResponse().getHeaders().set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        exchange.getResponse().getHeaders().set("Access-Control-Allow-Headers", "Content-Type");
 
        // 如果是OPTIONS请求,直接返回
        if ("OPTIONS".equals(exchange.getRequest().getMethodValue())) {
            exchange.getResponse().setStatusCode(200);
            return exchange.getResponse().setComplete();
        }
 
        // 继续执行其他过滤器链
        return chain.filter(exchange);
    }
}

在这个例子中,我们创建了一个名为CorsFilter的类,该类实现了WebFilter接口。我们在filter方法中手动设置了必要的跨域响应头,并允许所有源("*")进行跨域请求。如果请求方法是OPTIONS,我们直接设置响应状态为200并结束响应,以满足预检请求。

这样配置后,你的Spring Boot 3应用将能够正确处理跨域请求,不再需要CORS配置文件或复杂的配置。

2024-09-05



import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import java.nio.charset.StandardCharsets;
 
public class GuavaBloomFilterExample {
 
    // 创建一个布隆过滤器,假设预计插入10000个元素,期望错误概率为0.01%
    private static final BloomFilter<String> bloomFilter = BloomFilter.create(
            Funnels.stringFunnel(StandardCharsets.UTF_8),
            10000,
            0.01 / 100);
 
    public static void main(String[] args) {
        // 向布隆过滤器中添加元素
        bloomFilter.put("element1");
        bloomFilter.put("element2");
 
        // 检查元素是否可能存在于布隆过滤器中
        boolean mayContain = bloomFilter.mightContain("element1"); // 应该返回true
        boolean mayNotContain = bloomFilter.mightContain("element3"); // 应该返回false
 
        // 输出结果
        System.out.println("element1 is in the filter: " + mayContain);
        System.out.println("element3 is in the filter: " + mayNotContain);
    }
}

这段代码演示了如何在Spring Boot项目中使用Guava库的BloomFilter功能。首先创建了一个布隆过滤器实例,然后演示了如何添加元素并检查元素是否可能存在于过滤器中。这个例子简单明了,有助于理解布隆过滤器的概念和使用方法。