Spring boot 实战指南(三):配置事务,整合Elasticsearch、swagger、redis、rabbitMQ
文章目录
一、配置事务
依赖
<!-- 事务管理依赖以下二选一即可--><!-- 用来开启事务使用 但是mybatis-plus-boot-starter默认引入了sprint-tx -->
<!-- <dependency>-->
<!-- <groupId>org.springframework</groupId>-->
<!-- <artifactId>spring-tx</artifactId>-->
<!-- </dependency>--><!-- springboot整合的事务开启依赖,无论是mybatis或是mybatis-plus都适用 -->
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-aop</artifactId>-->
<!-- </dependency>-->
使用注解
在启动类上添加注解:
@EnableTransactionManagement //开启事务
在需要开启事务的类或者方法上使用注解,前者表示该类的所有方法都开启事务,后者表示只对具体的方法开启事务:
@Transactional(rollbackFor = Exception.class)
如果括号里不带参数表示仅在遇到运行时异常时才回滚,而写了rollbackFor = Exception.class
表示遇到非运行时异常也回滚。
二、Elasticsearch
官方文档
Elasticsearch教程
自己搭建了一个简单的demo,仓库在这里,可以直接运行,不过需要自行安装Elasticsearch7.16.3并在application.yml改一下url。
创建项目
用spring initializr 快速搭建一个项目,sdk选的1.8,java版本是8。
spring boot版本选择2.7.x。
勾选这些依赖:
配置maven
file > settings > build,execution,deployment > build tools > maven
完善依赖
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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.2</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>tracy</groupId><artifactId>claimnet-client</artifactId><version>0.0.1-SNAPSHOT</version><name>claimnet-client</name><description>claimnet客户端</description><properties><java.version>8</java.version></properties><dependencies><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-elasticsearch</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>
es连接配置
application.yml
spring:elasticsearch:rest:uris: http://es服务器ip:9200
实体映射
package tracy.claimnetclient.entity;import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;import java.io.Serializable;@Data
@Document(indexName = "text",createIndex = false) //如果Elasticsearch库中原本不存在这个索引的数据,这里可以写true
public class Text implements Serializable {@Id //将下面这个属性标记为id@Field(name = "id",type = FieldType.Text)String id;@Field(name = "application_no",type = FieldType.Text)String applicationNo;@Field(name = "content",type = FieldType.Text)String content;@Field(name = "date",type = FieldType.Text)String date;@Field(name = "entity",type = FieldType.Text)String entity;@Field(name = "feature",type = FieldType.Text)String feature;
}
注意,这些属性和Elasticsearch数据库中对应文档中的属性是一一对应的。
repository
ElasticsearchRepository中提供了很多线程的方法,可以满足简单的增删改查需求:
package tracy.claimnetclient.repository;import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import tracy.claimnetclient.entity.Text;
import java.util.List;public interface TextRepository extends ElasticsearchRepository<Text,String> {//这里的String表示id的类型//PageRequest用来实现分页查询List<Text> findTextsByIdOrApplicationNoOrContent(String id, String app, String keyword, PageRequest pageRequest);
}
service
接口:
package tracy.claimnetclient.service;import tracy.claimnetclient.entity.Text;
import tracy.claimnetclient.util.PairResult;import java.util.List;public interface TextService {List<Text> text(String keyword,Integer curPage,Integer pageSize);
}
实现:
package tracy.claimnetclient.service;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import tracy.claimnetclient.entity.Text;
import tracy.claimnetclient.repository.TextRepository;
import tracy.claimnetclient.util.PairResult;import java.util.Arrays;
import java.util.List;@Service
public class TextServiceImpl implements TextService{@Autowiredprivate TextRepository textRepository;@Overridepublic List<Text> text(String keyword, Integer curPage, Integer pageSize) {if(curPage==null)curPage=1;if(pageSize==null)pageSize=10;return textRepository.findTextsByIdOrApplicationNoOrContent(keyword,keyword,keyword, PageRequest.of(curPage-1,pageSize));}
}
controller
package tracy.claimnetclient.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tracy.claimnetclient.entity.Claim;
import tracy.claimnetclient.entity.Text;
import tracy.claimnetclient.service.ClaimService;
import tracy.claimnetclient.service.TextService;import java.util.List;@RestController
@RequestMapping("/search")
public class SearchController {@Autowiredprivate TextService textService;@GetMapping("/text/{keyword}")public List<Text> text(@PathVariable("keyword")String keyword,Integer curPage,Integer pageSize) {return textService.text(keyword,curPage,pageSize);}
}
【OK】
三、swagger
参考
依赖
<!-- 引入swagger相关的jar --><dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency>
启动类
类上添加注解@EnableOpenApi
路径匹配配置
application.yml
spring:mvc:pathmatch:matching-strategy: ant_path_matcher
配置类
package tracy.claimnetclient.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.VendorExtension;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;@Configuration
public class SwaggerConfiguration {@Beanpublic Docket docket() {//这里要配置controller包return new Docket(DocumentationType.OAS_30).select().apis(RequestHandlerSelectors.basePackage("tracy.claimnetclient.controller")).paths(PathSelectors.any()).build().apiInfo(setApiInfo());}private ApiInfo setApiInfo() {//作者信息Contact contact = new Contact("tracy","https://blog.csdn.net/Tracycoder?spm=1011.2415.3001.5343","1409568085@qq.com");//项目描述ApiInfo info = new ApiInfo("Claimnet-client Restful Api", "", "v1.0","https://blog.csdn.net/Tracycoder?spm=1011.2415.3001.5343", contact,"Apache 2.0", "", new ArrayList<VendorExtension>());return info;}
}
controller注解
使用类、方法、参数注解:
package tracy.claimnetclient.controller;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tracy.claimnetclient.entity.Claim;
import tracy.claimnetclient.entity.Text;
import tracy.claimnetclient.service.ClaimService;
import tracy.claimnetclient.service.TextService;import java.util.List;@Api(tags = "检索模块")
@RestController
@RequestMapping("/search")
public class SearchController {@Autowiredprivate TextService textService;@Autowiredprivate ClaimService claimService;@ApiOperation(value = "根据id、申请号、内容查询text索引文档", notes = "api/search/text", response = List.class)@GetMapping("/text/{keyword}")public List<Text> text(@ApiParam(value = "关键词", required = true) @PathVariable("keyword")String keyword,@ApiParam(value = "当前页码") Integer curPage,@ApiParam(value = "页大小") Integer pageSize) {return textService.text(keyword,curPage,pageSize);}
}
最后,启动项目,访问http://127.0.0.1:8080/swagger-ui/index.html。
四、redis(代码实现)
依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.5.9</version></dependency>
yml配置
spring:redis:host: ip地址database: 0port: 6379
配置类
package com.yy.myconfig;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** 自定义一个redis template模板*/
@Configuration
public class RedisConfig {@Bean@SuppressWarnings("all")public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {//为了使开发方便,直接使用<String, Object>RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);//Json序列化配置Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);//string的序列化StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();//key采用string的序列化方式template.setKeySerializer(stringRedisSerializer);//hash的key也是用string的序列化方式template.setHashKeySerializer(stringRedisSerializer);//value序列化方式采用jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);//hash的value序列化方式采用jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;}
}
封装redisTamplate
代码来自->
package tracy.client.util;import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.sql.Date;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;@Component
public class RedisUtil {@Resourceprivate RedisTemplate<String, Object> redisTemplate;public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {this.redisTemplate = redisTemplate;}public RedisTemplate<String, Object> getRedisTemplate() {return this.redisTemplate;}/** -------------------key相关操作--------------------- *//*** 删除key** @param key*/public void delete(String key) {redisTemplate.delete(key);}/*** 批量删除key** @param keys*/public void delete(Collection<String> keys) {redisTemplate.delete(keys);}/*** 序列化key** @param key* @return*/public byte[] dump(String key) {return redisTemplate.dump(key);}/*** 是否存在key** @param key* @return*/public Boolean hasKey(String key) {return redisTemplate.hasKey(key);}/*** 设置过期时间** @param key* @param timeout* @param unit* @return*/public Boolean expire(String key, long timeout, TimeUnit unit) {return redisTemplate.expire(key, timeout, unit);}/*** 设置过期时间** @param key* @param date* @return*/public Boolean expireAt(String key, Date date) {return redisTemplate.expireAt(key, date);}/*** 查找匹配的key** @param pattern* @return*/public Set<String> keys(String pattern) {return redisTemplate.keys(pattern);}/*** 将当前数据库的 key 移动到给定的数据库 db 当中** @param key* @param dbIndex* @return*/public Boolean move(String key, int dbIndex) {return redisTemplate.move(key, dbIndex);}/*** 移除 key 的过期时间,key 将持久保持** @param key* @return*/public Boolean persist(String key) {return redisTemplate.persist(key);}/*** 返回 key 的剩余的过期时间** @param key* @param unit* @return*/public Long getExpire(String key, TimeUnit unit) {return redisTemplate.getExpire(key, unit);}/*** 返回 key 的剩余的过期时间** @param key* @return*/public Long getExpire(String key) {return redisTemplate.getExpire(key);}/*** 从当前数据库中随机返回一个 key** @return*/public String randomKey() {return (String) redisTemplate.randomKey();}/*** 修改 key 的名称** @param oldKey* @param newKey*/public void rename(String oldKey, String newKey) {redisTemplate.rename(oldKey, newKey);}/*** 仅当 newkey 不存在时,将 oldKey 改名为 newkey** @param oldKey* @param newKey* @return*/public Boolean renameIfAbsent(String oldKey, String newKey) {return redisTemplate.renameIfAbsent(oldKey, newKey);}/*** 返回 key 所储存的值的类型** @param key* @return*/public DataType type(String key) {return redisTemplate.type(key);}/** -------------------string相关操作--------------------- *//*** 设置指定 key 的值** @param key* @param value*/public void set(String key, String value) {redisTemplate.opsForValue().set(key, value);}/*** 获取指定 key 的值** @param key* @return*/public String get(String key) {return (String) redisTemplate.opsForValue().get(key);}/*** 返回 key 中字符串值的子字符** @param key* @param start* @param end* @return*/public String getRange(String key, long start, long end) {return redisTemplate.opsForValue().get(key, start, end);}/*** 将给定 key 的值设为 value ,并返回 key 的旧值(old value)** @param key* @param value* @return*/public String getAndSet(String key, String value) {return (String) redisTemplate.opsForValue().getAndSet(key, value);}/*** 对 key 所储存的字符串值,获取指定偏移量上的位(bit)** @param key* @param offset* @return*/public Boolean getBit(String key, long offset) {return redisTemplate.opsForValue().getBit(key, offset);}/*** 批量获取** @param keys* @return*/public List<Object> multiGet(Collection<String> keys) {return redisTemplate.opsForValue().multiGet(keys);}/*** 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value** @param key 位置* @param value 值,true为1, false为0* @return*/public boolean setBit(String key, long offset, boolean value) {return redisTemplate.opsForValue().setBit(key, offset, value);}/*** 将值 value 关联到 key ,并将 key 的过期时间设为 timeout** @param key* @param value* @param timeout 过期时间* @param unit 时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES* 秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS*/public void setEx(String key, String value, long timeout, TimeUnit unit) {redisTemplate.opsForValue().set(key, value, timeout, unit);}/*** 只有在 key 不存在时设置 key 的值** @param key* @param value* @return 之前已经存在返回false, 不存在返回true*/public boolean setIfAbsent(String key, String value) {return redisTemplate.opsForValue().setIfAbsent(key, value);}/*** 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始** @param key* @param value* @param offset 从指定位置开始覆写*/public void setRange(String key, String value, long offset) {redisTemplate.opsForValue().set(key, value, offset);}/*** 获取字符串的长度** @param key* @return*/public Long size(String key) {return redisTemplate.opsForValue().size(key);}/*** 批量添加** @param maps*/public void multiSet(Map<String, String> maps) {redisTemplate.opsForValue().multiSet(maps);}/*** 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在** @param maps* @return 之前已经存在返回false, 不存在返回true*/public boolean multiSetIfAbsent(Map<String, String> maps) {return redisTemplate.opsForValue().multiSetIfAbsent(maps);}/*** 增加(自增长), 负数则为自减** @param key* @return*/public Long incrBy(String key, long increment) {return redisTemplate.opsForValue().increment(key, increment);}/*** @param key* @return*/public Double incrByFloat(String key, double increment) {return redisTemplate.opsForValue().increment(key, increment);}/*** 追加到末尾** @param key* @param value* @return*/public Integer append(String key, String value) {return redisTemplate.opsForValue().append(key, value);}/** -------------------hash相关操作------------------------- *//*** 获取存储在哈希表中指定字段的值** @param key* @param field* @return*/public Object hGet(String key, String field) {return redisTemplate.opsForHash().get(key, field);}/*** 获取所有给定字段的值** @param key* @return*/public Map<Object, Object> hGetAll(String key) {return redisTemplate.opsForHash().entries(key);}/*** 获取所有给定字段的值** @param key* @param fields* @return*/public List<Object> hMultiGet(String key, Collection<Object> fields) {return redisTemplate.opsForHash().multiGet(key, fields);}public void hPut(String key, String hashKey, String value) {redisTemplate.opsForHash().put(key, hashKey, value);}public void hPutAll(String key, Map<String, String> maps) {redisTemplate.opsForHash().putAll(key, maps);}/*** 仅当hashKey不存在时才设置** @param key* @param hashKey* @param value* @return*/public Boolean hPutIfAbsent(String key, String hashKey, String value) {return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);}/*** 删除一个或多个哈希表字段** @param key* @param fields* @return*/public Long hDelete(String key, Object... fields) {return redisTemplate.opsForHash().delete(key, fields);}/*** 查看哈希表 key 中,指定的字段是否存在** @param key* @param field* @return*/public boolean hExists(String key, String field) {return redisTemplate.opsForHash().hasKey(key, field);}/*** 为哈希表 key 中的指定字段的整数值加上增量 increment** @param key* @param field* @param increment* @return*/public Long hIncrBy(String key, Object field, long increment) {return redisTemplate.opsForHash().increment(key, field, increment);}/*** 为哈希表 key 中的指定字段的整数值加上增量 increment** @param key* @param field* @param delta* @return*/public Double hIncrByFloat(String key, Object field, double delta) {return redisTemplate.opsForHash().increment(key, field, delta);}/*** 获取所有哈希表中的字段** @param key* @return*/public Set<Object> hKeys(String key) {return redisTemplate.opsForHash().keys(key);}/*** 获取哈希表中字段的数量** @param key* @return*/public Long hSize(String key) {return redisTemplate.opsForHash().size(key);}/*** 获取哈希表中所有值** @param key* @return*/public List<Object> hValues(String key) {return redisTemplate.opsForHash().values(key);}/*** 迭代哈希表中的键值对** @param key* @param options* @return*/public Cursor<Map.Entry<Object, Object>> hScan(String key, ScanOptions options) {return redisTemplate.opsForHash().scan(key, options);}/** ------------------------list相关操作---------------------------- *//*** 通过索引获取列表中的元素** @param key* @param index* @return*/public String lIndex(String key, long index) {return (String) redisTemplate.opsForList().index(key, index);}/*** 获取列表指定范围内的元素** @param key* @param start 开始位置, 0是开始位置* @param end 结束位置, -1返回所有* @return*/public List<Object> lRange(String key, long start, long end) {return redisTemplate.opsForList().range(key, start, end);}/*** 存储在list头部** @param key* @param value* @return*/public Long lLeftPush(String key, String value) {return redisTemplate.opsForList().leftPush(key, value);}/*** @param key* @param value* @return*/public Long lLeftPushAll(String key, String... value) {return redisTemplate.opsForList().leftPushAll(key, value);}/*** @param key* @param value* @return*/public Long lLeftPushAll(String key, Collection<String> value) {return redisTemplate.opsForList().leftPushAll(key, value);}/*** 当list存在的时候才加入** @param key* @param value* @return*/public Long lLeftPushIfPresent(String key, String value) {return redisTemplate.opsForList().leftPushIfPresent(key, value);}/*** 如果pivot存在,再pivot前面添加** @param key* @param pivot* @param value* @return*/public Long lLeftPush(String key, String pivot, String value) {return redisTemplate.opsForList().leftPush(key, pivot, value);}/*** @param key* @param value* @return*/public Long lRightPush(String key, String value) {return redisTemplate.opsForList().rightPush(key, value);}/*** @param key* @param value* @return*/public Long lRightPushAll(String key, String... value) {return redisTemplate.opsForList().rightPushAll(key, value);}/*** @param key* @param value* @return*/public Long lRightPushAll(String key, Collection<String> value) {return redisTemplate.opsForList().rightPushAll(key, value);}/*** 为已存在的列表添加值** @param key* @param value* @return*/public Long lRightPushIfPresent(String key, String value) {return redisTemplate.opsForList().rightPushIfPresent(key, value);}/*** 在pivot元素的右边添加值** @param key* @param pivot* @param value* @return*/public Long lRightPush(String key, String pivot, String value) {return redisTemplate.opsForList().rightPush(key, pivot, value);}/*** 通过索引设置列表元素的值** @param key* @param index 位置* @param value*/public void lSet(String key, long index, String value) {redisTemplate.opsForList().set(key, index, value);}/*** 移出并获取列表的第一个元素** @param key* @return 删除的元素*/public String lLeftPop(String key) {return (String) redisTemplate.opsForList().leftPop(key);}/*** 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止** @param key* @param timeout 等待时间* @param unit 时间单位* @return*/public String lBLeftPop(String key, long timeout, TimeUnit unit) {return (String) redisTemplate.opsForList().leftPop(key, timeout, unit);}/*** 移除并获取列表最后一个元素** @param key* @return 删除的元素*/public String lRightPop(String key) {return (String) redisTemplate.opsForList().rightPop(key);}/*** 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止** @param key* @param timeout 等待时间* @param unit 时间单位* @return*/public String lBRightPop(String key, long timeout, TimeUnit unit) {return (String) redisTemplate.opsForList().rightPop(key, timeout, unit);}/*** 移除列表的最后一个元素,并将该元素添加到另一个列表并返回** @param sourceKey* @param destinationKey* @return*/public String lRightPopAndLeftPush(String sourceKey, String destinationKey) {return (String) redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,destinationKey);}/*** 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止** @param sourceKey* @param destinationKey* @param timeout* @param unit* @return*/public String lBRightPopAndLeftPush(String sourceKey, String destinationKey,long timeout, TimeUnit unit) {return (String) redisTemplate.opsForList().rightPopAndLeftPush(sourceKey,destinationKey, timeout, unit);}/*** 删除集合中值等于value得元素** @param key* @param index index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素;* index<0, 从尾部开始删除第一个值等于value的元素;* @param value* @return*/public Long lRemove(String key, long index, String value) {return redisTemplate.opsForList().remove(key, index, value);}/*** 裁剪list** @param key* @param start* @param end*/public void lTrim(String key, long start, long end) {redisTemplate.opsForList().trim(key, start, end);}/*** 获取列表长度** @param key* @return*/public Long lLen(String key) {return redisTemplate.opsForList().size(key);}/** --------------------set相关操作-------------------------- *//*** set添加元素** @param key* @param values* @return*/public Long sAdd(String key, String... values) {return redisTemplate.opsForSet().add(key, values);}/*** set移除元素** @param key* @param values* @return*/public Long sRemove(String key, Object... values) {return redisTemplate.opsForSet().remove(key, values);}/*** 移除并返回集合的一个随机元素** @param key* @return*/public String sPop(String key) {return (String) redisTemplate.opsForSet().pop(key);}/*** 将元素value从一个集合移到另一个集合** @param key* @param value* @param destKey* @return*/public Boolean sMove(String key, String value, String destKey) {return redisTemplate.opsForSet().move(key, value, destKey);}/*** 获取集合的大小** @param key* @return*/public Long sSize(String key) {return redisTemplate.opsForSet().size(key);}/*** 判断集合是否包含value** @param key* @param value* @return*/public Boolean sIsMember(String key, Object value) {return redisTemplate.opsForSet().isMember(key, value);}/*** 获取两个集合的交集** @param key* @param otherKey* @return*/public Set<Object> sIntersect(String key, String otherKey) {return redisTemplate.opsForSet().intersect(key, otherKey);}/*** 获取key集合与多个集合的交集** @param key* @param otherKeys* @return*/public Set<Object> sIntersect(String key, Collection<String> otherKeys) {return redisTemplate.opsForSet().intersect(key, otherKeys);}/*** key集合与otherKey集合的交集存储到destKey集合中** @param key* @param otherKey* @param destKey* @return*/public Long sIntersectAndStore(String key, String otherKey, String destKey) {return redisTemplate.opsForSet().intersectAndStore(key, otherKey,destKey);}/*** key集合与多个集合的交集存储到destKey集合中** @param key* @param otherKeys* @param destKey* @return*/public Long sIntersectAndStore(String key, Collection<String> otherKeys,String destKey) {return redisTemplate.opsForSet().intersectAndStore(key, otherKeys,destKey);}/*** 获取两个集合的并集** @param key* @param otherKeys* @return*/public Set<Object> sUnion(String key, String otherKeys) {return redisTemplate.opsForSet().union(key, otherKeys);}/*** 获取key集合与多个集合的并集** @param key* @param otherKeys* @return*/public Set<Object> sUnion(String key, Collection<String> otherKeys) {return redisTemplate.opsForSet().union(key, otherKeys);}/*** key集合与otherKey集合的并集存储到destKey中** @param key* @param otherKey* @param destKey* @return*/public Long sUnionAndStore(String key, String otherKey, String destKey) {return redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey);}/*** key集合与多个集合的并集存储到destKey中** @param key* @param otherKeys* @param destKey* @return*/public Long sUnionAndStore(String key, Collection<String> otherKeys,String destKey) {return redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey);}/*** 获取两个集合的差集** @param key* @param otherKey* @return*/public Set<Object> sDifference(String key, String otherKey) {return redisTemplate.opsForSet().difference(key, otherKey);}/*** 获取key集合与多个集合的差集** @param key* @param otherKeys* @return*/public Set<Object> sDifference(String key, Collection<String> otherKeys) {return redisTemplate.opsForSet().difference(key, otherKeys);}/*** key集合与otherKey集合的差集存储到destKey中** @param key* @param otherKey* @param destKey* @return*/public Long sDifference(String key, String otherKey, String destKey) {return redisTemplate.opsForSet().differenceAndStore(key, otherKey,destKey);}/*** key集合与多个集合的差集存储到destKey中** @param key* @param otherKeys* @param destKey* @return*/public Long sDifference(String key, Collection<String> otherKeys,String destKey) {return redisTemplate.opsForSet().differenceAndStore(key, otherKeys,destKey);}/*** 获取集合所有元素** @param key* @return*/public Set<Object> setMembers(String key) {return redisTemplate.opsForSet().members(key);}/*** 随机获取集合中的一个元素** @param key* @return*/public String sRandomMember(String key) {return (String) redisTemplate.opsForSet().randomMember(key);}/*** 随机获取集合中count个元素** @param key* @param count* @return*/public List<Object> sRandomMembers(String key, long count) {return redisTemplate.opsForSet().randomMembers(key, count);}/*** 随机获取集合中count个元素并且去除重复的** @param key* @param count* @return*/public Set<Object> sDistinctRandomMembers(String key, long count) {return redisTemplate.opsForSet().distinctRandomMembers(key, count);}/*** @param key* @param options* @return*/public Cursor<Object> sScan(String key, ScanOptions options) {return redisTemplate.opsForSet().scan(key, options);}/**------------------zSet相关操作--------------------------------*//*** 添加元素,有序集合是按照元素的score值由小到大排列** @param key* @param value* @param score* @return*/public Boolean zAdd(String key, String value, double score) {return redisTemplate.opsForZSet().add(key, value, score);}/*** @param key* @param values* @return*/public Long zAdd(String key, Set<ZSetOperations.TypedTuple<Object>> values) {return redisTemplate.opsForZSet().add(key, values);}/*** @param key* @param values* @return*/public Long zRemove(String key, Object... values) {return redisTemplate.opsForZSet().remove(key, values);}/*** 增加元素的score值,并返回增加后的值** @param key* @param value* @param delta* @return*/public Double zIncrementScore(String key, String value, double delta) {return redisTemplate.opsForZSet().incrementScore(key, value, delta);}/*** 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列** @param key* @param value* @return 0表示第一位*/public Long zRank(String key, Object value) {return redisTemplate.opsForZSet().rank(key, value);}/*** 返回元素在集合的排名,按元素的score值由大到小排列** @param key* @param value* @return*/public Long zReverseRank(String key, Object value) {return redisTemplate.opsForZSet().reverseRank(key, value);}/*** 获取集合的元素, 从小到大排序** @param key* @param start 开始位置* @param end 结束位置, -1查询所有* @return*/public Set<Object> zRange(String key, long start, long end) {return redisTemplate.opsForZSet().range(key, start, end);}/*** 获取集合元素, 并且把score值也获取** @param key* @param start* @param end* @return*/public Set<ZSetOperations.TypedTuple<Object>> zRangeWithScores(String key, long start,long end) {return redisTemplate.opsForZSet().rangeWithScores(key, start, end);}/*** 根据Score值查询集合元素** @param key* @param min 最小值* @param max 最大值* @return*/public Set<Object> zRangeByScore(String key, double min, double max) {return redisTemplate.opsForZSet().rangeByScore(key, min, max);}/*** 根据Score值查询集合元素, 从小到大排序** @param key* @param min 最小值* @param max 最大值* @return*/public Set<ZSetOperations.TypedTuple<Object>> zRangeByScoreWithScores(String key,double min, double max) {return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max);}/*** @param key* @param min* @param max* @param start* @param end* @return*/public Set<ZSetOperations.TypedTuple<Object>> zRangeByScoreWithScores(String key,double min, double max, long start, long end) {return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max,start, end);}/*** 获取集合的元素, 从大到小排序** @param key* @param start* @param end* @return*/public Set<Object> zReverseRange(String key, long start, long end) {return redisTemplate.opsForZSet().reverseRange(key, start, end);}/*** 获取集合的元素, 从大到小排序, 并返回score值** @param key* @param start* @param end* @return*/public Set<ZSetOperations.TypedTuple<Object>> zReverseRangeWithScores(String key,long start, long end) {return redisTemplate.opsForZSet().reverseRangeWithScores(key, start,end);}/*** 根据Score值查询集合元素, 从大到小排序** @param key* @param min* @param max* @return*/public Set<Object> zReverseRangeByScore(String key, double min,double max) {return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max);}/*** 根据Score值查询集合元素, 从大到小排序** @param key* @param min* @param max* @return*/public Set<ZSetOperations.TypedTuple<Object>> zReverseRangeByScoreWithScores(String key, double min, double max) {return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key,min, max);}/*** @param key* @param min* @param max* @param start* @param end* @return*/public Set<Object> zReverseRangeByScore(String key, double min,double max, long start, long end) {return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max,start, end);}/*** 根据score值获取集合元素数量** @param key* @param min* @param max* @return*/public Long zCount(String key, double min, double max) {return redisTemplate.opsForZSet().count(key, min, max);}/*** 获取集合大小** @param key* @return*/public Long zSize(String key) {return redisTemplate.opsForZSet().size(key);}/*** 获取集合大小** @param key* @return*/public Long zZCard(String key) {return redisTemplate.opsForZSet().zCard(key);}/*** 获取集合中value元素的score值** @param key* @param value* @return*/public Double zScore(String key, Object value) {return redisTemplate.opsForZSet().score(key, value);}/*** 移除指定索引位置的成员** @param key* @param start* @param end* @return*/public Long zRemoveRange(String key, long start, long end) {return redisTemplate.opsForZSet().removeRange(key, start, end);}/*** 根据指定的score值的范围来移除成员** @param key* @param min* @param max* @return*/public Long zRemoveRangeByScore(String key, double min, double max) {return redisTemplate.opsForZSet().removeRangeByScore(key, min, max);}/*** 获取key和otherKey的并集并存储在destKey中** @param key* @param otherKey* @param destKey* @return*/public Long zUnionAndStore(String key, String otherKey, String destKey) {return redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey);}/*** @param key* @param otherKeys* @param destKey* @return*/public Long zUnionAndStore(String key, Collection<String> otherKeys,String destKey) {return redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey);}/*** 交集** @param key* @param otherKey* @param destKey* @return*/public Long zIntersectAndStore(String key, String otherKey,String destKey) {return redisTemplate.opsForZSet().intersectAndStore(key, otherKey,destKey);}/*** 交集** @param key* @param otherKeys* @param destKey* @return*/public Long zIntersectAndStore(String key, Collection<String> otherKeys,String destKey) {return redisTemplate.opsForZSet().intersectAndStore(key, otherKeys,destKey);}/*** @param key* @param options* @return*/public Cursor<ZSetOperations.TypedTuple<Object>> zScan(String key, ScanOptions options) {return redisTemplate.opsForZSet().scan(key, options);}}
五、rabbitMQ
以实现路由模式为例。
依赖
<!-- rabbitMQ--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><!-- json工具--><dependency><groupId>org.json</groupId><artifactId>json</artifactId><version>20211205</version></dependency><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.9.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.1</version></dependency>
yml配置
spring:application:name: Spring-boot-rabbitmqrabbitmq:host: rabbitmq的ip地址port: 5673username: guestpassword: guestlistener:simple:# 表示消费者消费成功消息以后需要手工的进行签收(ack确认),默认为 autoacknowledge-mode: manual# 发送者开启 return 确认机制publisher-returns: true# 发送者开启 confirm 确认机制publisher-confirm-type: correlate
配置类
package tracy.manage.config;import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class RabbitMQConfig {public static final String EXCHANGE_NAME = "direct-exchange";public static final String TEXT_QUEUE = "text-queue";public static final String CLAIM_QUEUE = "claim-queue";public static final String TEXT_RKEY = "text";public static final String CLAIM_RKEY = "claim";@Value("${spring.rabbitmq.host}")private String host;@Value("${spring.rabbitmq.port}")private int port;@Value("${spring.rabbitmq.username}")private String username;@Value("${spring.rabbitmq.password}")private String password;/*** 1.声明交换机*/@Beanpublic DirectExchange directExchange() {/*** 参数说明:* 1. 交换机名称* 2. 是否持久化 true:持久化,交换机一直保留 false:不持久化,用完就删除* 3. 是否自动删除 false:不自动删除 true:自动删除*/return new DirectExchange(EXCHANGE_NAME, true, false);}/*** 2.声明队列*/@Beanpublic Queue textQueue() {/*** Queue构造函数参数说明* 1. 队列名* 2. 是否持久化 true:持久化 false:不持久化*/return new Queue(TEXT_QUEUE, true);}@Beanpublic Queue claimQueue() {/*** Queue构造函数参数说明* 1. 队列名* 2. 是否持久化 true:持久化 false:不持久化*/return new Queue(CLAIM_QUEUE, true);}/*** 3.队列与交换机绑定*/@Beanpublic Binding textBinding() {return BindingBuilder.bind(textQueue()).to(directExchange()).with(TEXT_RKEY);}@Beanpublic Binding claimBinding() {return BindingBuilder.bind(claimQueue()).to(directExchange()).with(CLAIM_RKEY);}/*** 4.声明连接工厂*/@Beanpublic ConnectionFactory connectionFactory() {CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host,port);connectionFactory.setUsername(username);connectionFactory.setPassword(password);return connectionFactory;}/*** 5.将自定义的RabbitTemplate对象注入bean容器*/@Beanpublic RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory) {RabbitTemplate rabbitTemplate = new RabbitTemplate();rabbitTemplate.setConnectionFactory(connectionFactory);//设置开启消息推送结果回调rabbitTemplate.setMandatory(true);//设置ConfirmCallback回调rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {@Overridepublic void confirm(CorrelationData correlationData, boolean ack, String cause) {//这部分没写,先空在这里}});//设置ReturnCallback回调rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {@Overridepublic void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {//这部分没写,先空在这里}});return rabbitTemplate;}}
生产者代码
package tracy.manage.mq;import org.json.JSONObject;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;@Service
public class Producer {public static final String EXCHANGE_NAME = "direct-exchange";public static final String TEXT_RKEY = "text";public static final String CLAIM_RKEY = "claim";@Autowiredprivate RabbitTemplate rabbitTemplate;public void send() {HashMap<String,String> map1=new HashMap<>();HashMap<String,String> map2=new HashMap<>();map1.put("message","text test");map2.put("message","claim test");String message1=new JSONObject(map1).toString();String message2=new JSONObject(map2).toString();rabbitTemplate.convertAndSend(EXCHANGE_NAME,TEXT_RKEY ,message1);rabbitTemplate.convertAndSend(EXCHANGE_NAME,CLAIM_RKEY,message2);}
}
消费者代码
我设置了两个消费者:
package tracy.manage.mq;import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;import java.io.IOException;@Service
@RabbitListener(queues = {"text-queue"}) //监听队列
public class TextConsumer {@RabbitHandlerpublic void receive(String msg, Channel channel, Message message) throws IOException {try {System.out.println("text consumer接收到消息:"+ msg);//消费确认channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {if (message.getMessageProperties().getRedelivered()) {//basicReject: 拒绝消息,与basicNack区别在于不能进行批量操作,其他用法很相似 false表示消息不再重新进入队列channel.basicReject(message.getMessageProperties().getDeliveryTag(), false); // 拒绝消息} else {// basicNack:表示失败确认,一般在消费消息业务异常时用到此方法,可以将消息重新投递入队列channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);}}}}
package tracy.manage.mq;import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;import java.io.IOException;@Service
@RabbitListener(queues = {"claim-queue"}) //监听队列
public class ClaimConsumer {@RabbitHandlerpublic void receive(String msg, Channel channel, Message message) throws IOException {try {System.out.println("claim consumer接收到消息:"+ msg);//消费确认channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);} catch (Exception e) {if (message.getMessageProperties().getRedelivered()) {//basicReject: 拒绝消息,与basicNack区别在于不能进行批量操作,其他用法很相似 false表示消息不再重新进入队列channel.basicReject(message.getMessageProperties().getDeliveryTag(), false); // 拒绝消息} else {// basicNack:表示失败确认,一般在消费消息业务异常时用到此方法,可以将消息重新投递入队列channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);}}}}
测试一下
在测试类中运行以下方法:
@Testvoid testProducer() {producer.send();}
成功!
相关文章:

Spring boot 实战指南(三):配置事务,整合Elasticsearch、swagger、redis、rabbitMQ
文章目录一、配置事务依赖使用注解二、Elasticsearch创建项目配置maven完善依赖es连接配置实体映射repositoryservicecontroller三、swagger依赖启动类路径匹配配置配置类controller注解四、redis(代码实现)依赖yml配置配置类封装redisTamplate五、rabbi…...

九、Bean的循环依赖问题
1 什么是Bean的循环依赖 A对象中有B属性。B对象中有A属性。这就是循环依赖。我依赖你,你也依赖我。 比如:丈夫类Husband,妻子类Wife。Husband中有Wife的引用。Wife中有Husband的引用。 2 singleton下的set注入产生的循环依赖 丈夫类 pac…...
macOS关闭SIP后,仍无法修改/usr文件夹下文件
发现问题 MacOS 升级到Big Sur后,删除多余的python3文件,发现写不到磁盘,会报OSError: [Errno 30] Read-only file system的错误。经过了解,在Mac OS10.11 之后,苹果公司为了提高系统环境安全,引入了一个内…...

【编程基础之Python】8、Python复合数据类型
【编程基础之Python】8、Python复合数据类型Python复合数据类型列表(List)创建列表访问元素内置方法列表操作元组(Tuple)创建元组访问元素集合(Set)创建集合基本操作其他操作字典(Dictionary&am…...

自动驾驶决策规划-控制方向学习资料总结(附相关资料的链接)
项目仓库 欢迎访问我的Github主页 项目名称说明chhCpp学习C仓库chhRobotics学习自动驾驶、控制理论相关仓库(python实现)chhRobotics_CPP学习自动驾驶、控制理论相关仓库(c实现)chhML 、chh-MachineLearning学习机器学习仓库chhRL学习强化学习仓库chhTricks存放一些有意思的t…...
网络安全岗位介绍——售前工程师
一、工作内容 1、独立完成并配合销售人员引导客户完成方案设计、产品选型、配置报价和能为客户提供安全咨询与方案优化等服务; 2、作为售前工程师,跟踪整个项目的进展,和销售进行配合,协调公司各种资源完成项目中标; 3、编写投标文件的技术…...

nodejs安装和卸载超详细步骤
安装程序①下载完成后,双击安装包,开始安装,使用默认配置安装一直点next即可,安装路径默认在C:\Program Files下,也可以自定义修改②安装路径默认在C:\Program Files下面,也能够自定义修改,而后…...

【Leetcode】移除链表元素 链表的中间节点 链表中倒数第k个节点
目录 一.【Leetcode203】移除链表元素 1.链接 2.题目再现 A.双指针法 B.类尾删法 C.哨兵位 二.【Leetcode876】链表的中间节点 1.链接:链表的中间节点 2.题目再现 3.解法:快慢指针 三.链表中倒数第k个节点 1.链接:链表中倒数第k个…...

快速上手配置firewalld
firewalld使用firewall-cmd命令配置策略。 查看当前firewalld当前服务运行状态 firewall-cmd --state firewalld防火墙状态还用使用如下命令查看状态 systemctl status firewalld 查看所有打开运行的端口 firewall-cmd --zonepublic --list-ports 查看区域信息情况 firewall…...
treap使用mt19937会导致问题原因分析
Treap 是一种使用随机数生成器来维护树形结构的数据结构,而 mt19937 是一种常用的伪随机数生成器。虽然 mt19937 可以生成高质量的随机数序列,但是在 Treap 中使用它可能会导致一些问题。 mt19937 返回的是一个 unsigned int 其中一个问题是࿰…...
tmux和vim
tmux 作用 分屏 允许断开Terminal连接后继续运行进程 结构 一个tmux可以开一堆session tmux: session 1, session 2, session 3 … Session: window 1, window 2, window 3… Window: pane 1, pane 2, pane 3… pane是最小单位,用shell语言编程 操作 输入…...
2023年全国最新保安员精选真题及答案12
百分百题库提供保安员考试试题、保安职业资格考试预测题、保安员考试真题、保安职业资格证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 121.《保安员证》是经由设区的()单位进行发放。 A:市级人民政…...

Hbase的基本概念与架构
一、Hbase的概念 HBase是Hadoop的生态系统,是建立在Hadoop文件系统(HDFS)之上的分布式、面向列的数据库,通过利用Hadoop的文件系统提供容错能力。如果你需要进行实时读写或者随机访问大规模的数据集的时候,请考虑使用H…...

颠覆你的认知,业务同事都能开发软件,我简直无地自容……
经常看到网络鼓吹业务人员也能搭建应用,本是嗤之以鼻、半信半疑,但当这件事真实发生在自己身上时,竟觉得此言不虚? 一、背景 最近公司为了集成系统、提升扩展能力,引进了低代码平台JNPF,说个题外话&#…...

01 | n2n虚拟局域网
1 n2n简介 为了满足两个不同局域网的机器进行通信,让不同网段的机器能够进行P2P( 点对点 peer-to-peer ) 通信。2 n2n源码 https://github.com/ntop/n2n.git3 n2n名词 3.1 SuperNode 超级节点 SuperNode 相当与注册中心, 它会记录边缘节点的连接信息,…...

MFC界面控件BCGControlBar v33.4 - 支持Win 11 Mica material主题
BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中,并为您节省数百个开发和调试时间。BCGControlBar专业版和BCGSuite for MFC v33.4已正式发布了,该版本包含了对Windows 11 Mica materia…...

手把手教你用js实现手机通讯录功能(附源码)
js实现手机通讯录效果图需求需求一:锚点通过#id配合a标签使用css中scroll-behavior属性的使用需求二需求三获取汉字拼音的首字母方法1:使用插件,这里推荐pinyin-pro方法2:使用unicode去重数组中冗余的对象法一:用Map去…...

【C/C++】逗号表达式、算术运算符优先级
一、逗号表达式 1、如下图中代码,为变量d赋值,d的值为逗号表达式中的哪一个呢? 运行结果:d的值为6 2、再举个例子 运行结果:d的结果还是6 3、再举个例子 运行结果 以上面三种不同的逗号表达式为例,…...
携禾生物面试总结
面试时间: 2022年2月3日 1.项目C11的特性具体有用到哪些? 智能指针 lambda表达式 auto unordered_map 2.智能指针用到了哪几种智能指针 3.shared_ptr和weak_ptr区别 4.多线程实现方式 prosix线程》pthread windows的_beginthreaex MFC多线程 ACEM中…...

FPGA纯verilog手写HDMI发送IP 提供源码和技术支持
目录1、前言2、设计思路和框架TMDS 编码算法OSERDESE串并转换3、顶层源码和IP封装4、源码和IP获取1、前言 本设计使用Xilinx原语和自己手写的代码实现了HDMI发送功能,纯verilog手写,有源码,也提供封装好的IP,你喜欢用例化的方式就…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...