Spring Cloud + Redis 是如何实现点赞、取消点赞的?

  • 文章结尾有彩蛋

  • 一、Redis 缓存设计及实现

    • 1.1 Redis 安装及运行

    • 1.2 Redis 与 SpringBoot 项目的整合

    • 1.3 Redis 的数据结构类型

    • 1.4 点赞数据在 Redis 中的存储格式

    • 1.5 操作 Redis

  • 二、数据库设计

  • 三、数据库操作

  • 四、开启定时任务持久化存储到数据库


本文基于 SpringCloud, 用户发起点赞、取消点赞后先存入 Redis 中,再每隔两小时从 Redis 读取点赞数据写入数据库中做持久化存储。

点赞功能在很多系统中都有,但别看功能小,想要做好需要考虑的东西还挺多的。

点赞、取消点赞是高频次的操作,若每次都读写数据库,大量的操作会影响数据库性能,所以需要做缓存。

至于多久从 Redis 取一次数据存到数据库中,根据项目的实际情况定吧,我是暂时设了两个小时。

项目需求需要查看都谁点赞了,所以要存储每个点赞的点赞人、被点赞人,不能简单的做计数。

文章分四部分介绍:

  • Redis 缓存设计及实现

  • 数据库设计

  • 数据库操作

  • 开启定时任务持久化存储到数据库

一、Redis 缓存设计及实现

1.1 Redis 安装及运行

Redis 安装请自行查阅相关教程。

说下Docker 安装运行 Redis

docker run -d -p 6379:6379 redis:4.0.8

如果已经安装了 Redis,打开命令行,输入启动 Redis 的命令

redis-server

1.2 Redis 与 SpringBoot 项目的整合

1.在 pom.xml 中引入依赖

1<dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-redis</artifactId> 4</dependency>

2.在启动类上添加注释 @EnableCaching

1@SpringBootApplication 2@EnableDiscoveryClient 3@EnableSwagger2 4@EnableFeignClients(basePackages = "com.solo.coderiver.project.client") 5@EnableCaching 6public class UserApplication { 7 8 public static void main(String[] args) { 9 SpringApplication.run(UserApplication.class, args); 10 } 11}

3.编写 Redis 配置类 RedisConfig

1import com.fasterxml.jackson.annotation.JsonAutoDetect; 2import com.fasterxml.jackson.annotation.PropertyAccessor; 3import com.fasterxml.jackson.databind.ObjectMapper; 4import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 5import org.springframework.context.annotation.Bean; 6import org.springframework.context.annotation.Configuration; 7import org.springframework.data.redis.connection.RedisConnectionFactory; 8import org.springframework.data.redis.core.RedisTemplate; 9import org.springframework.data.redis.core.StringRedisTemplate; 10import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 11 12import java.net.UnknownHostException; 13 14 15@Configuration 16public class RedisConfig { 17 18 @Bean 19 @ConditionalOnMissingBean(name = "redisTemplate") 20 public RedisTemplate<String, Object> redisTemplate( 21 RedisConnectionFactory redisConnectionFactory) 22 throws UnknownHostException { 23 24 Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class); 25 ObjectMapper om = new ObjectMapper(); 26 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 27 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 28 jackson2JsonRedisSerializer.setObjectMapper(om); 29 30 RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); 31 template.setConnectionFactory(redisConnectionFactory); 32 template.setKeySerializer(jackson2JsonRedisSerializer); 33 template.setValueSerializer(jackson2JsonRedisSerializer); 34 template.setHashKeySerializer(jackson2JsonRedisSerializer); 35 template.setHashValueSerializer(jackson2JsonRedisSerializer); 36 template.afterPropertiesSet(); 37 return template; 38 } 39 40 41 @Bean 42 @ConditionalOnMissingBean(StringRedisTemplate.class) 43 public StringRedisTemplate stringRedisTemplate( 44 RedisConnectionFactory redisConnectionFactory) 45 throws UnknownHostException { 46 StringRedisTemplate template = new StringRedisTemplate(); 47 template.setConnectionFactory(redisConnectionFactory); 48 return template; 49 } 50}

至此 Redis 在 SpringBoot 项目中的配置已经完成,可以愉快的使用了。

1.3 Redis 的数据结构类型

Redis 可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)。

下面来对这5种数据结构类型作简单的介绍:

1.4 点赞数据在 Redis 中的存储格式

用 Redis 存储两种数据,一种是记录点赞人、被点赞人、点赞状态的数据,另一种是每个用户被点赞了多少次,做个简单的计数。

由于需要记录点赞人和被点赞人,还有点赞状态(点赞、取消点赞),还要固定时间间隔取出 Redis 中所有点赞数据,分析了下 Redis 数据格式中 Hash 最合适。

因为 Hash 里的数据都是存在一个键里,可以通过这个键很方便的把所有的点赞数据都取出。这个键里面的数据还可以存成键值对的形式,方便存入点赞人、被点赞人和点赞状态。

设点赞人的 id 为 likedPostId,被点赞人的 id 为 likedUserId ,点赞时状态为 1,取消点赞状态为 0。将点赞人 id 和被点赞人 id 作为键,两个 id 中间用 :: 隔开,点赞状态作为值。

所以如果用户点赞,存储的键为:likedUserId::likedPostId,对应的值为 1 。取消点赞,存储的键为:likedUserId::likedPostId,对应的值为 0 。取数据时把键用 :: 切开就得到了两个id,也很方便。

在可视化工具 RDM 中看到的是这样子

1.5 操作 Redis

将具体操作方法封装到了 RedisService 接口里

RedisService.java

1import com.solo.coderiver.user.dataobject.UserLike; 2import com.solo.coderiver.user.dto.LikedCountDTO; 3 4import java.util.List; 5 6public interface RedisService { 7 8 /** 9 * 点赞。状态为1 10 * @param likedUserId 11 * @param likedPostId 12 */ 13 void saveLiked2Redis(String likedUserId, String likedPostId); 14 15 /** 16 * 取消点赞。将状态改变为0 17 * @param likedUserId 18 * @param likedPostId 19 */ 20 void unlikeFromRedis(String likedUserId, String likedPostId); 21 22 /** 23 * 从Redis中删除一条点赞数据 24 * @param likedUserId 25 * @param likedPostId 26 */ 27 void deleteLikedFromRedis(String likedUserId, String likedPostId); 28 29 /** 30 * 该用户的点赞数加1 31 * @param likedUserId 32 */ 33 void incrementLikedCount(String likedUserId); 34 35 /** 36 * 该用户的点赞数减1 37 * @param likedUserId 38 */ 39 void decrementLikedCount(String likedUserId); 40 41 /** 42 * 获取Redis中存储的所有点赞数据 43 * @return 44 */ 45 List<UserLike> getLikedDataFromRedis(); 46 47 /** 48 * 获取Redis中存储的所有点赞数量 49 * @return 50 */ 51 List<LikedCountDTO> getLikedCountFromRedis(); 52 53}

实现类 RedisServiceImpl.java

1import com.solo.coderiver.user.dataobject.UserLike; 2import com.solo.coderiver.user.dto.LikedCountDTO; 3import com.solo.coderiver.user.enums.LikedStatusEnum; 4import com.solo.coderiver.user.service.LikedService; 5import com.solo.coderiver.user.service.RedisService; 6import com.solo.coderiver.user.utils.RedisKeyUtils; 7import lombok.extern.slf4j.Slf4j; 8import org.springframework.beans.factory.annotation.Autowired; 9import org.springframework.data.redis.core.Cursor; 10import org.springframework.data.redis.core.RedisTemplate; 11import org.springframework.data.redis.core.ScanOptions; 12import org.springframework.stereotype.Service; 13 14import java.util.ArrayList; 15import java.util.List; 16import java.util.Map; 17 18@Service 19@Slf4j 20public class RedisServiceImpl implements RedisService { 21 22 @Autowired 23 RedisTemplate redisTemplate; 24 25 @Autowired 26 LikedService likedService; 27 28 @Override 29 public void saveLiked2Redis(String likedUserId, String likedPostId) { 30 String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId); 31 redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.LIKE.getCode()); 32 } 33 34 @Override 35 public void unlikeFromRedis(String likedUserId, String likedPostId) { 36 String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId); 37 redisTemplate.opsForHash().put(RedisKeyUtils.MAP_KEY_USER_LIKED, key, LikedStatusEnum.UNLIKE.getCode()); 38 } 39 40 @Override 41 public void deleteLikedFromRedis(String likedUserId, String likedPostId) { 42 String key = RedisKeyUtils.getLikedKey(likedUserId, likedPostId); 43 redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key); 44 } 45 46 @Override 47 public void incrementLikedCount(String likedUserId) { 48 redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, 1); 49 } 50 51 @Override 52 public void decrementLikedCount(String likedUserId) { 53 redisTemplate.opsForHash().increment(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, likedUserId, -1); 54 } 55 56 @Override 57 public List<UserLike> getLikedDataFromRedis() { 58 Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED, ScanOptions.NONE); 59 List<UserLike> list = new ArrayList<>(); 60 while (cursor.hasNext()){ 61 Map.Entry<Object, Object> entry = cursor.next(); 62 String key = (String) entry.getKey(); 63 //分离出 likedUserId,likedPostId 64 String[] split = key.split("::"); 65 String likedUserId = split[0]; 66 String likedPostId = split[1]; 67 Integer value = (Integer) entry.getValue(); 68 69 //组装成 UserLike 对象 70 UserLike userLike = new UserLike(likedUserId, likedPostId, value); 71 list.add(userLike); 72 73 //存到 list 后从 Redis 中删除 74 redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED, key); 75 } 76 77 return list; 78 } 79 80 @Override 81 public List<LikedCountDTO> getLikedCountFromRedis() { 82 Cursor<Map.Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, ScanOptions.NONE); 83 List<LikedCountDTO> list = new ArrayList<>(); 84 while (cursor.hasNext()){ 85 Map.Entry<Object, Object> map = cursor.next(); 86 //将点赞数量存储在 LikedCountDT 87 String key = (String)map.getKey(); 88 LikedCountDTO dto = new LikedCountDTO(key, (Integer) map.getValue()); 89 list.add(dto); 90 //从Redis中删除这条记录 91 redisTemplate.opsForHash().delete(RedisKeyUtils.MAP_KEY_USER_LIKED_COUNT, key); 92 } 93 return list; 94 } 95}

用到的工具类和枚举类

RedisKeyUtils, 用于根据一定规则生成 key

1public class RedisKeyUtils { 2 3 //保存用户点赞数据的key 4 public static final String MAP_KEY_USER_LIKED = "MAP_USER_LIKED"; 5 //保存用户被点赞数量的key 6 public static final String MAP_KEY_USER_LIKED_COUNT = "MAP_USER_LIKED_COUNT"; 7 8 /** 9 * 拼接被点赞的用户id和点赞的人的id作为key。格式 222222::333333 10 * @param likedUserId 被点赞的人id 11 * @param likedPostId 点赞的人的id 12 * @return 13 */ 14 public static String getLikedKey(String likedUserId, String likedPostId){ 15 StringBuilder builder = new StringBuilder(); 16 builder.append(likedUserId); 17 builder.append("::"); 18 builder.append(likedPostId); 19 return builder.toString(); 20 } 21}

LikedStatusEnum 用户点赞状态的枚举类

1package com.solo.coderiver.user.enums; 2 3import lombok.Getter; 4 5/** 6 * 用户点赞的状态 7 */ 8@Getter 9public enum LikedStatusEnum { 10 LIKE(1, "点赞"), 11 UNLIKE(0, "取消点赞/未点赞"), 12 ; 13 14 private Integer code; 15 16 private String msg; 17 18 LikedStatusEnum(Integer code, String msg) { 19 this.code = code; 20 this.msg = msg; 21 } 22}

二、数据库设计

数据库表中至少要包含三个字段:被点赞用户id,点赞用户id,点赞状态。再加上主键id,创建时间,修改时间就行了。

建表语句

1create table `user_like`( 2 `id` int not null auto_increment, 3 `liked_user_id` varchar(32) not null comment '被点赞的用户id', 4 `liked_post_id` varchar(32) not null comment '点赞的用户id', 5 `status` tinyint(1) default '1' comment '点赞状态,0取消,1点赞', 6 `create_time` timestamp not null default current_timestamp comment '创建时间', 7 `update_time` timestamp not null default current_timestamp on update current_timestamp comment '修改时间', 8 primary key(`id`), 9 INDEX `liked_user_id`(`liked_user_id`), 10 INDEX `liked_post_id`(`liked_post_id`) 11) comment '用户点赞表';

对应的对象 UserLike

1import com.solo.coderiver.user.enums.LikedStatusEnum; 2import lombok.Data; 3 4import javax.persistence.Entity; 5import javax.persistence.GeneratedValue; 6import javax.persistence.GenerationType; 7import javax.persistence.Id; 8 9/** 10 * 用户点赞表 11 */ 12@Entity 13@Data 14public class UserLike { 15 16 //主键id 17 @Id 18 @GeneratedValue(strategy = GenerationType.IDENTITY) 19 private Integer id; 20 21 //被点赞的用户的id 22 private String likedUserId; 23 24 //点赞的用户的id 25 private String likedPostId; 26 27 //点赞的状态.默认未点赞 28 private Integer status = LikedStatusEnum.UNLIKE.getCode(); 29 30 public UserLike() { 31 } 32 33 public UserLike(String likedUserId, String likedPostId, Integer status) { 34 this.likedUserId = likedUserId; 35 this.likedPostId = likedPostId; 36 this.status = status; 37 } 38}

三、数据库操作

操作数据库同样封装在接口中

LikedService

1import com.solo.coderiver.user.dataobject.UserLike; 2import org.springframework.data.domain.Page; 3import org.springframework.data.domain.Pageable; 4 5import java.util.List; 6 7public interface LikedService { 8 9 /** 10 * 保存点赞记录 11 * @param userLike 12 * @return 13 */ 14 UserLike save(UserLike userLike); 15 16 /** 17 * 批量保存或修改 18 * @param list 19 */ 20 List<UserLike> saveAll(List<UserLike> list); 21 22 23 /** 24 * 根据被点赞人的id查询点赞列表(即查询都谁给这个人点赞过) 25 * @param likedUserId 被点赞人的id 26 * @param pageable 27 * @return 28 */ 29 Page<UserLike> getLikedListByLikedUserId(String likedUserId, Pageable pageable); 30 31 /** 32 * 根据点赞人的id查询点赞列表(即查询这个人都给谁点赞过) 33 * @param likedPostId 34 * @param pageable 35 * @return 36 */ 37 Page<UserLike> getLikedListByLikedPostId(String likedPostId, Pageable pageable); 38 39 /** 40 * 通过被点赞人和点赞人id查询是否存在点赞记录 41 * @param likedUserId 42 * @param likedPostId 43 * @return 44 */ 45 UserLike getByLikedUserIdAndLikedPostId(String likedUserId, String likedPostId); 46 47 /** 48 * 将Redis里的点赞数据存入数据库中 49 */ 50 void transLikedFromRedis2DB(); 51 52 /** 53 * 将Redis中的点赞数量数据存入数据库 54 */ 55 void transLikedCountFromRedis2DB(); 56 57}

LikedServiceImpl 实现类

1import com.solo.coderiver.user.dataobject.UserInfo; 2import com.solo.coderiver.user.dataobject.UserLike; 3import com.solo.coderiver.user.dto.LikedCountDTO; 4import com.solo.coderiver.user.enums.LikedStatusEnum; 5import com.solo.coderiver.user.repository.UserLikeRepository; 6import com.solo.coderiver.user.service.LikedService; 7import com.solo.coderiver.user.service.RedisService; 8import com.solo.coderiver.user.service.UserService; 9import lombok.extern.slf4j.Slf4j; 10import org.springframework.beans.factory.annotation.Autowired; 11import org.springframework.data.domain.Page; 12import org.springframework.data.domain.Pageable; 13import org.springframework.stereotype.Service; 14import org.springframework.transaction.annotation.Transactional; 15 16import java.util.List; 17 18@Service 19@Slf4j 20public class LikedServiceImpl implements LikedService { 21 22 @Autowired 23 UserLikeRepository likeRepository; 24 25 @Autowired 26 RedisService redisService; 27 28 @Autowired 29 UserService userService; 30 31 @Override 32 @Transactional 33 public UserLike save(UserLike userLike) { 34 return likeRepository.save(userLike); 35 } 36 37 @Override 38 @Transactional 39 public List<UserLike> saveAll(List<UserLike> list) { 40 return likeRepository.saveAll(list); 41 } 42 43 @Override 44 public Page<UserLike> getLikedListByLikedUserId(String likedUserId, Pageable pageable) { 45 return likeRepository.findByLikedUserIdAndStatus(likedUserId, LikedStatusEnum.LIKE.getCode(), pageable); 46 } 47 48 @Override 49 public Page<UserLike> getLikedListByLikedPostId(String likedPostId, Pageable pageable) { 50 return likeRepository.findByLikedPostIdAndStatus(likedPostId, LikedStatusEnum.LIKE.getCode(), pageable); 51 } 52 53 @Override 54 public UserLike getByLikedUserIdAndLikedPostId(String likedUserId, String likedPostId) { 55 return likeRepository.findByLikedUserIdAndLikedPostId(likedUserId, likedPostId); 56 } 57 58 @Override 59 @Transactional 60 public void transLikedFromRedis2DB() { 61 List<UserLike> list = redisService.getLikedDataFromRedis(); 62 for (UserLike like : list) { 63 UserLike ul = getByLikedUserIdAndLikedPostId(like.getLikedUserId(), like.getLikedPostId()); 64 if (ul == null){ 65 //没有记录,直接存入 66 save(like); 67 }else{ 68 //有记录,需要更新 69 ul.setStatus(like.getStatus()); 70 save(ul); 71 } 72 } 73 } 74 75 @Override 76 @Transactional 77 public void transLikedCountFromRedis2DB() { 78 List<LikedCountDTO> list = redisService.getLikedCountFromRedis(); 79 for (LikedCountDTO dto : list) { 80 UserInfo user = userService.findById(dto.getId()); 81 //点赞数量属于无关紧要的操作,出错无需抛异常 82 if (user != null){ 83 Integer likeNum = user.getLikeNum() + dto.getCount(); 84 user.setLikeNum(likeNum); 85 //更新点赞数量 86 userService.updateInfo(user); 87 } 88 } 89 } 90}

数据库的操作就这些,主要还是增删改查。

四、开启定时任务持久化存储到数据库

定时任务 Quartz 很强大,就用它了。

Quartz 使用步骤:

1.添加依赖

1<dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-quartz</artifactId> 4</dependency>

2.编写配置文件

1package com.solo.coderiver.user.config; 2 3import com.solo.coderiver.user.task.LikeTask; 4import org.quartz.*; 5import org.springframework.context.annotation.Bean; 6import org.springframework.context.annotation.Configuration; 7 8@Configuration 9public class QuartzConfig { 10 11 private static final String LIKE_TASK_IDENTITY = "LikeTaskQuartz"; 12 13 @Bean 14 public JobDetail quartzDetail(){ 15 return JobBuilder.newJob(LikeTask.class).withIdentity(LIKE_TASK_IDENTITY).storeDurably().build(); 16 } 17 18 @Bean 19 public Trigger quartzTrigger(){ 20 SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() 21// .withIntervalInSeconds(10) //设置时间周期单位秒 22 .withIntervalInHours(2) //两个小时执行一次 23 .repeatForever(); 24 return TriggerBuilder.newTrigger().forJob(quartzDetail()) 25 .withIdentity(LIKE_TASK_IDENTITY) 26 .withSchedule(scheduleBuilder) 27 .build(); 28 } 29}

3.编写执行任务的类继承自 QuartzJobBean

1package com.solo.coderiver.user.task; 2 3import com.solo.coderiver.user.service.LikedService; 4import lombok.extern.slf4j.Slf4j; 5import org.apache.commons.lang.time.DateUtils; 6import org.quartz.JobExecutionContext; 7import org.quartz.JobExecutionException; 8import org.springframework.beans.factory.annotation.Autowired; 9import org.springframework.scheduling.quartz.QuartzJobBean; 10 11import java.text.SimpleDateFormat; 12import java.util.Date; 13 14/** 15 * 点赞的定时任务 16 */ 17@Slf4j 18public class LikeTask extends QuartzJobBean { 19 20 @Autowired 21 LikedService likedService; 22 23 private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 24 25 @Override 26 protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { 27 28 log.info("LikeTask-------- {}", sdf.format(new Date())); 29 30 //将 Redis 里的点赞信息同步到数据库里 31 likedService.transLikedFromRedis2DB(); 32 likedService.transLikedCountFromRedis2DB(); 33 } 34}

在定时任务中直接调用 LikedService 封装的方法完成数据同步。

以上就是点赞功能的设计与实现,不足之处还请各位大佬多多指教。

另外,点赞/取消点赞 跟 点赞数 +1/ -1 应该保证是原子操作 , 不然出现并发问题就会有两条重复的点赞记录 , 所以要给整个原子操作加锁 . 同时需要在Spring Boot 的系统关闭钩子函数中补充同步redis中点赞数据到mysql中的过程 . 不然有可能出现距离上一次同步1小时59分的时候服务器更新 , 把整整两小时的点赞数据都给清空了 . 如果点赞设计到比较重要活动业务的话这就很尴尬了 .

spring cloud分布式事务从入门到精通

(如下载连接失效,请私信我)

百度云下载链接:https://pan.baidu.com/s/1EtYyj7MEBqIGSYg2ljBFyg 提取码:n8p7

备份下载地址 https://huoyan-dabing.lanzous.com/b0d253o4h 密码:9sem

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )