java抽奖系统(一)2.0

 1. 项⽬介绍

1.1 背景

        随着数字营销的兴起,企业越来越重视通过在线活动来吸引和留住客⼾。抽奖活动作为⼀种有效的营 销⼿段,能够显著提升⽤⼾参与度和品牌曝光率。于是我们就开发了以抽奖活动作为背景的Spring Boot项⽬,通过这个项⽬提供⼀个全⾯、可靠、易于维护的抽奖平台,该平台将采⽤以下策略:

         集成多种技术组件:利⽤MySQL、Redis、RabbitMQ等常⽤组件,构建⼀个稳定、⾼效、可扩展 的抽奖系统。

        活动、奖品与⼈员管理:允许管理员创建配置抽奖活动;管理奖品信息;管理⼈员信息。

         实现状态机管理:通过精⼼设计的状态机,精确控制活动及奖品状态的转换,提⾼系统的可控性和 可预测性。

         保障数据⼀致性:通过事务管理和数据同步机制,确保数据的⼀致性和完整性。

        加强安全性:实施安全措施,包括数据加密、⽤⼾认证,保护⽤⼾数据和系统安全。

        降低维护成本:提供全⾯的⽇志记录和异常处理机制,简化问题诊断和系统维护。

         提⾼扩展性:采⽤模块化设计与设计模式的使⽤,提⾼系统的灵活性和扩展性。

1.2 需求描述

        1. 包含管理员的注册与登录。

        a. 注册包含:姓名、邮箱、⼿机号、密码

        b. 登录包含两种⽅式:

                 i. 电话+密码登录;

                ii. 电话+短信登录; 验证码获取

                iii. 登录需要校验管理员⾝份。

        2. ⼈员管理:管理员⽀持创建普通⽤⼾,查看⽤⼾列表

                a. 创建普通⽤⼾:姓名,邮箱,⼿机号

                b. ⼈员列表:⼈员id、姓名、⾝份(普通⽤⼾、管理员)

        3. 管理端⽀持创建奖品、奖品列表展⽰功能。

                a. 创建的奖品信息包含:奖品名称、描述、价格、奖品图(上传)

                 b. 奖品列表展⽰(可翻⻚):奖品id、奖品图、奖品名、奖品描述、奖品价值(元)

        4. 管理端⽀持创建活动、活动列表展⽰功能。

                 a. 创建的活动信息包含:

                        i. 活动名称

                        ii. 活动描述

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

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

                b. 活动列表展⽰(可翻⻚):

                         i. 活动名称

                         ii. 描述 

                        iii. 活动状态:

                                1. 活动状态为进⾏中:点击"活动进⾏中,去抽奖"按钮跳转抽奖⻚

                                2. 活动状态为已完成:点击"活动已完成,查看中奖名单"按钮跳转抽奖⻚查看结果

        5. 抽奖⻚⾯:

                a. 对于进⾏中的活动,管理员才可抽奖。

                b. 每轮抽奖的中奖⼈数跟随当前奖品数量。

                c. 每个⼈只能中⼀次奖

                d. 多轮抽奖,每轮抽奖有3个环节:展⽰奖品信息(奖品图、份数),⼈名闪动,停⽌闪动确定中 奖名单

                        i. 当前⻚展⽰奖品信息,点击‘开始抽奖’按钮,则跳转⾄⼈名闪动画⾯

                        ii. ⼈员闪动画⾯,点击’点我确定‘按钮,确认中奖名单。

                        iii. 当前⻚展⽰中奖名单,点击‘已抽完,下⼀步’按钮,若还有奖品未抽取,则展⽰下⼀个奖品 信息,否则展⽰全部中奖名单

                        iv. 点击’查看上⼀奖项‘按钮,展⽰上⼀个奖品信息

                e. 对于抽奖过程中的异常情况,如抽奖过程中刷新⻚⾯,要保证抽取成功的奖项不能重新抽取。

                        i. 刷新⻚⾯后,若当前奖品已抽完,点击"开始抽奖",则直接展⽰当前奖品中奖名单 f. 如该抽奖活动已完成:

                        ii. 展⽰所有奖项的全部中奖名单

                        iii. 新增"分享结果"按钮,点击可复制当前⻚链接,打开后隐藏其他按钮,只展⽰活动名称与中奖 结果,保留"分享结果"按钮

        6. 通知部分:抽奖完成需以邮件和短信⽅式通知中奖者。

                a. “Hi,xxx。恭喜你在xxx抽奖中获得⼀等奖:⼿机。中奖时间为:xx:xx。请尽快领取您的奖 品。”

        7. 管理端涉及的所有⻚⾯,包括抽奖⻚,需强制管理员登录后⽅可访问。

1.3 系统架构

前端:使⽤JavaScript管理各界⾯的动态性,使⽤AJAX技术从后端API获取数据。  

后端:采⽤SpringBoot3构建后端应⽤,实现业务逻辑。

数据库:使⽤MySQL作为主数据库,存储⽤⼾数据和活动信息。

缓存:使⽤Redis作为缓存层,减少数据库访问次数。

消息队列:使⽤RabbitMQ处理异步任务,如处理抽奖⾏为。

⽇志与安全:使⽤JWT进⾏⽤⼾认证,使⽤SLF4J+logback完成⽇志。 

1.4 项⽬环境

         编程语⾔:Java(后端),JavaScript(前端)。

        开发⼯具包:JDK17 (⻅《JDK17安装》⽂档)

        后端框架:SpringBoot3。

         数据库:MySQL。

        缓存:Redis。

         消息队列:RabbitMQ。

         ⽇志:logback。

         安全:JWT+加密。 

1.5 业务功能模块

⼈员业务模块:管理员注册、登录,及普通⽤⼾的创建。

活动业务模块:活动管理及活动状态管理。

 奖品业务模块:奖品管理与奖品的分配。还包括奖品图的上传。

 通知业务模块:发送短信、邮件等业务,例如验证码发送,中奖通知。

 抽奖业务模块:完成抽奖动作,以及抽奖后的结果展⽰;

1.6 数据库设计

 ⽤⼾表:存储⽤⼾信息,如⽤⼾名、密码、邮箱等。

活动表:存储活动信息,如活动名称、描述、活动状态等。

奖品表:存储奖品信息,如奖品名称、奖品图等。

活动奖品关联表:存储⼀个活动下关联了哪些奖品。

活动⽤⼾关联表:存储⼀个活动下设置的参与⼈员。

中奖记录表:存储⼀个活动的中奖名单,如活动id,奖品id,中奖者id等 

2.  数据库设计

2.1 表的关联图

sql代码略;

 2.2 使⽤source命令导⼊.sql⽂件

首先使用指令进入mysql:

mysql -u root -p

source指令一个sql脚本文件;

注意:使用的sql文件的绝对路径且在路径中不能有中文;

mysql> source E:\java_xiangmu\lottery_system\lottery_system.sql

结果如下:指令执行成功;

3. 新建项目

3.1 选择相应的框架

pom文件配置略:


3.2 代码结构设计

分层结构如下:

        上层依赖下层:

controller层(web层):接收来自前端的请求;

service层:里面含有具体的业务逻辑,是业务逻辑服务层;

数据持久层(dao层):数据访问层,与mysql进行数据交互;

common:通用处理层,只要存放util工具,config配置;

 

4. 功能模块设计

4.1 错误码

        我们对dao层不进行定义错误码(1、许多sql错误定义不出来;2、可以在service层包含一些dao层的错误),对controller层和servoce层进行定义错误码(分别对人员模块,活动模块,奖品模块,抽奖模块进行分别定义)

        由于errcode错误码是遍布两个层级,所以放在common通用层里面; errorcode类主要包含两个信息,一个是错误状态码code,另外一个是错误状态的信息msg;其次对于不同的层级来进行定义错误码;

        对于抓不到,没有思考到的错误,使用全局通用错误码来定义;

public interface GlobalErrorCodeConstants {
    ErrorCode SUCCESS = new ErrorCode(200,"成功!");
    ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500,"系统异常!");
    ErrorCode UNKNOW = new ErrorCode(999,"未知错误!");
}

4.2 ⾃义异常类

        对当前的系统进行设计一套自定义异常类;

        根据控制层和服务层来分别写相应的代码,

        同时在构建异常时引入错误码,比如controller的异常构造,引入controller层的errorcode来进一步完善该层的异常信息;

@Data
public class ServiceException extends RuntimeException{
    private Integer code;//异常码
    private String message;//异常信息

    //添加无参构造主要是为了进行序列化
    public ServiceException(){

    }

    public ServiceException(Integer code,String message){
        this.code = code;
        this.message = message;
    }

    public ServiceException(ErrorCode errorCode) {
        this.code = errorCode.getCode();
        this.message = errorCode.getMsg();
    }
}

        @EqualsAndHashCode(callSuper = true)注解: 

        @data注解会生成自己的@equals和hashcode方法,我们想要使用父类的属性和方法,就要使用上面的注解;

4.3. CommonResult<T>

        对所有接口返回的结果进行封装的类型;

        CommonResult<T>作为控制器层⽅法的返回类型,封装HTTP接⼝调⽤的结果,包括成功数据、错 误信息和状态码。它可以被SpringBoot框架等⾃动转换为JSON或其他格式的响应体,发送给客⼾端。

关于为什么要封装?

1. 统⼀的返回格式:确保客⼾端收到的响应具有⼀致的结构,⽆论处理的是哪个业务逻辑。 2. 错误码和消息:提供错误码(code)和错误消息(msg),帮助客⼾端快速识别和处理错误。

3. 泛型数据返回:使⽤泛型允许返回任何类型的数据,增加了返回对象的灵活性。

4. 静态⽅法:提供了error()和success()静态⽅法,⽅便快速创建错误或成功的响应对象。

5. 错误码常量集成:通过ErrorCode和GlobalErrorCodeConstants使⽤预定义的错误码,保持错 误码的⼀致性和可维护性。

6. 序列化:实现了Serializable接⼝,使得CommonResult对象可以被序列化为多种格式,如 JSON或XML,⽅便⽹络传输。

7. 业务逻辑解耦:将业务逻辑与API的响应格式分离,使得后端开发者可以专注于业务逻辑的实 现,⽽不必关⼼如何构建HTTP响应。

8. 客⼾端友好:客⼾端开发者可以通过统⼀的接⼝获取数据和错误信息,⽆需针对每个API编写特 定的错误处理逻辑。

public class CommonResult<T> implements Serializable {
//    CommonResult<T>是在http中进行传输,所以要进行序列化
    private Integer code;//返回的错误码
    private T data;//返回的数据
    private String msg;//对错误码的描述
    
    //返回成功结果的CommonResult<T>静态构造
    public static <T> CommonResult<T> success(T data){
        CommonResult<T> result = new CommonResult<>();
        result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
        result.data = data;
        result.msg = "";
        return result;
    }

    //返回异常结果的CommonResult<T>静态构造
    public static <T> CommonResult<T> error(Integer code,String msg){
        Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code),"code不是错误的异常");
        CommonResult<T> result = new CommonResult<>();
        result.code = code;
        result.msg = msg;
        return result;
    }

    public static <T> CommonResult<T> error(ErrorCode errorCode){
        return error(errorCode.getCode(),errorCode.getMsg());
    }
}

 4.4 jackson工具实现序列化

        方便将对象转化为string类,本项目中适用于日志打印个redis,rabbitmq的使用场景中;

        相对而言protobuf(pb实现序列化非常快,但是可视化非常差);

public class JacksonUtil {
    private JacksonUtil(){

    }

    private final static ObjectMapper OBJECT_MAPPER;//1点对objectmapper进行私有化单例操作

    static {
        OBJECT_MAPPER = new ObjectMapper();
    }

    private static ObjectMapper getObjectMapper(){
        return  OBJECT_MAPPER;
    }

    //2点。使用callable支持使用lamda表达式来进行处理,无论序列化的操作过程中出现的
    //异常都可以tryparse进行捕捉
    private static <T > T tryParse(Callable<T> parser) {
        return tryParse(parser, JacksonException.class);
    }

    private static <T > T tryParse(Callable<T> parser, Class<? extends Exception> check){
        try {
            return parser.call();
            } catch (Exception ex) {
                if (check.isAssignableFrom(ex.getClass())) {
                    throw new JsonParseException(ex);
                }
            throw new IllegalStateException(ex);
        }
    }

    /**
     *序列化objectmapper
     * @param value
     * @return
     */
    public static String writeValueAsString(Object value) {
        return JacksonUtil.tryParse(()->
                JacksonUtil.getObjectMapper().writeValueAsString(value));
    }

    /**
     反序列化objectmapper
     * @param content
     * @param valueType
     * @return
     * @param <T>
     */
    public static <T > T readValue(String content, Class<T> valueType) {
        return JacksonUtil.tryParse(()->
                JacksonUtil.getObjectMapper().readValue(content, valueType));
    }
    /**
     反序列化list
     * @param content
     * @param parameterClasses
     * @return
     * @param <T>
     */
    public static <T > T readListValue(String content, Class<?> parameterClasses) {
        JavaType javaType =  JacksonUtil.getObjectMapper().getTypeFactory().constructParametricType(List.class, parameterClasses);
        return JacksonUtil.tryParse(()->
        { return JacksonUtil.getObjectMapper().readValue(content,javaType);
        });
    }
}

在这里特别注意两点:jackson里面的部分方法是对springboot框架进行学习处理的

1、 对objectmapper进行私有单例化处理;

2、使用tryparse的方法,其第一个参数是callable<T> parse,支持使用lambda表达式进行处理,无论在lambda表达式哪里出现了问题,都可以在tryparse里面使用try-catch对异常进行处理;

4.5. ⽇志处理

        使用SLF4J+logback的配置:

        在本地(dev),通过控制台来打印出日志;

        服务器:日志主要存在目标目录文件;

application.properties配置:

spring.application.name=lottery_system
## logback xml ##
logging.config=classpath:logback-spring.xml
spring.profiles.active=dev

        新增logback-spring.xml文件:对于本地和服务器的日志进行配置:

<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="60 seconds" debug="false">
    <springProfile name="dev">
        <!--输出到控制台-->
        <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
            <encoder>
                <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n%ex</pattern>
            </encoder>
        </appender>
        <root level="info">
            <appender-ref ref="console" />
        </root>
    </springProfile>

    <springProfile name="prod,test">
        <!--ERROR级别的日志放在logErrorDir目录下,INFO级别的日志放在logInfoDir目录下-->
        <property name="logback.logErrorDir" value="/root/lottery-system/logs/error"/>
        <property name="logback.logInfoDir" value="/root/lottery-system/logs/info"/>
        <property name="logback.appName" value="lotterySystem"/>
        <contextName>${logback.appName}</contextName>

        <!--ERROR级别的日志配置如下-->
        <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
                如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
                的日志改名为今天的日期。即,<File> 的日志都是当天的。
            -->
            <File>${logback.logErrorDir}/error.log</File>
            <!-- 日志level过滤器,保证error.***.log中只记录ERROR级别的日志-->
            <filter class="ch.qos.logback.classic.filter.LevelFilter">
                <level>ERROR</level>
                <onMatch>ACCEPT</onMatch>
                <onMismatch>DENY</onMismatch>
            </filter>
            <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
                <FileNamePattern>${logback.logErrorDir}/error.%d{yyyy-MM-dd}.log</FileNamePattern>
                <!--只保留最近30天的日志-->
                <maxHistory>30</maxHistory>
                <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
                <!--<totalSizeCap>1GB</totalSizeCap>-->
            </rollingPolicy>
            <!--日志输出编码格式化-->
            <encoder>
                <charset>UTF-8</charset>
                <pattern>%d [%thread] %-5level %logger{36} %line - %msg%n%ex</pattern>
            </encoder>
        </appender>

        <!--INFO级别的日志配置如下-->
        <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则
                如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天
                的日志改名为今天的日期。即,<File> 的日志都是当天的。
            -->
            <File>${logback.logInfoDir}/info.log</File>
            <!--自定义过滤器,保证info.***.log中只打印INFO级别的日志, 填写全限定路径-->
            <filter class="com.example.lotterysystem.common.filter.InfoLevelFilter"/>
            <!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
                <FileNamePattern>${logback.logInfoDir}/info.%d{yyyy-MM-dd}.log</FileNamePattern>
                <!--只保留最近14天的日志-->
                <maxHistory>14</maxHistory>
                <!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
                <!--<totalSizeCap>1GB</totalSizeCap>-->
            </rollingPolicy>
            <!--日志输出编码格式化-->
            <encoder>
                <charset>UTF-8</charset>
                <pattern>%d [%thread] %-5level %logger{36} %line - %msg%n%ex</pattern>
            </encoder>
        </appender>
        <root level="info">
            <appender-ref ref="fileErrorLog" />
            <appender-ref ref="fileInfoLog"/>
        </root>
    </springProfile>
</configuration>

在配置的包中自定义过滤info级别日志的类:

public class InfoLevelFilter extends Filter<ILoggingEvent> {
    //过滤器来过滤info级别的日志,将info的日志进行接受;
    @Override
    public FilterReply decide(ILoggingEvent iLoggingEvent) {
        if (iLoggingEvent.getLevel().toInt() == Level.INFO.toInt()){
            return FilterReply.ACCEPT;
        }
        return FilterReply.DENY;
    }
}

使用测试类来进行日志打印测试:

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

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

相关文章

spring 源码分析

1 IOC 源码解析 BeanDefinition: bean的定义。里面会有beanClass、beanName、scope等属性 beanClass&#xff1a;通过Class.forName生成的Class 对象beanName&#xff1a;context.getBean(“account”)&#xff0c;acount就是beanNamescope: 作用区分单例bean、原型bean Bea…

Android水波纹效果

Android水波纹效果 需要到水波纹效果的场景还蛮少的。万一刚好你需要呢 一、思路&#xff1a; 自定义组件SpreadView 二、效果图&#xff1a; 看视频更直观点&#xff1a; Android轮子分享-水波纹效果 三、关键代码&#xff1a; public class SpreadView extends View {pr…

用 NotePad++ 运行 Java 程序

安装包 网盘链接 下载得到的安装包: 安装步骤 双击安装包开始安装. 安装完成: 配置编码 用 NotePad 写 Java 程序时, 需要设置编码. 在 设置, 首选项, 新建 中进行设置, 可以对每一个新建的文件起作用. 之前写的文件不起作用. 在文件名处右键, 可以快速打开 CMD 窗口, 且路…

TaskBuilder SQL执行工具

为了方便开发者连接当前任擎服务器上配置的各个数据源对应的数据库进行相关操作&#xff0c;TaskBuilder提供了一个SQL执行工具&#xff0c;点击系统侧边栏里的执行SQL图标 &#xff0c;即可打开该工具&#xff0c;界面如下图所示&#xff1a; 该工具从上至下分为三个区域&a…

学生信息管理系统(简化版)数据库部分

使用Mysql&#xff0c;与navicat工具 下面是mysql创建的代码&#xff0c;可做必要修改 -- 创建学生学籍信息表 CREATE TABLE StudentEnrollment (-- 学号&#xff0c;作为主键student_id VARCHAR(8) NOT NULL,-- 学生姓名stu_name VARCHAR(8) NOT NULL,-- 学生性别gender VARC…

计算机网络之传输层协议TCP

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络之传输层协议TCP 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目…

美畅物联丨观看实时视频对服务器带宽有什么要求?

​随着互联网的迅猛发展&#xff0c;实时视频观看已然成为人们日常生活中不可或缺的一部分。不管是视频会议、在线教育&#xff0c;还是在线娱乐&#xff0c;实时视频都起到了极为重要的作用。不过&#xff0c;实时视频的流畅播放对服务器的带宽有着极高的要求。本文将深入探究…

SWIRL:有望成为2025年顶级AI搜索引擎

现在几乎每家公司都会有内部文档系统&#xff0c;如阿里的语雀、钉钉&#xff0c;字节的飞书&#xff0c;Confluence&#xff0c;印象笔记等等都可以提供给B端在局域网部署。因此&#xff0c;如果能把搜索功能做得高效&#xff0c;就能提高自家产品的竞争力。 想象一下&#xf…

技术栈6:Docker入门 Linux入门指令

目录 1.Linux系统目录结构 2.处理目录的常用命令 3.Docker概述 4.Docker历史 5.Docker基本组成 6.Docker底层原理 7.Docker修改镜像源 8.Docker基本命令 9.Docker创建Nginx实战 10.数据卷 11.本地目录直接挂载* 12.镜像和dockerfile 13.容器互联与自定义网络 14.…

LeetCode - #156 上下翻转二叉树(会员题)

文章目录 前言1. 描述2. 示例3. 答案关于我们 前言 本题为 LeetCode 的高级会员解锁题 我们社区陆续会将顾毅&#xff08;Netflix 增长黑客&#xff0c;《iOS 面试之道》作者&#xff0c;ACE 职业健身教练。&#xff09;的 Swift 算法题题解整理为文字版以方便大家学习与阅读…

汽车零部件设计之——麦弗逊悬架KC特性分析仿真APP介绍

汽车零部件是汽车工业的基石&#xff0c;是构成车辆的基础元素。一辆汽车通常由上万件零部件组成&#xff0c;包括发动机系统、传动系统、制动系统、电子控制系统等&#xff0c;它们共同确保了汽车的安全、可靠性及高效运行。在汽车产业快速发展的今天&#xff0c;汽车零部件需…

STM32串口接收与发送(关于为什么接收不需要中断而发生需要以及HAL_UART_Transmit和HAL_UART_Transmit_IT的区别)

一、HAL_UART_Transmit和HAL_UART_Transmit_IT的区别 1. HAL_UART_Transmit_IT&#xff08;非阻塞模式&#xff09;&#xff1a; HAL_UART_Transmit_IT 是非阻塞的传输函数&#xff0c;也就是说&#xff0c;当你调用 HAL_UART_Transmit_IT 时&#xff0c;它不会等到数据完全发…

学生信息管理系统(简化版)后端接口

目录 allAPI __init__.py是空文件&#xff0c;目的让python知道这个文件夹是个包 ClassInfo.py from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from API.database import get_db, Base from sqlalchemy import Column, String,…

网络安全信息收集(总结)更新

目录 重点&#xff1a; 前言&#xff1a; 又学到了&#xff0c;就是我们什么时候要子域名收集&#xff0c;什么时候收集域名&#xff0c;重点应该放前面 思考&#xff1a; 信息收集分为哪几类&#xff0c;什么是主域名&#xff0c;为什么要收集主域名&#xff0c;为什么要收…

微信小程序从后端获取的图片,展示的时候上下没有完全拼接,有缝隙【已解决】

文章目录 1、index.wxml2、index.js3、detail.detail为什么 .rich-text-style 样式可以生效&#xff1f;1. <rich-text> 组件的特殊性2. 类选择器的作用范围3. 样式优先级4. line-height: 0 的作用5. 为什么直接使用 rich-text 选择器无效&#xff1f; 总结 上下两张图片…

【达梦数据库】存储过程调用实践案例-select

目录 前言创建表插入数据查询表中数据创建存储过程打开dbms_output包输出开关调用存储过程 前言 如果要在存储过程中执行一个SELECT语句并处理其结果&#xff0c;你不能直接使用EXECUTE IMMEDIATE&#xff0c;因为EXECUTE IMMEDIATE主要用于执行那些不返回行的语句&#xff08;…

C语言:指针(第一天)

C语言&#xff1a;指针&#xff08;第一天&#xff09; 预备知识 内存地址 字节&#xff1a;字节是内存的容量单位&#xff0c;英文名byte&#xff0c;一个字节有8位&#xff0c;即1byte8bits地址&#xff1a;系统为了便于区分每一个字节而对他们逐一进行的编号&#xff0c;…

vue3如何实现点击回车,自动登录?

vue3如何实现点击回车&#xff0c;自动登录&#xff1f; 场景&#xff1a;登录账号的时候&#xff0c;可能有的人不习惯直接点击登录&#xff0c;而是通过顺手敲个回车键实现登录 解决办法&#xff1a;上代码 //监听回车 function onKeyUp(e) {//console.log(e)if (e.key En…

LNMP和Discuz论坛

文章目录 LNMP和Discuz论坛1 LNMP搭建1.1 编译安装nginx服务1.1.1 编译安装1.1.2 添加到系统服务 1.2 编译安装MySQL服务1.2.1 准备工作1.2.2 编辑配置文件1.2.3 设置路径环境变量1.2.4 数据库初始化1.2.5 添加mysqld系统服务1.2.6 修改mysql的登录密码 1.3 编译安装PHP服务1.3…

目标跟踪算法:SORT、卡尔曼滤波、匈牙利算法

目录 1 目标检测 2 卡尔曼滤波 3《从放弃到精通&#xff01;卡尔曼滤波从理论到实践》视频简单学习笔记 3.1 入门 3.2 进阶 3.2.1 状态空间表达式 3.2.2 高斯分布 3.3 放弃 3.4 精通 4 匈牙利算法 5 《【运筹学】-指派问题&#xff08;匈牙利算法&#xff09;》视…