Commit d91374865fb33ea96a5ec6c30c9a9b2d04d5d29f
1 parent
97b0ec46
day11-物流信息微服务
Showing
12 changed files
with
457 additions
and
2 deletions
sl-express-ms-transport-info-service/pom.xml
| @@ -49,6 +49,10 @@ | @@ -49,6 +49,10 @@ | ||
| 49 | <artifactId>spring-boot-starter-web</artifactId> | 49 | <artifactId>spring-boot-starter-web</artifactId> |
| 50 | </dependency> | 50 | </dependency> |
| 51 | <dependency> | 51 | <dependency> |
| 52 | + <groupId>org.redisson</groupId> | ||
| 53 | + <artifactId>redisson</artifactId> | ||
| 54 | + </dependency> | ||
| 55 | + <dependency> | ||
| 52 | <groupId>com.alibaba.cloud</groupId> | 56 | <groupId>com.alibaba.cloud</groupId> |
| 53 | <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> | 57 | <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> |
| 54 | </dependency> | 58 | </dependency> |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/config/BloomFilterConfig.java
0 → 100644
| 1 | +package com.sl.transport.info.config; | ||
| 2 | + | ||
| 3 | +import lombok.Getter; | ||
| 4 | +import org.springframework.beans.factory.annotation.Value; | ||
| 5 | +import org.springframework.context.annotation.Configuration; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 布隆过滤器相关配置 | ||
| 9 | + */ | ||
| 10 | +@Getter | ||
| 11 | +@Configuration | ||
| 12 | +public class BloomFilterConfig { | ||
| 13 | + | ||
| 14 | + /** | ||
| 15 | + * 名称,默认:sl-bloom-filter | ||
| 16 | + */ | ||
| 17 | + @Value("${bloom.name:sl-bloom-filter}") | ||
| 18 | + private String name; | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 布隆过滤器长度,最大支持Integer.MAX_VALUE*2,即:4294967294,默认:1千万 | ||
| 22 | + */ | ||
| 23 | + @Value("${bloom.expectedInsertions:10000000}") | ||
| 24 | + private long expectedInsertions; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 误判率,默认:0.05 | ||
| 28 | + */ | ||
| 29 | + @Value("${bloom.falseProbability:0.05d}") | ||
| 30 | + private double falseProbability; | ||
| 31 | + | ||
| 32 | +} |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/config/CaffeineConfig.java
0 → 100644
| 1 | +package com.sl.transport.info.config; | ||
| 2 | + | ||
| 3 | +import com.github.benmanes.caffeine.cache.Cache; | ||
| 4 | +import com.github.benmanes.caffeine.cache.Caffeine; | ||
| 5 | +import com.sl.transport.info.domain.TransportInfoDTO; | ||
| 6 | +import org.springframework.beans.factory.annotation.Value; | ||
| 7 | +import org.springframework.context.annotation.Bean; | ||
| 8 | +import org.springframework.context.annotation.Configuration; | ||
| 9 | + | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * Caffeine缓存配置 | ||
| 13 | + */ | ||
| 14 | +@Configuration | ||
| 15 | +public class CaffeineConfig { | ||
| 16 | + | ||
| 17 | + @Value("${caffeine.init}") | ||
| 18 | + private Integer init; | ||
| 19 | + | ||
| 20 | + @Value("${caffeine.max}") | ||
| 21 | + private Integer max; | ||
| 22 | + | ||
| 23 | + @Bean | ||
| 24 | + public Cache<String, TransportInfoDTO> transportInfoCache() { | ||
| 25 | + return Caffeine.newBuilder() | ||
| 26 | + .initialCapacity(init) | ||
| 27 | + .maximumSize(max) | ||
| 28 | + .build(); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | +} |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/config/MyRedisCacheManager.java
0 → 100644
| 1 | +package com.sl.transport.info.config; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.ObjectUtil; | ||
| 4 | +import cn.hutool.core.util.RandomUtil; | ||
| 5 | +import org.springframework.data.redis.cache.RedisCache; | ||
| 6 | +import org.springframework.data.redis.cache.RedisCacheConfiguration; | ||
| 7 | +import org.springframework.data.redis.cache.RedisCacheManager; | ||
| 8 | +import org.springframework.data.redis.cache.RedisCacheWriter; | ||
| 9 | + | ||
| 10 | +import java.time.Duration; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * 自定义CacheManager,用于设置不同的过期时间,防止雪崩问题的发生 | ||
| 14 | + */ | ||
| 15 | +public class MyRedisCacheManager extends RedisCacheManager { | ||
| 16 | + | ||
| 17 | + public MyRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { | ||
| 18 | + super(cacheWriter, defaultCacheConfiguration); | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + @Override | ||
| 22 | + protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) { | ||
| 23 | + //获取到原有过期时间 | ||
| 24 | + Duration duration = cacheConfig.getTtl(); | ||
| 25 | + if (ObjectUtil.isNotEmpty(duration)) { | ||
| 26 | + //在原有时间上随机增加1~10分钟 | ||
| 27 | + Duration newDuration = duration.plusMinutes(RandomUtil.randomInt(1, 11)); | ||
| 28 | + cacheConfig = cacheConfig.entryTtl(newDuration); | ||
| 29 | + } | ||
| 30 | + return super.createRedisCache(name, cacheConfig); | ||
| 31 | + } | ||
| 32 | +} |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/config/RedisConfig.java
0 → 100644
| 1 | +package com.sl.transport.info.config; | ||
| 2 | + | ||
| 3 | +import io.lettuce.core.dynamic.RedisCommandFactory; | ||
| 4 | +import org.springframework.beans.factory.annotation.Value; | ||
| 5 | +import org.springframework.context.annotation.Bean; | ||
| 6 | +import org.springframework.context.annotation.Configuration; | ||
| 7 | +import org.springframework.data.redis.cache.RedisCacheConfiguration; | ||
| 8 | +import org.springframework.data.redis.cache.RedisCacheManager; | ||
| 9 | +import org.springframework.data.redis.cache.RedisCacheWriter; | ||
| 10 | +import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
| 11 | +import org.springframework.data.redis.core.RedisTemplate; | ||
| 12 | +import org.springframework.data.redis.listener.ChannelTopic; | ||
| 13 | +import org.springframework.data.redis.listener.RedisMessageListenerContainer; | ||
| 14 | +import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; | ||
| 15 | +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; | ||
| 16 | +import org.springframework.data.redis.serializer.RedisSerializationContext; | ||
| 17 | +import org.springframework.data.redis.serializer.StringRedisSerializer; | ||
| 18 | + | ||
| 19 | +import java.time.Duration; | ||
| 20 | + | ||
| 21 | +@Configuration | ||
| 22 | +public class RedisConfig { | ||
| 23 | + | ||
| 24 | + public static final String CHANNEL_TOPIC = "sl-express-ms-transport-info-caffeine"; | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * 存储的默认有效期时间,单位:小时 | ||
| 28 | + */ | ||
| 29 | + @Value("${redis.ttl:1}") | ||
| 30 | + private Integer redisTtl; | ||
| 31 | + | ||
| 32 | + @Bean | ||
| 33 | + public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) { | ||
| 34 | + // 默认配置 | ||
| 35 | + RedisCacheConfiguration defaultCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() | ||
| 36 | + // 设置key的序列化方式为字符串 | ||
| 37 | + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) | ||
| 38 | + // 设置value的序列化方式为json格式 | ||
| 39 | + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) | ||
| 40 | + .disableCachingNullValues() // 不缓存null | ||
| 41 | + .entryTtl(Duration.ofHours(redisTtl)); // 默认缓存数据保存1小时 | ||
| 42 | + | ||
| 43 | + // 构redis缓存管理器 | ||
| 44 | +// RedisCacheManager redisCacheManager = RedisCacheManager.RedisCacheManagerBuilder | ||
| 45 | +// .fromConnectionFactory(redisTemplate.getConnectionFactory()) | ||
| 46 | +// .cacheDefaults(defaultCacheConfiguration) | ||
| 47 | +// .transactionAware() // 只在事务成功提交后才会进行缓存的put/evict操作 | ||
| 48 | +// .build(); | ||
| 49 | + | ||
| 50 | + RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory()); | ||
| 51 | + MyRedisCacheManager myRedisCacheManager = new MyRedisCacheManager(redisCacheWriter, defaultCacheConfiguration); | ||
| 52 | + myRedisCacheManager.setTransactionAware(true); | ||
| 53 | + return myRedisCacheManager; | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * 配置订阅,用于解决Caffeine一致性的问题 | ||
| 58 | + * | ||
| 59 | + * @param redisCommandFactory 链接工厂 | ||
| 60 | + * @param messageListenerAdapter 消息监听器 | ||
| 61 | + * @return 消息监听容器 | ||
| 62 | + */ | ||
| 63 | + @Bean | ||
| 64 | + public RedisMessageListenerContainer container( | ||
| 65 | + RedisConnectionFactory redisCommandFactory, | ||
| 66 | + MessageListenerAdapter messageListenerAdapter | ||
| 67 | + ) { | ||
| 68 | + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); | ||
| 69 | + container.setConnectionFactory(redisCommandFactory); | ||
| 70 | + container.addMessageListener(messageListenerAdapter, new ChannelTopic(CHANNEL_TOPIC)); | ||
| 71 | + return container; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + | ||
| 75 | +} |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/config/RedissonConfiguration.java
0 → 100644
| 1 | +package com.sl.transport.info.config; | ||
| 2 | + | ||
| 3 | + | ||
| 4 | +import cn.hutool.core.convert.Convert; | ||
| 5 | +import cn.hutool.core.util.StrUtil; | ||
| 6 | +import org.redisson.Redisson; | ||
| 7 | +import org.redisson.api.RedissonClient; | ||
| 8 | +import org.redisson.config.Config; | ||
| 9 | +import org.redisson.config.SingleServerConfig; | ||
| 10 | +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; | ||
| 11 | +import org.springframework.context.annotation.Bean; | ||
| 12 | +import org.springframework.context.annotation.Configuration; | ||
| 13 | + | ||
| 14 | +import javax.annotation.Resource; | ||
| 15 | + | ||
| 16 | +@Configuration | ||
| 17 | +public class RedissonConfiguration { | ||
| 18 | + | ||
| 19 | + @Resource | ||
| 20 | + private RedisProperties redisProperties; | ||
| 21 | + | ||
| 22 | + @Bean | ||
| 23 | + public RedissonClient redissonSingle() { | ||
| 24 | + Config config = new Config(); | ||
| 25 | + SingleServerConfig serverConfig = config.useSingleServer() | ||
| 26 | + .setAddress("redis://" + redisProperties.getHost() + ":" + redisProperties.getPort()); | ||
| 27 | + if (null != (redisProperties.getTimeout())) { | ||
| 28 | + serverConfig.setTimeout(1000 * Convert.toInt(redisProperties.getTimeout().getSeconds())); | ||
| 29 | + } | ||
| 30 | + if (StrUtil.isNotEmpty(redisProperties.getPassword())) { | ||
| 31 | + serverConfig.setPassword(redisProperties.getPassword()); | ||
| 32 | + } | ||
| 33 | + return Redisson.create(config); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | +} |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/controller/TransportInfoController.java
| 1 | package com.sl.transport.info.controller; | 1 | package com.sl.transport.info.controller; |
| 2 | 2 | ||
| 3 | +import com.github.benmanes.caffeine.cache.Cache; | ||
| 3 | import com.sl.transport.common.exception.SLException; | 4 | import com.sl.transport.common.exception.SLException; |
| 4 | import com.sl.transport.common.util.BeanUtil; | 5 | import com.sl.transport.common.util.BeanUtil; |
| 5 | import com.sl.transport.common.util.ObjectUtil; | 6 | import com.sl.transport.common.util.ObjectUtil; |
| 7 | +import com.sl.transport.info.config.CaffeineConfig; | ||
| 6 | import com.sl.transport.info.domain.TransportInfoDTO; | 8 | import com.sl.transport.info.domain.TransportInfoDTO; |
| 7 | import com.sl.transport.info.entity.TransportInfoEntity; | 9 | import com.sl.transport.info.entity.TransportInfoEntity; |
| 8 | import com.sl.transport.info.enums.ExceptionEnum; | 10 | import com.sl.transport.info.enums.ExceptionEnum; |
| 11 | +import com.sl.transport.info.service.BloomFilterService; | ||
| 9 | import com.sl.transport.info.service.TransportInfoService; | 12 | import com.sl.transport.info.service.TransportInfoService; |
| 10 | import io.swagger.annotations.Api; | 13 | import io.swagger.annotations.Api; |
| 11 | import io.swagger.annotations.ApiImplicitParam; | 14 | import io.swagger.annotations.ApiImplicitParam; |
| 12 | import io.swagger.annotations.ApiImplicitParams; | 15 | import io.swagger.annotations.ApiImplicitParams; |
| 13 | import io.swagger.annotations.ApiOperation; | 16 | import io.swagger.annotations.ApiOperation; |
| 17 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 14 | import org.springframework.web.bind.annotation.GetMapping; | 18 | import org.springframework.web.bind.annotation.GetMapping; |
| 15 | import org.springframework.web.bind.annotation.PathVariable; | 19 | import org.springframework.web.bind.annotation.PathVariable; |
| 16 | import org.springframework.web.bind.annotation.RequestMapping; | 20 | import org.springframework.web.bind.annotation.RequestMapping; |
| @@ -26,6 +30,12 @@ public class TransportInfoController { | @@ -26,6 +30,12 @@ public class TransportInfoController { | ||
| 26 | @Resource | 30 | @Resource |
| 27 | private TransportInfoService transportInfoService; | 31 | private TransportInfoService transportInfoService; |
| 28 | 32 | ||
| 33 | + @Resource | ||
| 34 | + public Cache<String, TransportInfoDTO> transportInfoCache; | ||
| 35 | + | ||
| 36 | + @Autowired | ||
| 37 | + private BloomFilterService bloomFilterService; | ||
| 38 | + | ||
| 29 | /** | 39 | /** |
| 30 | * 根据运单id查询运单信息 | 40 | * 根据运单id查询运单信息 |
| 31 | * | 41 | * |
| @@ -38,10 +48,23 @@ public class TransportInfoController { | @@ -38,10 +48,23 @@ public class TransportInfoController { | ||
| 38 | @ApiOperation(value = "查询", notes = "根据运单id查询物流信息") | 48 | @ApiOperation(value = "查询", notes = "根据运单id查询物流信息") |
| 39 | @GetMapping("{transportOrderId}") | 49 | @GetMapping("{transportOrderId}") |
| 40 | public TransportInfoDTO queryByTransportOrderId(@PathVariable("transportOrderId") String transportOrderId) { | 50 | public TransportInfoDTO queryByTransportOrderId(@PathVariable("transportOrderId") String transportOrderId) { |
| 41 | - TransportInfoEntity transportInfoEntity = transportInfoService.queryByTransportOrderId(transportOrderId); | ||
| 42 | - if (ObjectUtil.isNotEmpty(transportInfoEntity)) { | 51 | +// 如果布隆过滤器中不存在,无需缓存命中,直接返回即可 |
| 52 | + boolean contains = bloomFilterService.contains(transportOrderId); | ||
| 53 | + if (!contains) { | ||
| 54 | + throw new SLException(ExceptionEnum.NOT_FOUND); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + TransportInfoDTO transportInfoDTO = transportInfoCache.get(transportOrderId, s -> { | ||
| 58 | +// 未命中,查询MongoMD | ||
| 59 | + TransportInfoEntity transportInfoEntity = this.transportInfoService.queryByTransportOrderId(transportOrderId); | ||
| 60 | +// 转换成DTO | ||
| 43 | return BeanUtil.toBean(transportInfoEntity, TransportInfoDTO.class); | 61 | return BeanUtil.toBean(transportInfoEntity, TransportInfoDTO.class); |
| 62 | + }); | ||
| 63 | + | ||
| 64 | + if (ObjectUtil.isNotEmpty(transportInfoDTO)) { | ||
| 65 | + return transportInfoDTO; | ||
| 44 | } | 66 | } |
| 67 | + | ||
| 45 | throw new SLException(ExceptionEnum.NOT_FOUND); | 68 | throw new SLException(ExceptionEnum.NOT_FOUND); |
| 46 | } | 69 | } |
| 47 | 70 |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/mq/RedisMessageListener.java
0 → 100644
| 1 | +package com.sl.transport.info.mq; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.convert.Convert; | ||
| 4 | +import com.github.benmanes.caffeine.cache.Cache; | ||
| 5 | +import com.sl.transport.info.domain.TransportInfoDTO; | ||
| 6 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 7 | +import org.springframework.data.redis.connection.Message; | ||
| 8 | +import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; | ||
| 9 | +import org.springframework.stereotype.Component; | ||
| 10 | + | ||
| 11 | +import javax.annotation.Resource; | ||
| 12 | + | ||
| 13 | +/** | ||
| 14 | + * redis消息监听,解决Caffeine一致性的问题 | ||
| 15 | + */ | ||
| 16 | +@Component | ||
| 17 | +public class RedisMessageListener extends MessageListenerAdapter { | ||
| 18 | + | ||
| 19 | + @Resource | ||
| 20 | + public Cache<String, TransportInfoDTO> transportInfoCache; | ||
| 21 | + | ||
| 22 | + @Override | ||
| 23 | + public void onMessage(Message message, byte[] pattern) { | ||
| 24 | +// 获取到消息中的运单ID | ||
| 25 | + String transportOrderId = Convert.toStr(message); | ||
| 26 | + | ||
| 27 | +// 将本JVM中的缓存删除掉 | ||
| 28 | + transportInfoCache.invalidate(transportOrderId); | ||
| 29 | + } | ||
| 30 | +} |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/mq/TransportInfoMQListener.java
| 1 | package com.sl.transport.info.mq; | 1 | package com.sl.transport.info.mq; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.convert.Convert; | ||
| 4 | +import cn.hutool.core.util.StrUtil; | ||
| 5 | +import cn.hutool.json.JSONUtil; | ||
| 6 | +import com.sl.ms.transport.api.OrganFeign; | ||
| 3 | import com.sl.transport.common.constant.Constants; | 7 | import com.sl.transport.common.constant.Constants; |
| 8 | +import com.sl.transport.common.vo.TransportInfoMsg; | ||
| 9 | +import com.sl.transport.domain.OrganDTO; | ||
| 10 | +import com.sl.transport.info.entity.TransportInfoDetail; | ||
| 11 | +import com.sl.transport.info.service.TransportInfoService; | ||
| 4 | import org.springframework.amqp.core.ExchangeTypes; | 12 | import org.springframework.amqp.core.ExchangeTypes; |
| 5 | import org.springframework.amqp.rabbit.annotation.Exchange; | 13 | import org.springframework.amqp.rabbit.annotation.Exchange; |
| 6 | import org.springframework.amqp.rabbit.annotation.Queue; | 14 | import org.springframework.amqp.rabbit.annotation.Queue; |
| 7 | import org.springframework.amqp.rabbit.annotation.QueueBinding; | 15 | import org.springframework.amqp.rabbit.annotation.QueueBinding; |
| 8 | import org.springframework.amqp.rabbit.annotation.RabbitListener; | 16 | import org.springframework.amqp.rabbit.annotation.RabbitListener; |
| 17 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 9 | import org.springframework.stereotype.Component; | 18 | import org.springframework.stereotype.Component; |
| 10 | import org.springframework.transaction.annotation.Transactional; | 19 | import org.springframework.transaction.annotation.Transactional; |
| 11 | 20 | ||
| @@ -15,6 +24,13 @@ import org.springframework.transaction.annotation.Transactional; | @@ -15,6 +24,13 @@ import org.springframework.transaction.annotation.Transactional; | ||
| 15 | @Component | 24 | @Component |
| 16 | public class TransportInfoMQListener { | 25 | public class TransportInfoMQListener { |
| 17 | 26 | ||
| 27 | + @Autowired | ||
| 28 | + private OrganFeign organFeign; | ||
| 29 | + | ||
| 30 | + @Autowired | ||
| 31 | + private TransportInfoService transportInfoService; | ||
| 32 | + | ||
| 33 | + | ||
| 18 | @RabbitListener(bindings = @QueueBinding( | 34 | @RabbitListener(bindings = @QueueBinding( |
| 19 | value = @Queue(name = Constants.MQ.Queues.TRANSPORT_INFO_APPEND), | 35 | value = @Queue(name = Constants.MQ.Queues.TRANSPORT_INFO_APPEND), |
| 20 | exchange = @Exchange(name = Constants.MQ.Exchanges.TRANSPORT_INFO, type = ExchangeTypes.TOPIC), | 36 | exchange = @Exchange(name = Constants.MQ.Exchanges.TRANSPORT_INFO, type = ExchangeTypes.TOPIC), |
| @@ -23,6 +39,29 @@ public class TransportInfoMQListener { | @@ -23,6 +39,29 @@ public class TransportInfoMQListener { | ||
| 23 | @Transactional | 39 | @Transactional |
| 24 | public void listenTransportInfoMsg(String msg) { | 40 | public void listenTransportInfoMsg(String msg) { |
| 25 | //{"info":"您的快件已到达【$organId】", "status":"运输中", "organId":90001, "transportOrderId":"SL920733749248" , "created":1653133234913} | 41 | //{"info":"您的快件已到达【$organId】", "status":"运输中", "organId":90001, "transportOrderId":"SL920733749248" , "created":1653133234913} |
| 42 | + TransportInfoMsg transportInfoMsg = JSONUtil.toBean(msg, TransportInfoMsg.class); | ||
| 43 | + Long organId = transportInfoMsg.getOrganId(); | ||
| 44 | + String transportOrderId = Convert.toStr(transportInfoMsg.getTransportOrderId()); | ||
| 45 | + String info = transportInfoMsg.getInfo(); | ||
| 46 | + | ||
| 47 | +// 查询机构信息 | ||
| 48 | + if (StrUtil.contains(info, "$organId")) { | ||
| 49 | + OrganDTO organDTO = organFeign.queryById(organId); | ||
| 50 | + if (organDTO == null) { | ||
| 51 | + return; | ||
| 52 | + } | ||
| 53 | + info = StrUtil.replace(info, "$organId", organDTO.getName()); | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | +// 封装Detail对象 | ||
| 57 | + TransportInfoDetail infoDetail = TransportInfoDetail.builder() | ||
| 58 | + .info(info) | ||
| 59 | + .status(transportInfoMsg.getStatus()) | ||
| 60 | + .created(transportInfoMsg.getCreated()) | ||
| 61 | + .build(); | ||
| 62 | + | ||
| 63 | +// 存储到MongoDB | ||
| 64 | + transportInfoService.saveOrUpdate(transportOrderId, infoDetail); | ||
| 26 | 65 | ||
| 27 | } | 66 | } |
| 28 | } | 67 | } |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/service/BloomFilterService.java
0 → 100644
| 1 | +package com.sl.transport.info.service; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * 布隆过滤器服务 | ||
| 5 | + */ | ||
| 6 | +public interface BloomFilterService { | ||
| 7 | + | ||
| 8 | + /** | ||
| 9 | + * 初始化布隆过滤器 | ||
| 10 | + */ | ||
| 11 | + void init(); | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 向布隆过滤器中添加数据 | ||
| 15 | + * | ||
| 16 | + * @param obj 待添加的数据 | ||
| 17 | + * @return 是否成功 | ||
| 18 | + */ | ||
| 19 | + boolean add(Object obj); | ||
| 20 | + | ||
| 21 | + /** | ||
| 22 | + * 判断数据是否存在 | ||
| 23 | + * | ||
| 24 | + * @param obj 数据 | ||
| 25 | + * @return 是否存在 | ||
| 26 | + */ | ||
| 27 | + boolean contains(Object obj); | ||
| 28 | + | ||
| 29 | +} |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/service/impl/BloomFilterServiceImpl.java
0 → 100644
| 1 | +package com.sl.transport.info.service.impl; | ||
| 2 | + | ||
| 3 | +import com.sl.transport.info.config.BloomFilterConfig; | ||
| 4 | +import com.sl.transport.info.service.BloomFilterService; | ||
| 5 | +import org.redisson.api.RBloomFilter; | ||
| 6 | +import org.redisson.api.RedissonClient; | ||
| 7 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 8 | +import org.springframework.stereotype.Service; | ||
| 9 | + | ||
| 10 | +import javax.annotation.PostConstruct; | ||
| 11 | + | ||
| 12 | +@Service | ||
| 13 | +public class BloomFilterServiceImpl implements BloomFilterService { | ||
| 14 | + | ||
| 15 | + @Autowired | ||
| 16 | + private RedissonClient redissonClient; | ||
| 17 | + | ||
| 18 | + @Autowired | ||
| 19 | + private BloomFilterConfig bloomFilterConfig; | ||
| 20 | + | ||
| 21 | + private RBloomFilter<Object> getBloomFilter() { | ||
| 22 | + return redissonClient.getBloomFilter(this.bloomFilterConfig.getName()); | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + @Override | ||
| 26 | + @PostConstruct | ||
| 27 | + public void init() { | ||
| 28 | + RBloomFilter<Object> bloomFilter = getBloomFilter(); | ||
| 29 | + bloomFilter.tryInit( | ||
| 30 | + bloomFilterConfig.getExpectedInsertions(), | ||
| 31 | + bloomFilterConfig.getFalseProbability()); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + @Override | ||
| 35 | + public boolean add(Object obj) { | ||
| 36 | + return getBloomFilter().add(obj); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + @Override | ||
| 40 | + public boolean contains(Object obj) { | ||
| 41 | + return getBloomFilter().contains(obj); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | +} |
sl-express-ms-transport-info-service/src/main/java/com/sl/transport/info/service/impl/TransportInfoServiceImpl.java
0 → 100644
| 1 | +package com.sl.transport.info.service.impl; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.ListUtil; | ||
| 4 | +import com.github.benmanes.caffeine.cache.Cache; | ||
| 5 | +import com.sl.transport.common.util.ObjectUtil; | ||
| 6 | +import com.sl.transport.info.config.RedisConfig; | ||
| 7 | +import com.sl.transport.info.entity.TransportInfoDetail; | ||
| 8 | +import com.sl.transport.info.entity.TransportInfoEntity; | ||
| 9 | +import com.sl.transport.info.service.TransportInfoService; | ||
| 10 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 11 | +import org.springframework.cache.annotation.CachePut; | ||
| 12 | +import org.springframework.cache.annotation.Cacheable; | ||
| 13 | +import org.springframework.data.mongodb.core.MongoTemplate; | ||
| 14 | +import org.springframework.data.mongodb.core.query.Criteria; | ||
| 15 | +import org.springframework.data.mongodb.core.query.Query; | ||
| 16 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 17 | +import org.springframework.stereotype.Service; | ||
| 18 | + | ||
| 19 | +@Service | ||
| 20 | +public class TransportInfoServiceImpl implements TransportInfoService { | ||
| 21 | + | ||
| 22 | + @Autowired | ||
| 23 | + private MongoTemplate mongoTemplate; | ||
| 24 | + @Autowired | ||
| 25 | + private Cache transportInfoCache; | ||
| 26 | + private StringRedisTemplate stringRedisTemplate; | ||
| 27 | + @Autowired | ||
| 28 | + private BloomFilterServiceImpl bloomFilterService; | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 如果运单数据不存在,就新增,否则更新数据 | ||
| 32 | + * | ||
| 33 | + * @param transportOrderId 运单id | ||
| 34 | + * @param infoDetail 信息详情 | ||
| 35 | + * @return 运输信息数据 | ||
| 36 | + */ | ||
| 37 | + @Override | ||
| 38 | + @CachePut(value = "transport-info",key = "#p0") | ||
| 39 | + public TransportInfoEntity saveOrUpdate(String transportOrderId, TransportInfoDetail infoDetail) { | ||
| 40 | +// 根据运单ID查询 | ||
| 41 | + Query query = Query.query(Criteria.where("transportOrderId").is(transportOrderId)); | ||
| 42 | + TransportInfoEntity transportInfoEntity = mongoTemplate.findOne(query, TransportInfoEntity.class); | ||
| 43 | + if (ObjectUtil.isEmpty(transportInfoEntity)) { | ||
| 44 | +// 运单信息不存在,新增数据 | ||
| 45 | + transportInfoEntity = new TransportInfoEntity(); | ||
| 46 | + transportInfoEntity.setTransportOrderId(transportOrderId); | ||
| 47 | + transportInfoEntity.setInfoList(ListUtil.toList(infoDetail)); | ||
| 48 | + transportInfoEntity.setCreated(System.currentTimeMillis()); | ||
| 49 | + | ||
| 50 | +// 写到布隆过滤器中 | ||
| 51 | + bloomFilterService.add(transportOrderId); | ||
| 52 | + } else { | ||
| 53 | +// 运单信息存在,只需要追加物流详情数据 | ||
| 54 | + transportInfoEntity.getInfoList().add(infoDetail); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | +// 无论新增还是更新都要设置更新时间 | ||
| 58 | + transportInfoEntity.setUpdated(System.currentTimeMillis()); | ||
| 59 | + | ||
| 60 | +// 清除缓存中的数据 | ||
| 61 | +// transportInfoCache.invalidate(transportOrderId); | ||
| 62 | + stringRedisTemplate.convertAndSend(RedisConfig.CHANNEL_TOPIC, transportOrderId); | ||
| 63 | + | ||
| 64 | + return mongoTemplate.save(transportInfoEntity); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + /** | ||
| 68 | + * 根据运单id查询运输信息 | ||
| 69 | + * | ||
| 70 | + * @param transportOrderId 运单id | ||
| 71 | + * @return 运输信息数据 | ||
| 72 | + */ | ||
| 73 | + @Override | ||
| 74 | + @Cacheable(value = "transport-info", key = "#p0") | ||
| 75 | + public TransportInfoEntity queryByTransportOrderId(String transportOrderId) { | ||
| 76 | + Query query = Query.query(Criteria.where("transportOrderId").is(transportOrderId)); | ||
| 77 | + return mongoTemplate.findOne(query, TransportInfoEntity.class); | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | +} |