芝法酱学习笔记(0.3)——SpringBoot下使用mybatis做增删改查和报表

news2024/11/19 1:22:59

零、前言

书接上回,我们搭建了windows下的开发环境,并给出了一个hello world级别的多模块SpringBoot项目。
毕竟java后端开发,离不开数据库的操作,为方便后面内容的讲解,这里再做一期铺垫,core模块下新增一个core-mpenhance模块,该模块引入mybatis-plus,并对其进行一定规范封装。基于该模块,我们编写一些crud的业务代码。

一、软件安装

说到数据库操作,windows端我一般会装2个软件。powerdesigner和workbench。

1.1 powerdesigner

powerdesigner是一个数据库设计软件,下载地址可以去这位网友那里下载。关于powerdesigner的用法,织法先前的博客有讲解。

2.2 workbench

可以去这里下载。为什么我不说navcat,因为workbench是免费的,而且满足使用需求,何必再用需要破解的软件呢?尤其是在上市公司和国企的小伙伴。

二、构思一个业务

本次笔记,打算实现一个简化了的供应商货物管理系统。

2.1 供应商管理系统简介

在市场上,商品的流通中,有4个角色,厂商、中间商、零售商、用户。我们现在要做的就是中间商用的一个管理系统。
中间商从厂商进货到自己的仓库,然后通过自己的业务员,把货物卖向一个个的零售商。

2.2 这次开发的核心系统

2.2.1 商品定义系统

定义一个个的商品,商品包括名称,商品单位转换比,商品所属的大类型、小类型和品牌等。
这里比较不好理解的是商品的转换比,我在这里多讲一些。
商品的单位类型有3种,如下枚举所示

@RequiredArgsConstructor
@EnumDesc(name = "商品单位类型",desc = "商品单位类型",defaultIdx = 2,defaultItem = "大小单位")
public enum EItemUnitType {


    SINGLE_UNIT(1,"单单位","只有一个小单位"),
    NORMAL_UNIT(2,"大小单位","有一个大单位,有一个小单位"),
    TRIPLE_UNIT(3,"三单位","有一个大单位,中单位,小单位");

    @EnumValue
    @Getter
    private final int code;
    @Getter
    private final String name;
    @Getter
    private final String desc;
}

比如最常见的NORMAL_UNIT,就是一个大单位一个小单位,比如1箱=24袋,箱就是大单位,袋是小单位,转换比是24.
在业务员录单时,一般录入大单位价格。统计销售量,也通常会统计大单位数量。
商品定义表设计如图所示:
在这里插入图片描述

2.2.2 商品录单

该系统的核心业务,业务员去门店销售商品。由于这里是学习贴,会做很多简化,先不去考虑预售等情况。
销售单一共3个类型,如下枚举:

@RequiredArgsConstructor
@EnumDesc(name = "销售单类型",desc = "销售单类型",defaultIdx = 1,defaultItem = "销售单")
public enum EConsignType {

    CONSIGN(1,"销售单","销售单,该单据从中间商出售商品到门店"),
    RETURN(2,"退货单","该单据从门店退货到中间商"),
    EXCHANGE(3, "换货单","换货单,门店把不好的货物退给中间商,拿到一个新的货物,相当于一个销售一个退货");

    @EnumValue
    @Getter
    private final int code;
    @Getter
    private final String name;
    @Getter
    private final String desc;
}

商品录单的数据结构,一个头表,一个明细表。一个销售单,可能包括多个商品的销售。数据库设计如图所示:
在这里插入图片描述

2.2.3 库存数据

在门店的商品是有库存概念的。销售时,销售数量不能超过库存。本次由于简化,就不再引入进货单的概念了,仅仅记录商品的库存和当前的成本价格。
商品的价格,取决于每次进货时的数量与价格。这种价格叫移动加权平均。比如原先库存中100个大单位,原价100元;再进货100个大单位,单价为150。此时,该商品的成本价格为125每个大单位。
库存表设计如图所示:
在这里插入图片描述

2.2.4 销售报表

销售报表中,需要根据不同维度分组。如商品Id,品牌,门店,业务员。也有复合分组,门店+商品。在查询时,会有时间范围,商品名、业务员名、门店等筛选条件。
销售报表的返回内容,无非是销售的数量、销售额、成本、利润等信息。并且支持按某种维度排序。

三、代码结构

3.1 mp-enhence

在core模块下,建一个mp-enhence的子模块,用于放置mysql相关操作的库。
由于该业务既有增删改查,又有报表相关的复杂连表分组查询,我们ORM选用mybatis-plus。
该模块如图所示:
在这里插入图片描述
由于该模块的实现,在之前的博客中已经写过,这里就不再赘述
芝法酱躺平攻略(3)—— 搭建基于mybatis-plus的开发框架
芝法酱躺平攻略(4)—— powerdesigner与mybatis-plus生成代码

3.2 代码结构的思考

大概讲一下代码位置的规划。分层设计虽然是一个看上去很干净的设计,但在实际开发中,不同模块间总会有相互关联,很难把每个模块拆成一个个的微服务。通常情况下,我们仅仅会针对大功能做服务划分。并且,微服务的拆分,其实完全可以体现在controller上,基层的业务代码,通过包引用方式引入。不同微服务仅仅是暴露不同的接口。
这样的情况下,现在的实际开发中,代码就会更偏向单体风格。然后有些程序员理解不深刻,硬要把代码做成分层的风格,比如所有的po在一个包内,所有service在一个包内,所有的mapper在一个包内。报表的mybatis的xml再放一个文件夹中。刚开始开发觉得没什么,但当业务量膨胀后,就会发现这样的结构写起代码十分痛苦。一个模块想找一下他相关的类,简直远隔千山万水。同时也使得,在实际执行时,基础程序员倾向于写更少的类。一个结构体里包含多个功能的字段,然后代码就成了屎山,极难维护。
这里展示一下我们这次的代码结构:
在这里插入图片描述
我们详细看一下报表系统的结构。我们可以看到,entity写了好多,分为request,response,mapperIn,mapperOut。
这里一定不要嫌烦,这种做法可以使代码结构清晰,并且易于复用。mapper的入参出参,一定要和controller的分开,不然代码会变得很不好理解。那还不如全用Map传递了事。既然都用map传递了,为什么不放弃Java改用python写代码呢?
具体可以在最后的代码展示中来看。
在这里插入图片描述

3.3 mybatis-plus还是原生mybatis

对于一般单表的增删改查业务,我更倾向于用mybatis-plus,减少不必要的代码量,快速开发。
而对于报表类的业务,会牵扯大量表连接,分组,聚合函数等情况。这时,使用原生的mybatis。

3.4 报表代码的复用性

由于该报表会有各个维度的分组查找,不同维度的查找返回字段也不相同。如果针对每个函数写一套xml的sql,那实在太麻烦了。毕竟mybatis支持动态sql。要不要查询商品相关信息,如何分组等,完全可以在mapper的入参中体现。
如何设置ConsignMapperIn,这个代码可以放在Request的类里。由于多数设置(如分页、时间范围等)也是通用的,所以可以写在Request的积累里。
我这里展示一部分代码,供大家参考

BaseConsignReportRequest

public abstract class BaseConsignReportRequest extends BasePageRequest {
    Long itemId;
    String itemName;
    String mainType;
    String segmentType;
    String brand;
    Long customerId;
    String customerName;
    Long salesId;
    String salesName;
    LocalDateTime timeBegin;
    LocalDateTime timeEnd;
    EConsignReportOrderType consignOrderType;
    EOrderType orderType;

    public BaseConsignReportRequest(){
        timeBegin = LocalDateTime.now().minusDays(3l);
        timeEnd = LocalDateTime.now();
        consignOrderType = EConsignReportOrderType.BILL_TIME;
        orderType = EOrderType.DESC;
    }

    public  ConsignMapperIn toMapperIn(){
        ConsignMapperIn consignMapperIn = new ConsignMapperIn();
        consignMapperIn.setItemId(itemId);
        consignMapperIn.setItemName(itemName);
        consignMapperIn.setMainType(mainType);
        consignMapperIn.setSegmentType(segmentType);
        consignMapperIn.setBrand(brand);
        consignMapperIn.setCustomerId(customerId);
        consignMapperIn.setCustomerName(customerName);
        consignMapperIn.setSalesId(salesId);
        consignMapperIn.setSalesName(salesName);
        consignMapperIn.setConsignOrderType(consignOrderType);
        consignMapperIn.setOrderType(orderType);

        Instant instantBeg = timeBegin.toInstant(ZoneOffset.UTC);
        consignMapperIn.setBillTimeBegin(instantBeg.getEpochSecond());
        Instant instantEnd = timeEnd.toInstant(ZoneOffset.UTC);
        consignMapperIn.setBillTimeEnd(instantEnd.getEpochSecond());

        if(size > 0){
            consignMapperIn.setPage(true);
            consignMapperIn.setOffset((current-1)*size);
            consignMapperIn.setLimit(size);
        }else{
            consignMapperIn.setPage(false);
        }

        consignMapperIn = onConsignMapperInInit(consignMapperIn);
        return consignMapperIn;

    }

    protected abstract ConsignMapperIn onConsignMapperInInit(ConsignMapperIn pConsignMapperIn);
    
}

ConsignMapperIn

@Data
public class ConsignMapperIn {
    String itemName;
    Long itemId;
    String mainType;
    String segmentType;
    String brand;
    Long customerId;
    String customerName;
    Long salesId;
    String salesName;
    Long billTimeBegin;
    Long billTimeEnd;


    boolean selectItemInfo;
    boolean selectCustomerInfo;
    boolean selectSalesInfo;

    boolean isGroup;
    List<String> groups;
    boolean joinItem;
    boolean groupItem;

    EConsignReportOrderType consignOrderType;
    EOrderType orderType;

    boolean isPage;
    Integer offset;
    Integer limit;

    public ConsignMapperIn(){
        isGroup = true;
        groups = new ArrayList<String>();
        joinItem = false;
        consignOrderType = EConsignReportOrderType.BILL_TIME;
        orderType = EOrderType.NONE;
        isPage = true;

        selectItemInfo = false;
        selectCustomerInfo = false;
        selectSalesInfo = false;
    }
}

xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="indi.zhifa.study2024.class002.busy.generalTest.business.report.consign.mapper.ConsignMapper">

    <sql id="select_col">
        SUM(CASE WHEN cd.sale_type = 1 or cd.sale_type = 0 THEN cd.cost ELSE 0  END) AS sale_cost,
        SUM(CASE WHEN cd.sale_type = 1 THEN cd.amount ELSE 0 END) AS sale_amount,

        SUM(CASE WHEN cd.sale_type = 2 THEN -cd.cost ELSE 0  END) AS return_cost,
        SUM(CASE WHEN cd.sale_type = 2 THEN -cd.amount ELSE 0 END) AS return_amount,

        SUM(cd.amount) AS amount,
        SUM(cd.amount - cd.cost ) AS profit,
        SUM(cd.cost) AS cost,
        SUM(cd.amount - cd.cost ) / SUM(cd.amount) AS profit_ratio

        <if test="In.groupItem">
            ,SUM(CASE WHEN cd.sale_type = 1 or cd.sale_type = 0 THEN cd.count ELSE 0  END) AS sale_cnt
            ,SUM(CASE WHEN cd.sale_type = 2 THEN -cd.count ELSE 0  END) AS return_cnt
            ,SUM(cd.count) AS nest_cnt
        </if>

        <if test="not In.isGroup">
            ,ch.id, ch.bill_no, ch.bill_type, ch.bill_time
        </if>
        <if test="In.selectItemInfo">
            ,cd.item_id, cd.item_name
            <if test="In.joinItem">
                ,itm.unit_type,itm.small_unit_name,itm.mid_unit_name,itm.large_unit_name,itm.large_convert,itm.mid_convert,itm.main_type,itm.segment_type,itm.brand
            </if>
        </if>
        <if test="In.selectCustomerInfo">
            ,ch.customer_id,ch.customer_name
        </if>
        <if test="In.selectSalesInfo">
            ,sales_id,sales_name
        </if>
    </sql>

    <select id="consignReport"
            resultType="indi.zhifa.study2024.class002.busy.generalTest.business.report.consign.entity.mapperOut.ConsignMapperOut">
        SELECT <include refid="select_col"/>
        FROM
        consign_head ch JOIN consign_detail_simple cd ON ch.id = cd.bill_id

        <if test="In.joinItem">
            JOIN item_define itm ON cd.item_id = itm.id
        </if>

        <where>
            ch.bill_time BETWEEN #{In.billTimeBegin} AND #{In.billTimeEnd}
            <if test="In.itemName != null and In.itemName != ''">
                AND cd.item_name like CONCAT('%', #{In.itemName}, '%')
            </if>
            <if test="In.itemId != null">
                AND cd.item_id = #{In.item_id}
            </if>
            <if test="In.mainType != null and In.mainTyp != '' and In.joinItem">
                AND itm.main_type = #{In.mainTyp}
            </if>
            <if test="In.segmentType != null and In.segmentType != '' and In.joinItem">
                AND itm.segment_type = #{In.segmentType}
            </if>
            <if test="In.brand != null and In.brand != '' and In.joinItem">
                AND itm.brand = #{In.brand}
            </if>
            <if test="In.customerId != null">
                AND ch.customer_id = #{In.customerId}
            </if>
            <if test="In.customerName != null and In.customerName != ''">
                AND ch.customer_name like CONCAT('%', #{In.customerName}, '%')
            </if>
            <if test="In.salesId != null">
                AND ch.sales_id = #{In.salesId}
            </if>
            <if test="In.salesName != null and In.salesName != ''">
                AND ch.sales_name = #{In.salesName}
            </if>
        </where>

        <if test="In.isGroup">
            GROUP BY
            <foreach item="item" index="index" collection="In.groups" separator=",">
                ${item}
            </foreach>
        </if>

        <if test="In.orderType.name() != 'NONE'">
            ORDER BY ${In.consignOrderType.getKey()} ${In.orderType.getKey()}
        </if>
        <if test="In.isPage">
            LIMIT #{In.offset},#{In.limit}
        </if>

    </select>
</mapper>

四、出现的一些问题

4.1 分组问题

按照我写的这个sql,在不经任何设置时,就会报error 1055的sql错误。
这时,我们在workbench中先运行这个命令

SELECT @@sql_mode

而后,我们把返回值中的ONLY_FULL_GROUP_BY去掉
而后,进入linux的/etc/mysql
vim my.cnf
在最下面加这一段

sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION

4.2 mybatis的xml的位置配置

首先在pom的build标签中,加入如下配置:
该配置的目的,是把mybatis的xml,放到mybatis的目录下

<build>
        <resources>
            <resource>
                <directory>src/main/java/indi/zhifa/study2024/class002/busy/generalTest/business/report</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <targetPath>${project.build.directory}/classes/mybatis</targetPath>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>

点击编译,观察target文件夹
在这里插入图片描述

在application.yml中,加入如下配置

mybatis-plus:
  mapper-locations: classpath:mybatis/**/xml/*.xml

这样一来,我们就不需要把xml写到一个文件夹下,可以和mapper放在一起。

4.3 打印sql

在mybatis-plus下加一段配置,可以打印出所有的sql信息,包括查询的返回值。

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

查询的log如图所示:
在这里插入图片描述
在实际的生产中,这样的log膨胀的太快,返回结果对我们发现错误来说也没太大的意义。
实际上,之所以没有打印出sql的log,是因为mybatis的sql log的日志级别是Debug的,而我们默认的日志级别是info的。
我在实际开发时,通常把mapper中的sql打印出来,而mp自动生成的不会打印。这样,只要把indi.zhifa.study2024.class002.busy.generalTest.business.report.这个包的日志级别改为Debug即可:
在这里插入图片描述

4.4 logback

在实际生产中,不可能把日志打印在屏幕上,而是打印到一个文件里。由于日志量很大,日志需要按天按数量做拆分,这时就需要引入logback了。
SpringBoot默认已经引入了logback的库,我们只需要在resource文件夹下放置logback.xml即可。
下面是logback.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<!-- 定义文件输出格式, 编码方式, 输出文件的路径 -->
	<property name="pattern"
			  value="[%date{yyyy-MM-dd HH:mm:ss.SSS}] %X{logthreadId} %-5level %logger{80} %method %line - %msg%n"/>
	<!-- magenta:洋红  boldMagenta:粗红  cyan:青色  white:白色  magenta:洋红 -->
	<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<!--    <property name="CONSOLE_LOG_PATTERN"-->
<!--              value="%yellow(%date{yyyy-MM-dd HH:mm:ss})|%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n))"/>-->
	<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
	<!-- 日志路径 -->
	<property name="logPath" value="../logs"/>
	<property name="APP_NAME" value="study2024-busy-general-test"/>
	<property name="charsetEncoding" value="UTF-8"/>
	<!-- 控制台输出 -->
	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
		<!--日志级别过滤INFO以下-->
		<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
			<level>DEBUG</level>
		</filter>
		<encoder charset="GBK">
			<!-- <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}]-[%t]-[%C:%L]- %-5level-%m%n</pattern> -->
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
		</encoder>
	</appender>


	<!-- INFO 输出到文件 -->
	<appender name="infoLog" 	class="ch.qos.logback.core.rolling.RollingFileAppender">
		<append>true</append>
		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<fileNamePattern>
				${logPath}/${APP_NAME}-INFO-%d{yyyy-MM-dd}_%i.log
			</fileNamePattern>
			<maxHistory>30</maxHistory>
			<maxFileSize>100MB</maxFileSize>
		</rollingPolicy>
		<encoder>
			<pattern>${pattern}</pattern>
			<charset>${charsetEncoding}</charset>
		</encoder>
		<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
			<!-- 设置日志输出级别 -->
			<level>DEBUG</level>
		</filter>
	</appender>

	<!-- ERROR 输出到文件 -->
	<appender name="errorLog" 	class="ch.qos.logback.core.rolling.RollingFileAppender">
		<append>true</append>
		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
			<fileNamePattern>
				${logPath}/${APP_NAME}-ERROR-%d{yyyy-MM-dd}_%i.log
			</fileNamePattern>
			<maxHistory>30</maxHistory>
			<maxFileSize>100MB</maxFileSize>
		</rollingPolicy>
		<encoder>
			<pattern>${pattern}</pattern>
			<charset>${charsetEncoding}</charset>
		</encoder>
		<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
			<!-- 设置日志输出级别 -->
			<level>WARN</level>
		</filter>
	</appender>

	<logger name="indi.zhifa.study2024" level="INFO" additivity="false">
		<appender-ref ref="console" />
		<appender-ref ref="infoLog" />
		<appender-ref ref="errorLog" />
	</logger>

	<!-- 报表mapper的信息,-->
	<logger name="indi.zhifa.study2024.class002.busy.generalTest.business.report" level="DEBUG" additivity="false">
		<appender-ref ref="infoLog" />
		<appender-ref ref="console" />
		<appender-ref ref="errorLog" />
	</logger>

</configuration> 

五、代码展示

我们这节属于过渡章节,仅仅是不想让测试项目只有hello world,显得太过单薄。所以代码讲解并不是本章重点。所以,这里还是展示我的码云,大家可以下载后观看。

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

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

相关文章

国际版多语言点赞抖音分享点赞任务平台源码

>>>系统简述&#xff1a; 本系统是一个国际化的点赞、分享任务平台的源代码&#xff0c;特别针对抖音这个短视频社交平台进行了定制。源码支持十二种不同的语言&#xff0c;旨在为用户提供一个全球化的服务环境&#xff0c;促进内容的传播和互动。首页可领取脸书tikt…

如何使用 DomCrawler 进行复杂的网页数据抓取?

在互联网时代&#xff0c;数据是宝贵的资源。无论是市场分析、客户洞察还是内容聚合&#xff0c;从网页中抓取数据都是一项关键技能。Symfony 的 DomCrawler 是一个强大的工具&#xff0c;可以帮助开发者从复杂的网页中提取所需的数据。本文将详细介绍如何使用 DomCrawler 进行…

学习Python的难点分析

一、语法灵活性带来的困惑 缩进规则 Python使用缩进来表示代码块&#xff0c;而不是像其他编程语言&#xff08;如C或Java&#xff09;使用大括号。这虽然使代码看起来简洁&#xff0c;但对于初学者来说可能会造成困扰。例如&#xff1a; if True:print("This is insid…

C语言开发基础新手快速入门及精通系列学习教程(系统性完整C语言学习笔记整理)

关注我&#xff0c;一起学编程 前言 作为一名拥有多年开发经验的码农&#xff0c;我的职业生涯涵盖了多种编程语言&#xff0c;包括 C 语言、C、C# 和 JavaScript。在这一过程中&#xff0c;我深刻地意识到扎实的基础对于编程学习的重要性&#xff0c;尤其是对于 C 语言…

React 启动时webpack版本冲突报错

报错信息&#xff1a; 解决办法&#xff1a; 找到全局webpack的安装路径并cmd 删除全局webpack 安装所需要的版本

这条挣钱的路,离我好遥远啊

近日&#xff0c;笔者在发表的《乱篇弹&#xff08;54&#xff09;让子弹飞》一文中写道&#xff1a;“ 当然&#xff0c;笔者在《博客中国-狼头长啸的作家专栏》耕耘期间&#xff0c;也赚了一些用以补贴自己养老的‘ 散碎银两’。那么笔者是否可以依照知乎网的‘申请开通权限’…

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-28

计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-28 目录 文章目录 计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-09-28目录前言1. Cognitive phantoms in LLMs through the lens of latent variables摘要研究背景问题与挑战创新点算法模型实验效果…

Java项目实战II基于Java+Spring Boot+MySQL的大学城水电管理系统(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者 一、前言 随着大学城规模的不断扩大和学生数量的急剧增加&#xff0c;大学城内的水电管理面临着前所未有的挑战…

一个月涨粉15万!霸屏某书的“AI奶奶”怎么做?AI副业变现零基础入门教程

大家好&#xff0c;我是灵魂画师向阳 最近&#xff0c;大家可能在小红书刷到过不少“奶奶"账号。这些账号通常都打着人间清醒xxx的名号&#xff0c;比如人间清醒月亮奶奶 人间清醒柒奶奶 等。它们在小红书上的数据都不错&#xff0c;其中&#xff0c;”人间清醒柒奶奶“一…

InfluxDB数据库在Windows中的部署与运行

本文介绍在Windows电脑中&#xff0c;下载、安装、部署并运行InfluxDB数据库服务的方法。 InfluxDB是一个开源的时间序列数据库&#xff0c;专为处理时间序列数据而设计。它最初发布于2013年&#xff0c;目前已被广泛应用于监控、日志记录、物联网、实时分析等领域&#xff0c;…

使用AT command 修改手机APN

文章目录 使用AT command 修改手机APN其他AT command 使用AT command 修改手机APN 首先通过设备管理器查找到手机所使用的串口号。 然后通过putty 等串口连接软件&#xff0c;以telnet的方式连接手机。 连接成功后先&#xff0c;查看手机的 APN&#xff1a; ATCGDCONT可以用于…

AI技术在爱奇艺视频搜索中的应用

当前AI技术已经全面在爱奇艺搜索引擎中落地应用。与传统搜索仅能查找片名不同&#xff0c;爱奇艺的AI搜索功能让用户能够在搜索阶段使用更多模糊信息获得想找的影片。首次将生成式AI技术应用于角色搜索、剧情搜索、明星搜索、奖项搜索和语义搜索五大场景。通过对模糊搜索query的…

木材检测系统源码分享

木材检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

转行自学网安,八个月成功上岸,0基础转行熬过来了_自学网安要多久

目录 转行前的阵痛 我学的专业 寻找新的技术 分享我学习经验 你想学吗&#xff1f; 网络安全零基础到进阶学习路线 转行前的阵痛 转行学网安&#xff0c;最后找到第一份工作&#xff0c;我一共用了八个月。六个半月学习技术&#xff0c;一个半月找到工作。 自学网安到就…

8609 哈夫曼树

### 思路 1. **选择最小权值节点**&#xff1a;在哈夫曼树构建过程中&#xff0c;选择两个权值最小且父节点为0的节点。 2. **构建哈夫曼树**&#xff1a;根据权值构建哈夫曼树&#xff0c;确保左子树权值小于右子树权值。 3. **生成哈夫曼编码**&#xff1a;从叶子节点到根节点…

瓶子类型检测系统源码分享

瓶子类型检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

一张照片生成会动的3D模型,这个AI工具有点厉害!

分享一个实用的3D模型生成工具。 这个工具甚至还可以让你的模型动起来&#xff01; 不需要懂建模技术&#xff0c;只需要输入提示词或者或者上传图片&#xff0c;AI就可以在1分钟内帮你生成3D模型。 你可以用它来制作各种手办或者实物的3D模型&#xff0c;以后真的可以不用学…

记一次停车场后台管理系统漏洞挖掘

漏洞描述 停车场后台管理系统是一种专为停车场管理者设计的综合管理平台&#xff0c;旨在提供全面、高效、智能的停车场运营管理解决方案&#xff0c;系统利用现代信息技术&#xff0c;如物联网、大数据、云计算等&#xff0c;实现对停车场内车辆进出、车位管理、费用结算、安…

shell脚本使用==判断相等报错

文章目录 方法 1&#xff1a;使用 比较符方法 2&#xff1a;强制使用 bash 这个错误的原因是你使用了 比较符&#xff0c;而 /bin/sh (或一些系统的默认 sh 解释器) 可能不支持它。对于 POSIX 兼容的 shell&#xff08;如 /bin/sh&#xff09;&#xff0c;应该使用单个等号…

3分钟掌握大模型训练全流程

之前有小伙伴私信我&#xff0c;想了解下大模型比如 chatGPT 是如何进行训练的。 和他们聊了一下&#xff0c;发现有一个点一直在困惑着大家&#xff0c;那就是—— 大模型的训练是无监督学习还是有监督学习&#xff1f;在大模型训练过程中&#xff0c;数据的标签是什么&…