某马点评——day04

达人探店

发布探店笔记

 改一下,图片保存路径就可以直接运行测试了。

查看探店笔记

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
    @Resource
    private IUserService userService;
    @Override
    public Result queryBlogById(Long id) {
        //1.查询blog
        Blog blog = getById(id);
        if(blog==null){
            return Result.fail("笔记不存在");
        }
        //2.查询blog有关用户
        queryBlogUser(blog);
        return Result.ok(blog);
    }

    private void queryBlogUser(Blog blog) {
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }

    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(this::queryBlogUser);
        return Result.ok(records);
    }
}

点赞

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
    @Resource
    private IUserService userService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Result queryBlogById(Long id) {
        //1.查询blog
        Blog blog = getById(id);
        if(blog==null){
            return Result.fail("笔记不存在");
        }
        //2.查询blog有关用户
        queryBlogUser(blog);
        //3.查询blog是否被点赞
        isBlogLiked(blog);
        return Result.ok(blog);
    }

    private void isBlogLiked(Blog blog) {
        //1.判获取登录用户
        Long userId = UserHolder.getUser().getId();
        //2.判断当前登录用户是否已经点赞
        String key=BLOG_LIKED_KEY+blog.getId();
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        blog.setIsLike(BooleanUtil.isTrue(isMember));
    }

    private void queryBlogUser(Blog blog) {
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }

    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(blog->{
            this.queryBlogUser(blog);
            this.isBlogLiked(blog);

        });
        return Result.ok(records);
    }

    @Override
    public Result likeBlog(Long id) {
        //1.判获取登录用户
        Long userId = UserHolder.getUser().getId();
        //2.判断当前登录用户是否已经点赞
        String key=BLOG_LIKED_KEY+id;
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        if(BooleanUtil.isFalse(isMember)) {
            //3.如果未点赞
            //3.1数据库点赞数+1
            boolean isSuccess = update().setSql("liked = liked + 1").eq("id", id).update();
            //3.2保存用户到Redis的set集合
            if(isSuccess){
                stringRedisTemplate.opsForSet().add(key,userId.toString());
            }
        }else {
            //4.如果已点赞,取消点赞
            //4.1数据库点赞数-1
            boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();
            //4.2把用户从redis的set集合删除
            stringRedisTemplate.opsForSet().remove(key,userId.toString());
        }
            return Result.ok();
    }
}

点赞排行榜

 为了将最早点赞的人摆在最前面,需要按照时间先后存储分数,这里使用zset存储时间戳作为zset的score作为排序的依据。

然后针对mysql的排序会乱序的问题需要自定义排序规则,将数据按照指定顺序展示.

@Service
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {
    @Resource
    private IUserService userService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Result queryBlogById(Long id) {
        //1.查询blog
        Blog blog = getById(id);
        if(blog==null){
            return Result.fail("笔记不存在");
        }
        //2.查询blog有关用户
        queryBlogUser(blog);
        //3.查询blog是否被点赞
        isBlogLiked(blog);
        return Result.ok(blog);
    }

    private void isBlogLiked(Blog blog) {
        //1.判获取登录用户
        UserDTO user = UserHolder.getUser();
        if(user==null){
            //用户未登录,无需查询是否点赞
            return;
        }
        Long userId = user.getId();
        //2.判断当前登录用户是否已经点赞
        String key=BLOG_LIKED_KEY+blog.getId();
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
        blog.setIsLike(score!=null);
    }

    private void queryBlogUser(Blog blog) {
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }

    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(blog->{
            this.queryBlogUser(blog);
            this.isBlogLiked(blog);

        });
        return Result.ok(records);
    }

    @Override
    public Result likeBlog(Long id) {
        //1.判获取登录用户
        Long userId = UserHolder.getUser().getId();
        //2.判断当前登录用户是否已经点赞
        String key=BLOG_LIKED_KEY+id;
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
        if(score==null) {
            //3.如果未点赞
            //3.1数据库点赞数+1
            boolean isSuccess = update().setSql("liked = liked + 1").eq("id", id).update();
            //3.2保存用户到Redis的set集合 zadd key value score
            if(isSuccess){
                stringRedisTemplate.opsForZSet().add(key,userId.toString(),System.currentTimeMillis());
            }
        }else {
            //4.如果已点赞,取消点赞
            //4.1数据库点赞数-1
            boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update();
            //4.2把用户从redis的set集合删除
            stringRedisTemplate.opsForZSet().remove(key,userId.toString());
        }
            return Result.ok();
    }

    @Override
    public Result queryBlogLikes(Long id) {
        //1.查询top5的点赞用户 zrange key 0 4
        String key=BLOG_LIKED_KEY+id;
        Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);
        if(top5==null||top5.isEmpty()){
            return Result.ok(Collections.emptyList());
        }
        //2.解析出用户id
        List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());
         //将id拼成字符串
        String idStr = StrUtil.join(",", ids);
        //3.根绝用户id查询用户 必须自定义排序规则进行查询,否则原本是有序的数据查完之后就变成无序的了
        List<UserDTO> userDTOS = userService.query()
                .in("id",ids).last("ORDER BY FIELD(id,"+idStr+")")
                .list()
                .stream()
                .map(user -> BeanUtil.copyProperties(user, UserDTO.class))
                .collect(Collectors.toList());

        //4.返回
        return Result.ok(userDTOS);
    }
}

好友关注

关注和取关

一个接口实现关注和取关

@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {

    /**
     * 关注取关功能
     * @param followUserId
     * @param isFollow
     * @return
     */
    @Override
    public Result follow(Long followUserId, Boolean isFollow) {
        //1.获取登录用户
        Long userId = UserHolder.getUser().getId();
        //1.判断到底是关注还是取关
        if (isFollow) {
            //2.关注,新增数据
            Follow follow = new Follow();
            follow.setUserId(userId);
            follow.setFollowUserId(followUserId);
            save(follow);
        }else{
            //3.取关,删除 delete from tb_follow where userId = ? and follow_user_id = ?
            remove(new QueryWrapper<Follow>()
                    .eq("user_id",userId)
                    .eq("follow_user_id",followUserId));
        }
        return Result.ok();
    }

    @Override
    public Result isFollow(Long followUserId) {
        //1.获取登录用户
        Long userId = UserHolder.getUser().getId();
        //2.查询是否关注 select count(*)  from tb_follow where userId = ? and follow_user_id = ?
        Integer count = query().eq("user_id", userId)
                .eq("follow_user_id", followUserId).count();
        //3.判断
        return Result.ok(count>0);
    }
}

共同关注

这两个接口直接使用资料里的代码片段

// UserController 根据id查询用户

@GetMapping("/{id}")
public Result queryUserById(@PathVariable("id") Long userId){
	// 查询详情
	User user = userService.getById(userId);
	if (user == null) {
		return Result.ok();
	}
	UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
	// 返回
	return Result.ok(userDTO);
}

// BlogController
@GetMapping("/of/user")
public Result queryBlogByUserId(
		@RequestParam(value = "current", defaultValue = "1") Integer current,
		@RequestParam("id") Long id) {
	// 根据用户查询
	Page<Blog> page = blogService.query()
			.eq("user_id", id).page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
	// 获取当前页数据
	List<Blog> records = page.getRecords();
	return Result.ok(records);
}

 为了能用redis的set集合取交集求得共同关注的好友,这里要将一个用户关注的所有人都存储到redis里的set集合,,取关了从set集合里删除。

代码实现

    @Override
    public Result followCommons(Long id) {
        //1.获取当前用户
        Long userId = UserHolder.getUser().getId();
        String key="follows:"+userId;
        //2.求交集
        String key2="follows:"+id;
        Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key, key2);
        if(intersect==null||intersect.isEmpty()){
            //无交集
            return Result.ok(Collections.emptyList());
        }
        //3.解析id集合
        List<Long> ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList());
        //4.查询用户
        List<UserDTO> users = userService
                .listByIds(ids)
                .stream()
                .map(user -> BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());
        return Result.ok(users);
    }

关注推送

有点像观察者模式,观察者给监听者集体发送消息。

 feed流实现方案分析 

拉模式下会将用户关注的人的消息全都拉取到收件箱里面按照时间进行排序。 这个模式下,消息只会在作者的发件箱持久保存一份,用户的收件箱每次打开都会去拉取一份新的,用完就删。每次都读取一堆,性能消耗大。

 推模式下会将消息发送到用户的收件箱持久化保存。但是这个模式下一个消息会写n份,内存占用高。

普通v直接用推模式,大v的活跃粉丝用推模式,普通粉丝数量多用拉模式。 

 基于推模式实现关注推送功能

这里选择推送blog的id到用户的收件箱,用户要看时再现查。

这里使用Redis的Zset进行保存,基于时间戳进行排序,要进行分页查询时利用角标0~n。

这里传统分页好像是有个问题,会出现相同商品重复出现的情况。然后利用滚动分页就不会有这种情况,但是这样话新数据又去哪里了? 

 

使用sortedSet实现的时候,每次分页记住时间戳最小的那个,下次查就从更小的开始,就不会出现数据重复了。

推送代码实现

改造新增blog的代码,在新增成功的时候获取所有粉丝id进行blog推送。

    @Override
    public Result saveBlog(Blog blog) {
        // 1.获取登录用户
        UserDTO user = UserHolder.getUser();
        blog.setUserId(user.getId());
        // 2.保存探店博文
        boolean isSucess = save(blog);
        if(!isSucess){
            return Result.fail("新增笔记失败");
        }
        //3.查询笔记作者的所有粉丝 select * from tb_follow where follow_user_id=?
        List<Follow> follows = followService.query().eq("follow_user_id", user.getId()).list();
        //4.推送笔记id给所有粉丝
        for(Follow follow:follows){
            //4.1获取粉丝id
            Long userId = follow.getUserId();
            //4.2推送
            String key=FEED_KEY+userId;
            stringRedisTemplate.opsForZSet().add(key,blog.getId().toString(),System.currentTimeMillis());
        }
        // 3.返回id
        return Result.ok(blog.getId());
    }
滚动分页查询收件箱思路

使用的是zrange,不能按照角标查询,要按照score进行查询.

所以这里使用按照分数查询的命令. 但是这里也会存在问题,如果存在两个相同score的话,可能也会出现重复,因为命令是按照小于等于。

滚动分页查询实现 

这个代码好像还是有点问题,这里查询了blog有关用户和是否点赞却没有用上

@Data
public class ScrollResult {
    private List<?> list;
    private Long minTime;
    private Integer offset;
}
    @GetMapping("/of/follow")
    public Result queryBlogOfFollow(
            @RequestParam("lastId") Long max, @RequestParam(value = "offset",defaultValue = "0") Integer offset){
        return blogService.queryBlogOfFollow(max,offset);
    }
    @Override
    public Result queryBlogOfFollow(Long max, Integer offset) {
        //1.获取当前用户
        Long userId = UserHolder.getUser().getId();
        //2.查询收件箱 ZREVRANGBYSCORE key MAX MIN WITHSCORES LIMIT offset count
        String key=FEED_KEY+userId;
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores(key, 0, max, offset, 2);
        //3.非空判断
        if(typedTuples==null||typedTuples.isEmpty()){
            return Result.ok();
        }
        //4.解析数据: blogId ,mintime(时间戳),offset
        List<Long> ids=new ArrayList<>(typedTuples.size());
        long minTime=0;
        int os=1;
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) { //
            //4.1获取id
            ids.add(Long.valueOf(tuple.getValue()));
            //4.2获取分数(时间戳)
            long time=tuple.getScore().longValue();
            if(time==minTime){
                os++;
            }else{
                minTime=time;
                os=1;
            }
        }
        //5.根据id查询blog 基于in语句查询会打乱顺序
        String idStr = StrUtil.join(",", ids);
        List<Blog> blogs =query()
                .in("id",ids).last("ORDER BY FIELD(id,"+idStr+")").list();

        for (Blog blog : blogs) {
            //5.1.查询blog有关的用户
            queryBlogUser(blog);
            //5.2.查询blog是否被点赞
            isBlogLiked(blog);
        }

        //6.封装并返回
        ScrollResult scrollResult = new ScrollResult();
        scrollResult.setList(blogs);
        scrollResult.setMinTime(minTime);
        scrollResult.setOffset(os);
        return Result.ok(scrollResult);
    }

附近商铺

GEO数据结构的基本用法

 

导入店铺数据到GEO

写一个数据导入的测试类

 

    @Test
    void loadShopDate(){
        //1.查询店铺信息
        List<Shop> list = shopService.list();
        //2.把店铺分组,按照typeId分组,typeId一致的放到一个集合
        Map<Long,List<Shop>>  map=list.stream().collect(Collectors.groupingBy(Shop::getTypeId));
        //3.分批完成写入Redis
        for (Map.Entry<Long, List<Shop>> entry : map.entrySet()) {
            //3.1获取类型id
            Long typeId = entry.getKey();
            String key= SHOP_GEO_KEY+typeId;
            //3.2获取同类型的店铺的集合
            List<Shop> value = entry.getValue();
            List<RedisGeoCommands.GeoLocation<String>> locations=new ArrayList<>();

            //3.3写入redis geoadd key 经度 维度 member
            for (Shop shop : value) {
                //写入一条数据
                //stringRedisTemplate.opsForGeo().add(key,new Point(shop.getX(),shop.getY()),shop.getId().toString());
                locations.add(new RedisGeoCommands.GeoLocation<>(
                        shop.getId().toString(),
                        new Point(shop.getX(),shop.getY())));
            }
            //一次写入多条数据
            stringRedisTemplate.opsForGeo().add(key,locations);
        }
    }

实现附近商户功能

用户签到

BitMap功能演示 

这个表格里的每一行数据就是用户的一条签到记录,现在使用二进制压缩来存储.

实现签到功能

 代码实现

    @Override
    public Result sign() {
        //1.获取当前登录用户
        Long userId = UserHolder.getUser().getId();
        //2.获取日期
        LocalDateTime now = LocalDateTime.now();
        //3.拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key=USER_SIGN_KEY+userId+keySuffix;
        //4.获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        //5.写入Redis SETBIT key offset 1
        stringRedisTemplate.opsForValue().setBit(key, dayOfMonth-1,true);
        return Result.ok();
    }

统计连续签到

代码实现

@Override
    public Result signCount() {
        //1.获取当前登录用户
        Long userId = UserHolder.getUser().getId();
        //2.获取日期
        LocalDateTime now = LocalDateTime.now();
        //3.拼接key
        String keySuffix = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
        String key=USER_SIGN_KEY+userId+keySuffix;
        //4.获取今天是本月的第几天
        int dayOfMonth = now.getDayOfMonth();
        //5.获取本月截止今天为止的所有的签到记录,要返回的是一个十进制的数字 BITFIELD sign:8:202312 GET u14 0
        List<Long> result = stringRedisTemplate.opsForValue().bitField(
                key,
                BitFieldSubCommands.create()
                        .get(BitFieldSubCommands.BitFieldType
                                .unsigned(dayOfMonth))
                        .valueAt(0) //今天多少号就多少个bit位
        );
        if(result==null||result.isEmpty())
        {
            //没有任何签到结果
            return Result.ok(0);
        }
        Long num=result.get(0);
        if(num==null||num==0){
            return Result.ok(0);
        }
        //6.循环遍历
        int count=0;
        while(true){
        //6.1让这个数字与1做与运算,得到数字的最后一个bit位
            //判断这个bit位是否为0
            if ((num&1)==0) {
                //如果为0,说明未签到,结束
                break;
            }else{
                //如果不为0,说明已签到,计数器+1
                count++;
            }
        //把数字右移一位,抛弃最后一个bit位,继续下一个bit位
            num>>>=1;
        }
        return Result.ok(count);
    }

UV统计

HyperLogLog的用法

 

测试百万数据的统计

    @Test
    void testHyperLogLog(){
        //准备数组,装用户数据
        String[] users = new String[1000];
        //数据角标记
        int index=0;
        for(int i=1;i<=1000000;i++){
            //赋值
            users[index++]="user_"+i;
            //每1000条发送一次
            if(i%1000==0){
                index=0;
                stringRedisTemplate.opsForHyperLogLog().add("hl2",users);
            }
        }
        //统计数量
        Long hl2 = stringRedisTemplate.opsForHyperLogLog().size("hl2");
        System.out.println(hl2);
    }

这个测试方法一直运行失败,我真的吐了.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/231156.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker build 无法解析域名

### 报错 Docker build 无法解析域名 报错&#xff1a;ERROR [ 2/12] RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo 解决Docker build无法解析域名 # 追加到 etc/docker/daemon.json&#xff0c;注意JSON的格式 {"dn…

【GAMES101】观测变换

图形学不等于 OpenGL&#xff0c;不等于光线追踪&#xff0c;而是一套生成整个虚拟世界的方法 记得有个概念叫光栅化&#xff0c;就是把三维虚拟世界的事物显示在二维的屏幕上&#xff0c;这里就涉及到观察变换 观察变换&#xff0c;叫viewing transformation&#xff0c;包括…

基于Live555实现RtspServer及高清高码率视频传输优化

基于Live555实现RtspServer及高清高码率视频传输优化 最近做了一些pc和嵌入式平台的RTSP服务器项目&#xff0c;大多数的要求是简单但是功能全面&#xff0c;并且性能还要强劲。综合考虑后&#xff0c;基本都是在基于live555的基础上进行开发&#xff0c;在进行Live555本身的优…

前端-杂记

1 子域请求时候会默认带上父域下的Coolkie 2 document.cookie 设置cookie只能设置当前域和父域&#xff0c;且path只能是当前页或者/ 比如当前页面地址为 http://localhost:3000/about 我们设置 document.cookie "demo11"; 设置 document.cookie "demo22; …

[ROS2] --- param

1 param介绍 类似C编程中的全局变量&#xff0c;可以便于在多个程序中共享某些数据&#xff0c;参数是ROS机器人系统中的全局字典&#xff0c;可以运行多个节点中共享数据。 全局字典 在ROS系统中&#xff0c;参数是以全局字典的形态存在的&#xff0c;什么叫字典&#xff1f;…

Ubunutu18.04 ROS melodic 无人机 XTDrone PX4 仿真平台配置

一、依赖安装 sudo apt install ninja-build exiftool ninja-build protobuf-compiler libeigen3-dev genromfs xmlstarlet libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev python-pip python3-pip gawk pip2 install pandas jinja2 pyserial cerberus pyulog0.7.0 n…

【uC/OS-II】

uC/OS-II 1. uC/OS-II1.1 代码组成1.2 任务基本概念1.3 任务控制块![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/23fe7cd390b94b7eb06a110b10165d22.png)1.4 任务的状态与切换1.5 任务创建的代码 2 任务2.1 系统任务2.2 任务管理相关函数2.3 任务基本属性2.4 uC/…

IP地址定位技术:追踪位置、识别风险

随着互联网的普及&#xff0c;IP地址定位技术逐渐成为网络安全领域的一项重要工具。通过追踪IP地址位置&#xff0c;可以识别潜在的风险用户&#xff0c;加强网络安全。本文将深入研究IP地址定位技术的原理、应用以及相关的风险与防范。 1. IP地址定位技术的原理&#xff1a; …

架构面试:全链路压测,你是怎么设计的?

尼恩说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;很多小伙伴拿到一线互联网企业、上市企业如阿里、网易、有赞、希音、百度、滴滴的面试资格。 就在前几天&#xff0c;尼恩的指导一个 30岁小伙拿到一个工业互联网上市企业55W年薪的offer&#xff0c;是架构师…

Python数据处理的六种方式总结,Python零基础学习

文章目录 前言1、dedup()去重并排序2、traverse()拆分嵌套数组3、filter()数据筛选4、groupby()分组运算5、select()遍历结果集6、sort()数据排序 总结 前言 在 Python 的数据处理方面经常会用到一些比较常用的数据处理方式&#xff0c;比如pandas、numpy等等。 今天介绍的这…

AI文档助手,当下热门的AI文档助手【2024】

在当今信息爆炸的时代&#xff0c;文档创作的需求愈发庞大。为了满足用户对高效、准确、原创性文档的需求&#xff0c;人工智能技术的应用日益广泛。本文将专心分享AI文档助手领域的热门推荐。 AI文档助手的背景与应用 AI文档助手作为人工智能技术在文档创作领域的一大应用&am…

跨平台的文本编辑器——CudaText

CudaText 是一个轻量级、跨平台的文本编辑器&#xff0c;它免费开源&#xff0c;启动速度非常快&#xff0c;有拓展功能&#xff0c;可安装插件。 下载 浏览器搜索框输入CudaText - Home进行搜索&#xff0c; 选择官网进入&#xff0c; 进入官网界面如下&#xff1a;选择点击…

孩子都能学会的FPGA:第二十六课——用FPGA实现CIC抽取滤波器

&#xff08;原创声明&#xff1a;该文是作者的原创&#xff0c;面向对象是FPGA入门者&#xff0c;后续会有进阶的高级教程。宗旨是让每个想做FPGA的人轻松入门&#xff0c;作者不光让大家知其然&#xff0c;还要让大家知其所以然&#xff01;每个工程作者都搭建了全自动化的仿…

windows系统如何解决爆满C盘

目录 方法一&#xff1a;清理临时文件 方法二&#xff1a;清理临时文件 方法三&#xff1a;清理系统更新文件 方法四&#xff1a; 设置自动清理无用文件 4.1 清理缓存 4.2 打开存储感知 4.3 调整新内容存储地方 方法一&#xff1a;清理临时文件 代码&#xff1a;win …

Python框架篇(4):FastApi-错误处理

提示: 微信搜索【猿码记】回复 【fastapi】即可获取源码信息~ 1.验证错误 1.1 默认返回 当传参不符合模型验证规则时&#xff0c;默认错误信息和格式返回如下: { "detail": [ { "loc": [ "body", "age" …

22、pytest多个参数化的组合

官方实例 # content of test_multi_parametrie.py import pytestpytest.mark.parametrize("x",[0,1]) pytest.mark.parametrize("y",[2,3]) def test_foo(x,y):print("{}-{}".format(x,y))pass解读与实操 要获得多个参数化参数的所有组合&…

科学指南针助力江西高校开展《透射电子显微镜简介及案例分析课程》讲座

2023年11月&#xff0c;科学指南针与江西各大高校合作&#xff0c;共同开展了一场关于《透射电子显微镜的简介及案例分析课程》讲座。该讲座旨在加强学生对于透射电子显微镜的了解&#xff0c;提高他们在科学研究中的实践能力。 透射电子显微镜&#xff08;简称TEM&#xff09…

【LeetCode】每日一题 2023_12_9 下一个更大的数值平衡数(枚举/打表二分)

文章目录 刷题前唠嗑题目&#xff1a;下一个更大的数值平衡数题目描述代码与解题思路官方解法 结语 刷题前唠嗑 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 题目&#xff1a;下一个更大的数值平衡数 题目链接&#xff1a;2048. 下一个更大的数值平衡数 …

C++11原子操作atomic

文章目录 原子操作atomic原子操作的相关函数原子操作的特点“平凡的”与“合格的” 原子操作atomic 前面我们介绍了互斥锁等一系列多线程相关操作&#xff0c;这里我们来说下原子操作atomic。 可以理解为原子变量就是将上面的操作进行了整合的一个全新变量&#xff0c;但是实际…

Qt 容器QGroupBox带有标题的组框框架

控件简介 QGroupBox 小部件提供一个带有标题的组框框架。一般与一组或者是同类型的部件一起使用。教你会用,怎么用的强大就靠你了靓仔、靓妹。 用法示例 例 qgroupbox,组框示例(难度:简单),使用 3 个 QRadioButton 单选框按钮,与QVBoxLayout(垂直布局)来展示组框的…