java抽奖系统(七)

news2024/12/15 6:10:37

8. 抽奖活动

8.1 新建抽奖活动

创建的活动信息包含:

           i. 活动名称 

          ii. 活动描述

         iii. 圈选奖品:勾选对应奖品,并设置奖品等级(⼀⼆三等奖),及奖品数量

         iv. 圈选⼈员:勾选参与抽奖⼈员

库表关联分析如下所示: 

时序图如下: 

 

 将完整的信息放入到redis目的:

1、为了抽奖的时候确定抽奖的活动是哪一个。

2、活动+关联奖品+关联人员的完整信息,就是为了抽奖,根据关联的人员去进行抽奖。为了达到高效的目的,将完整的信息放入到缓存中、

8.2 后端代码实现

约定前后端交互接⼝:

8.2.1 创建活动的请求参数

@Data
public class CreateActivityParam implements Serializable {
    //活动名称
    @NotBlank(message = "活动名称不能为空!")
    private String activityName;
    //活动描述
    @NotBlank(message = "活动描述不能为空!")
    private String description;
    //活动关联奖品列表
    @NotEmpty(message = "活动关联奖品列表不能为空!")
    //list是容器,使用notempty的注解
    @Valid
    //这个valid注解就是备注列表中的对象的参数的相关不能为空的注解可以生效
    private List<CreatePrizeByActivityParam> activityPrizeList;
    //活动关联人员列表
    @NotEmpty(message = "活动关联人员列表不能为空!")
    @Valid
    private List<CreateUserByActivityParam> activityUserList;
}

8.2.2 创建活动奖品关联表的请求参数

@Data
public class CreatePrizeByActivityParam implements Serializable {
    /**
     * 活动关联的奖品id
     */
    @NotNull(message = "活动关联的奖品id不能为空!")
    private Long prizeId;
    /**
     * 奖品数量
     */
    @NotNull(message = "奖品数量不能为空!")
    private Long prizeAmount;
    /**
     * 奖品等奖
     */
    @NotBlank(message = "奖品等奖不能为空!")
    private String prizeTiers;
}

 8.2.3 创建活动人员关联表的请求参数

@Data
public class CreateUserByActivityParam implements Serializable {
    /**
     * 活动关联的人员id
     */
    @NotNull(message = "活动关联的人员id不能为空!")
    private Long userId;
    /**
     * 姓名
     */
    @NotBlank(message = "姓名不能为空!")
    private String userName;
}

8.2.4 活动奖品状态的枚举

@AllArgsConstructor
@Getter
public enum ActivityPrizeStatusEnum {
    INIT(1, "初始化"),

    COMPLETED(2, "已被抽取");


    private final Integer code;

    private final String message;

    public static ActivityPrizeStatusEnum forName(String name) {
        for (ActivityPrizeStatusEnum activityPrizeStatusEnum : ActivityPrizeStatusEnum.values()) {
            if (activityPrizeStatusEnum.name().equalsIgnoreCase(name)) {
                return activityPrizeStatusEnum;
            }
        }
        return null;
    }
}

 8.2.5  活动奖品等级的枚举

@AllArgsConstructor
@Getter
public enum ActivityPrizeTiersEnum {

    FIRST_PRIZE(1, "一等奖"),

    SECOND_PRIZE(2, "二等奖"),

    THIRD_PRIZE(3, "三等奖");

    private final Integer code;

    private final String message;

    public static ActivityPrizeTiersEnum forName(String name) {
        for (ActivityPrizeTiersEnum activityPrizeTiersEnum : ActivityPrizeTiersEnum.values()) {
            if (activityPrizeTiersEnum.name().equalsIgnoreCase(name)) {
                return activityPrizeTiersEnum;
            }
        }
        return null;
    }

}

 8.2.6 controller接口设计

@RestController
public class ActivityController {

    @Autowired
    private ActivityService activityService;
    private static final Logger logger = LoggerFactory.getLogger(ActivityController.class);

    //创建活动
    @RequestMapping("/activity/create")
    public CommonResult<CreateActivityResult> createActivity(
            @Validated @RequestBody CreateActivityParam param) {
        logger.info("ActivityController createActivity CreateActivityParam:{}",
                JacksonUtil.writeValueAsString(param));
        return CommonResult.success(
                convertToCreateActivityResult(activityService.createActivity(param)));
    }


    private CreateActivityResult convertToCreateActivityResult(CreateActivityDTO createActivityDTO) {
        if (createActivityDTO == null) {
            throw new ControllerException(ControllerErrorCodeConstants.CREATE_ACTIVITY_ERROR);
        }
        CreateActivityResult result = new CreateActivityResult();
        result.setActivityId(createActivityDTO.getActivityId());
        return result;
    }
}

8.2.7 service接口及其实现

public interface ActivityService {
    //创建活动
    CreateActivityDTO createActivity(CreateActivityParam param);
}


@Service
public class ActivityServiceImpl implements ActivityService {
    private static final Logger logger = LoggerFactory.getLogger(ActivityServiceImpl.class);

    /**
     * 活动缓存前置,为了区分业务
     */
    private final String ACTIVITY_PREFIX = "ACTIVITY_";
    /**
     * 活动缓存过期时间
     */
    private final Long ACTIVITY_TIMEOUT = 60 * 60 * 24 * 60L;//60天
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PrizeMapper prizeMapper;
    @Autowired
    private ActivityMapper activityMapper;
    @Autowired
    private ActivityUserMapper activityUserMapper;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Override
    @Transactional(rollbackFor = Exception.class)
    // 因为涉及多表,所以要进行本地事务回滚,防治出现下面情况
    //第二部,活动信息保存了
    //但是第三四部,活动相关联的表的信息保存失败,就要进行活动回滚
    public CreateActivityDTO createActivity(CreateActivityParam param) {
        // 校验活动信息是否正确
        checkActivityInfo(param);
        //校验失败就直接抛异常抛出去

        // 保存活动信息
        ActivityDO activityDO = new ActivityDO();
        activityDO.setActivityName(param.getActivityName());
        activityDO.setDescription(param.getDescription());
        activityDO.setStatus(ActivityStatusEnum.RUNNING.name());
        activityMapper.insert(activityDO);

        // 保存活动关联的奖品信息
        List<CreatePrizeByActivityParam> prizeParams = param.getActivityPrizeList();
        List<ActivityPrizeDO> activityPrizeDOList = prizeParams.stream()
                .map(prizeParam -> {
                    ActivityPrizeDO activityPrizeDO = new ActivityPrizeDO();
                    activityPrizeDO.setActivityId(activityDO.getId());
                    activityPrizeDO.setPrizeId(prizeParam.getPrizeId());
                    activityPrizeDO.setPrizeAmount(prizeParam.getPrizeAmount());
                    activityPrizeDO.setPrizeTiers(prizeParam.getPrizeTiers());
                    activityPrizeDO.setStatus(ActivityPrizeStatusEnum.INIT.name());
                    return activityPrizeDO;
                }).collect(Collectors.toList());
        activityPrizeMapper.batchInsert(activityPrizeDOList);
        // 保存活动关联的人员信息
        List<CreateUserByActivityParam> userParams = param.getActivityUserList();
        List<ActivityUserDO> activityUserDOList = userParams.stream()
                .map(userParam -> {
                    ActivityUserDO activityUserDO = new ActivityUserDO();
                    activityUserDO.setActivityId(activityDO.getId());
                    activityUserDO.setUserId(userParam.getUserId());
                    activityUserDO.setUserName(userParam.getUserName());
                    activityUserDO.setStatus(ActivityUserStatusEnum.INIT.name());
                    return activityUserDO;
                }).collect(Collectors.toList());
        activityUserMapper.batchInsert(activityUserDOList);
        // 整合完整的活动信息,存放 redis
        // activityId: ActivityDetailDTO:活动+奖品+人员
        // 先获取奖品基本属性列表
        // 获取需要查询的奖品id
        List<Long> prizeIds = param.getActivityPrizeList().stream()
                .map(CreatePrizeByActivityParam::getPrizeId)
                .distinct()
                .collect(Collectors.toList());
        List<PrizeDO> prizeDOList = prizeMapper.batchSelectByIds(prizeIds);

        ActivityDetailDTO detailDTO = convertToActivityDetailDTO(activityDO, activityUserDOList,
                prizeDOList, activityPrizeDOList);
        //放入redis缓存
        cacheActivity(detailDTO);

        // 构造返回
        CreateActivityDTO createActivityDTO = new CreateActivityDTO();
        createActivityDTO.setActivityId(activityDO.getId());
        return createActivityDTO;
    }

    /**
     * 缓存完整的活动信息 ActivityDetailDTO
     *
     * @param detailDTO
     */
    private void cacheActivity(ActivityDetailDTO detailDTO) {
        // key: ACTIVITY_12
        // value: ActivityDetailDTO(json)
        if (detailDTO == null || detailDTO.getActivityId() == null) {
            logger.warn("要缓存的活动信息不存在!");
            return;
        }

        try {
            redisUtil.set(ACTIVITY_PREFIX + detailDTO.getActivityId(),
                    JacksonUtil.writeValueAsString(detailDTO), ACTIVITY_TIMEOUT);
        } catch (Exception e) {
            logger.error("缓存活动异常,ActivityServiceImpl ActivityDetailDTO={}",
                    JacksonUtil.writeValueAsString(detailDTO), e);
        }
    }
    /**
     * 根据活动id从缓存中获取活动详细信息
     * @param activityId
     * @return
     */
    private ActivityDetailDTO getActivityFromCache(Long activityId) {
        if (activityId == null) {
            logger.warn("获取缓存活动数据的activityId为空!");
            return null;
        }
        try {
            String str = redisUtil.get(ACTIVITY_PREFIX + activityId);
            if (!StringUtils.hasText(str)) {
                logger.info("获取的缓存活动数据为空!key={}", ACTIVITY_PREFIX + activityId);
                return null;
            }
            return JacksonUtil.readValue(str, ActivityDetailDTO.class);
        } catch (Exception e) {
            logger.error("从缓存中获取活动信息异常,key={}", ACTIVITY_PREFIX + activityId, e);
            return null;
        }
    }


    /**
     * 根据基本DO整合完整的活动信息ActivityDetailDTO
     *
     * @param activityDO
     * @param activityUserDOList
     * @param prizeDOList
     * @param activityPrizeDOList
     * @return
     */
    private ActivityDetailDTO convertToActivityDetailDTO(ActivityDO activityDO,
                                                         List<ActivityUserDO> activityUserDOList,
                                                         List<PrizeDO> prizeDOList,
                                                         List<ActivityPrizeDO> activityPrizeDOList) {
        ActivityDetailDTO detailDTO = new ActivityDetailDTO();
        detailDTO.setActivityId(activityDO.getId());
        detailDTO.setActivityName(activityDO.getActivityName());
        detailDTO.setDesc(activityDO.getDescription());
        detailDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));

        // apDO: {prizeId,amount, status}, {prizeId,amount, status}
        // pDO: {prizeid, name....},{prizeid, name....},{prizeid, name....}
        List<ActivityDetailDTO.PrizeDTO> prizeDTOList = activityPrizeDOList
                .stream()
                .map(apDO -> {
                    ActivityDetailDTO.PrizeDTO prizeDTO = new ActivityDetailDTO.PrizeDTO();
                    prizeDTO.setPrizeId(apDO.getPrizeId());
                    Optional<PrizeDO> optionalPrizeDO = prizeDOList.stream()
                            .filter(prizeDO -> prizeDO.getId().equals(apDO.getPrizeId()))
                            .findFirst();
                    //将第二行的每一个pdo和第一个的apdo根据奖品id进行比较,
                    //得到同id的第二行的第一个pdo
                    // 如果PrizeDO为空,不执行当前方法,不为空才执行
                    optionalPrizeDO.ifPresent(prizeDO -> {
                        prizeDTO.setName(prizeDO.getName());
                        prizeDTO.setImageUrl(prizeDO.getImageUrl());
                        prizeDTO.setPrice(prizeDO.getPrice());
                        prizeDTO.setDescription(prizeDO.getDescription());
                    });
                    prizeDTO.setTiers(ActivityPrizeTiersEnum.forName(apDO.getPrizeTiers()));
                    prizeDTO.setPrizeAmount(apDO.getPrizeAmount());
                    prizeDTO.setStatus(ActivityPrizeStatusEnum.forName(apDO.getStatus()));
                    return prizeDTO;
                }).collect(Collectors.toList());
        detailDTO.setPrizeDTOList(prizeDTOList);

        List<ActivityDetailDTO.UserDTO> userDTOList = activityUserDOList.stream()
                .map(auDO -> {
                    ActivityDetailDTO.UserDTO userDTO = new ActivityDetailDTO.UserDTO();
                    userDTO.setUserId(auDO.getUserId());
                    userDTO.setUserName(auDO.getUserName());
                    userDTO.setStatus(ActivityUserStatusEnum.forName(auDO.getStatus()));
                    return userDTO;
                }).collect(Collectors.toList());
        detailDTO.setUserDTOList(userDTOList);
        return detailDTO;
    }




    //校验活动有效性
    private void checkActivityInfo(CreateActivityParam param) {
        //虽然在controller层已经进行非空判断,但是为了解耦,在service层要进行再次判断
        if (param == null) {
            throw new ServiceException(ServiceErrorCodeConstants.CREATE_ACTIVITY_INFO_IS_EMPTY);
        }
        //校验维度一
        // 人员id在人员表中是否存在
        // 1 2 3  ->  1 2
        List<Long> userIds = param.getActivityUserList()
                .stream()
                .map(CreateUserByActivityParam::getUserId)
                .distinct()//去重id
                .collect(Collectors.toList());
        //数据表中真实存在的id
        List<Long> existUserIds = userMapper.selectExistByIds(userIds);
        if (CollectionUtils.isEmpty(existUserIds)) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_USER_ERROR);
        }
        userIds.forEach(id -> {
            if (!existUserIds.contains(id)) {
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_USER_ERROR);
            }
        });
        //校验维度二
        // 奖品id在奖品表中是否存在
        List<Long> prizeIds = param.getActivityPrizeList()
                .stream()
                .map(CreatePrizeByActivityParam::getPrizeId)
                .distinct()
                .collect(Collectors.toList());
        List<Long> existPrizeIds = prizeMapper.selectExistByIds(prizeIds);
        if (CollectionUtils.isEmpty(existPrizeIds)) {
            throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR);
        }
        prizeIds.forEach(id -> {
            if (!existPrizeIds.contains(id)) {
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_ERROR);
            }
        });
        //校验维度三
        // 人员数量大于等于奖品数量,奖励不会被抽完
        // 2个奖品 2 1
        int userAmount = param.getActivityUserList().size();
        long prizeAmount = param.getActivityPrizeList()
                .stream()
                .mapToLong(CreatePrizeByActivityParam::getPrizeAmount) // 2 1
                .sum();
        if (userAmount < prizeAmount) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_PRIZE_AMOUNT_ERROR);
        }
        // 校验活动奖品等奖有效性
        param.getActivityPrizeList().forEach(prize -> {
            if (ActivityPrizeTiersEnum.forName(prize.getPrizeTiers()) == null) {
                throw new ServiceException(ServiceErrorCodeConstants.ACTIVITY_PRIZE_TIERS_ERROR);
            }
        });
    }
}

8.2.8 dao层

 

@Mapper
public interface ActivityMapper {
    @Insert("insert into activity (activity_name, description, status)" +
            " values (#{activityName}, #{description}, #{status})")
    @Options(useGeneratedKeys = true, keyProperty ="id", keyColumn ="id")
    int insert(ActivityDO activityDO);
}

@Mapper
public interface ActivityPrizeMapper {
    @Insert("<script>" +
            " insert into activity_prize (activity_id, prize_id, prize_amount, prize_tiers, status)" +
            " values <foreach collection = 'items' item='item' index='index' separator=','>" +
            " (#{item.activityId}, #{item.prizeId}, #{item.prizeAmount}, #{item.prizeTiers}, #{item.status})" +
            " </foreach>" +
            " </script>")
    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
    int batchInsert(@Param("items") List<ActivityPrizeDO> activityPrizeDOList);
}

@Mapper
public interface ActivityUserMapper {
    @Insert("<script>" +
            " insert into activity_user (activity_id, user_id, user_name, status)" +
            " values <foreach collection = 'items' item='item' index='index' separator=','>" +
            " (#{item.activityId}, #{item.userId}, #{item.userName}, #{item.status})" +
            " </foreach>" +
            " </script>")
    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
    int batchInsert(@Param("items") List<ActivityUserDO> activityUserDOList);
}

8.3  论相关事务的回滚

论表与表之间之间事务的回滚:

从管理角度看:

        活动信息表完成注入,活动关联奖品表和活动关联人员表,这三表是出于一个事务的状态,其中但凡有一个表的相关信息没有成功注入,就应该回滚到三个表都没有信息注入的状态;

        但是前三表信息无误之后,将完整的活动信息保存到redis这个操作是否要和三个表注入处于一个事物?

从后续抽奖角度:

请求查找活动抽奖后的完整信息,前往redis发现这里面表的状态是空白,就会接下来前往后面处于一个事务的三个表对相关信息进行查询,并将这些信息返回到redis之后再回返给请求;所以可以不处于一个事物中;

8.4 后端测试

不合法的人员id和奖品id进行测试: 

正确的人员和奖品id进行测试:

 

redis缓存信息,活动id为26

数据库activity如下所示:

8.5 前端后端交互测试

 完善前端页面,代码见码云,进行测试:

创建成功并跳转到活动列表页面:

redis活动信息存储如下:

活动库表信息存储:

 8.6 抽奖活动列表创建

        活动列表支持翻页

8.6.1 时序图

8.6.2 前后端交互

8.6.3 后端代码实现

controller:

 @RequestMapping("/activity/find-list")
    public CommonResult<FindActivityListResult> findActivityList(PageParam param) {
        logger.info("ActivityController findActivityList PageParam:{}",
                JacksonUtil.writeValueAsString(param));
        return CommonResult.success(
                convertToFindActivityListResult(
                        activityService.findActivityList(param)));
    }

    private FindActivityListResult convertToFindActivityListResult(
            PageListDTO<ActivityDTO> activityList) {
        if (activityList == null) {
            throw new ControllerException(ControllerErrorCodeConstants.FIND_ACTIVITY_LIST_ERROR);
        }
        FindActivityListResult result = new FindActivityListResult();
        result.setTotal(activityList.getTotal());
        result.setRecords(
                activityList.getRecords()
                        .stream()
                        .map(activityDTO -> {
                            FindActivityListResult.ActivityInfo activityInfo = new FindActivityListResult.ActivityInfo();
                            activityInfo.setActivityId(activityDTO.getActivityId());
                            activityInfo.setActivityName(activityDTO.getActivityName());
                            activityInfo.setDescription(activityDTO.getDescription());
                            activityInfo.setValid(activityDTO.valid());
                            return activityInfo;
                        }).collect(Collectors.toList())
        );
        return result;
    }

service:

 PageListDTO<ActivityDTO> findActivityList(PageParam param);

    @Override
    public PageListDTO<ActivityDTO> findActivityList(PageParam param) {
        // 获取总量
        int total = activityMapper.count();

        // 获取当前页列表
        List<ActivityDO> activityDOList = activityMapper.selectActivityList(param.offset(),
                param.getPageSize());
        List<ActivityDTO> activityDTOList = activityDOList.stream()
                .map(activityDO -> {
                    ActivityDTO activityDTO = new ActivityDTO();
                    activityDTO.setActivityId(activityDO.getId());
                    activityDTO.setActivityName(activityDO.getActivityName());
                    activityDTO.setDescription(activityDO.getDescription());
                    activityDTO.setStatus(ActivityStatusEnum.forName(activityDO.getStatus()));
                    return activityDTO;
                }).collect(Collectors.toList());
        return new PageListDTO<>(total, activityDTOList);
    }

dao:


    @Select("select count(1) from activity")
    int count();

    @Select("select * from activity order by id desc limit #{offset}, #{pageSize}")
    List<ActivityDO> selectActivityList(@Param("offset") Integer offset,
                                        @Param("pageSize") Integer pageSize);

使用postman进行测试:

返回结果如下:

{
    "code": 200,
    "data": {
        "total": 4,
        "records": [
            {
                "activityId": 27,
                "activityName": "抽奖活动3.0",
                "description": "抽奖活动3.0",
                "valid": true
            },
            {
                "activityId": 26,
                "activityName": "测试抽奖活动2.0",
                "description": "测试抽奖活动2.0",
                "valid": true
            },
            {
                "activityId": 25,
                "activityName": "平安夜抽奖活动",
                "description": "平安夜抽奖活动",
                "valid": true
            },
            {
                "activityId": 24,
                "activityName": "抽奖的活动",
                "description": "测试抽奖的活动",
                "valid": true
            }
        ]
    },
    "msg": ""
}

8.6.4 前端代码完善

前后端交互测试:

ps:谢谢观看。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity学习笔记(一)如何实现物体之间碰撞

前言 本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记 如何实现物体之间碰撞 实现物体之间的碰撞关键组件&#xff1a;Rigidbody 2D(刚体)、Collider 2D(碰撞体)、Sprite Renderer&#xff08;Sprite渲染器&#xff09; 实现物体之间的碰撞 …

MATLAB 平面直线与直线求交(99)

MATLAB 平面直线与直线求交(99) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 平面上,给定两直线,直线由两个点确定,计算直线与直线的交点,理论上只要不平行就有交点,下面是计算代码和效果: 二、算法实现 1.代码 代码如下(示例): % 示例用法 % 定义两条线…

STM32单片机芯片与内部21 电源管理——低功耗 睡眠模式 停止模式 待机模式

目录 一、SMT32电源框图 1、ADC电源与参考电压VDDA 2、调压器供电电路VDD/1.8V 3、备份域电路 二、电源监控器 1、上电复位与掉电复位&#xff08;POR与PDR&#xff09; 2、可编程电压检测器 PVD 三、功耗模式 1、睡眠模式 2、停止模式 3、待机模式 电源对电子设备的…

数智读书笔记系列006 协同进化:人类与机器融合的未来

书名:协同进化&#xff1a;人类与机器融合的未来 作者:[美]爱德华阿什福德李 译者:李杨 出版时间:2022-06-01 ISBN:9787521741476 中信出版集团制作发行 爱德华・阿什福德・李&#xff08;Edward Ashford Lee&#xff09;是一位在计算机科学与工程领域颇具影响力的学者&am…

计算机网络知识点全梳理(一.TCP/IP网络模型)

目录 TCP/IP网络模型概述 应用层 什么是应用层 应用层功能 应用层协议 传输层 什么是传输层 传输层功能 传输层协议 网络层 什么是网络层 网络层功能 网络层协议 数据链路层 什么是数据链路层 数据链路层功能 物理层 物理层的概念和功能 TCP/IP网络模型概述…

docker启动一个helloworld(公司内网服务器)

这里写目录标题 容易遇到的问题&#xff1a;1、docker连接问题 我来介绍几种启动 Docker Hello World 的方法&#xff1a; 最简单的方式&#xff1a; docker run hello-world这会自动下载并运行官方的 hello-world 镜像。 使用 Nginx 作为 Hello World&#xff1a; docker…

Ubuntu 安装texstudio sty与texlive

手动安装需要的包 访问CTAN网站&#xff08;Comprehensive TeX Archive Network&#xff09;并下载enumitem宏包&#xff1a; enumitem CTAN页面下载后&#xff0c;将宏包解压到/usr/share/texmf/tex/latex/下。 可打开texstudio/帮助/宏包帮助下载。 如果不想手动安装一个个…

游戏引擎学习第42天

仓库: https://gitee.com/mrxiao_com/2d_game 简介 目前我们正在研究的内容是如何构建一个基本的游戏引擎。我们将深入了解游戏开发的每一个环节&#xff0c;从最基础的技术实现到高级的游戏编程。 角色移动代码 我们主要讨论的是角色的移动代码。我一直希望能够使用一些基…

SEGGER | 基于STM32F405 + Keil - RTT组件01 - 移植SEGGER RTT

导言 RTT(Real Time Transfer)是一种用于嵌入式中与用户进行交互的技术&#xff0c;它结合了SWO和半主机的优点&#xff0c;具有极高的性能。 使用RTT可以从MCU非常快速输出调试信息和数据&#xff0c;且不影响MCU实时性。这个功能可以用于很多支持J-Link的设备和MCU&#xff0…

【01】mysql安装后MySQL Configurator无法启动的问题

安装完Mysql之后打开MySql Configurator提示MySQL Configurator Internal error.(值不能为null.参数名:input) The Configurator will now close. mysql安装后MySQL Configurator无法启动的问题 文章目录 mysql安装后MySQL Configurator无法启动的问题1.MySQL Configurator无法…

重生之我在异世界学编程之C语言:深入文件操作篇(下)

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 函数递归与迭代 引言正文一、文件的基本操作&#…

【论文阅读笔记】One Diffusion to Generate Them All

One Diffusion to Generate Them All 介绍理解 引言二、相关工作三、方法预备知识训练推理实现细节训练细节 数据集构建实验分结论附录 介绍 Paper&#xff1a;https://arxiv.org/abs/2411.16318 Code&#xff1a;https://github.com/lehduong/onediffusion Authors&#xff1…

Qt知识之 2. Windows下使用QtCreator创建的CMake项目,配置CMakeLists.txt文件生成sln文件方案

1. 先使用QtCreator创建CMake项目 到构建系统时&#xff0c;选择CMake。 2. 创建完成后&#xff0c;进入该项目文件夹 3. 在该文件夹空白处&#xff0c;右键启动Powershell命令行窗口 4. 使用命令行前&#xff0c;记得在系统环境变量中配置所用编译器的环境变量&#xff0c;…

C语言实验 函数一

时间:2024.12.14 6-1 弹球距离 double dist (double h,double p) {double sum = h,height;height = h*p;while(height>=TOL){sum += height * 2; //上行下行都算,所以是两倍的距离。height *=p;}return sum; } 6-2 使用函数输出一个整数的逆序数 错误代码:运行超…

【C语言实现:用队列模拟栈与用栈模拟队列(LeetCode 225 232)】

LeetCode刷题记录 &#x1f310; 我的博客主页&#xff1a;iiiiiankor&#x1f3af; 如果你觉得我的内容对你有帮助&#xff0c;不妨点个赞&#x1f44d;、留个评论✍&#xff0c;或者收藏⭐&#xff0c;让我们一起进步&#xff01;&#x1f4dd; 专栏系列&#xff1a;LeetCode…

STM32标准库学习之寄存器方法点亮LED灯

STM32C8T6最小系统开发板&#xff0c;点亮PC13引脚的LED灯 1.使能PC13引脚的定时器 PC13引脚为GPIOC组的第13个端口&#xff0c;GPIO的时钟使能定时器为RCC_APB2ENR&#xff0c;这是可以从手册中得出的&#xff0c;如下图所示 从下图可以得出&#xff0c;若要使能GPIOC端口&a…

探索 Echarts 绘图:数据可视化的奇妙之旅

目录 一、Echarts 初印象 二、搭建 Echarts 绘图环境 三、绘制第一个图表&#xff1a;柱状图的诞生 四、图表的美化与定制&#xff1a;让数据更具吸引力 1. 主题切换&#xff1a;一键变换风格 2. 颜色调整&#xff1a;色彩搭配的艺术 3. 标签与提示框&#xff1a;丰富信…

泷羽sec-burp(6)暴力破解与验证码识别绕过(下,验证码识别绕过0) 学习笔记

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

docker快速实现ELK的安装和使用

目录 一、ELK功能原理 二、项目功能展示​ 三、日志查询展示​ 四、ELK安装步骤 1、创建elasticsearch、kibana、filebeat相关data、log、conf目录 2、进入/usr/local/elk目录&#xff0c;并创建一个docker网络 3、启动 elasticsearch容器 4、运行kibana容器 5、启动f…

onnx算子的注册详解及案例 (完整版)

文章目录 1. 介绍1.1 导出onnx不成功1.2 分析和解决方案2. 案例2.1 Asinh算子注册2.1.1 导出onnx2.1.2 算子注册2.2 自定义算子的注册2.1 直接导出自定义算子2.2 自定义算子的注册并导出2.3 导出带deformable conv 的onnx2.3.1 直接导出deformable conv2.3.2 注册并导出deforma…