Spring Boot 集成MyBatis-Plus
文章目录
-
- 一、背景说明
- 二、集成过程
-
- 2.1 引入 maven 依赖
- 2.2 增加属性配置
- 2.3 自动配置类
- 三、验证集成
-
- 3.1 控制器
- 3.2 服务类
- 3.3 Mapper接口类
- 3.4 实体类
- 3.4 不要忘记XML文件
- 3.5 发起请求
- 四、技巧拓展
-
- 4.1 如何打印sql语句?
- 4.2 如何对参数增加非空验证?
- 4.3 如何查看 Maven 依赖?
- 4.3 如何解决时间格式问题?
- 4.4 如何快速增加 `serialVersionUID` 属性?
- 五、总 结
一、背景说明
大部分的项目都需要进行数据的持久化,所以必然会使用到数据库。而关系型数据库是其中比较常见的数据库类型。目前使用比较多的关系型数据库有:MySQL、PostgreSQL和Oracle等。
在古早的应用开发中,需要开发人员写许多的DAL(数据访问层)代码,需要自己管理数据库的连接与关闭,还需要自己从ResultSet中获取数据,然后再将其组装为对象。在其中会编写大量非业务代码,并且这些代码往往充满了重复。
ORM的出现解决了前面提到的一系列问题,ORM的全称是 Object Relational Mapping
,翻译为对象关系模型
。这里所说的对象
是指业务领域的对象,关系
则指的是关系数据库(具体而言就是数据表和字段)。
ORM可以实现自动将数据库中的表字段映射为对象的属性,其采用的方式是:使用映射元数据
来描述对象关系的映射。ORM充当了应用程序的业务逻辑层和数据库之间的桥梁。常见的ORM中间件有:Hibernate和ibatis(目前已更名为 MyBatis
)。
本篇所提及的 MyBatis-Plus
对 MyBatis
的功能进行了增强。
二、集成过程
在Spring Boot项目中集成 MyBatis-Plus 过程比较简单,大概分为三个步骤:
- 引入maven依赖
- 增加属性配置
- 增加相关的自动配置类
如果不知道如何创建Spring Boot项目,可以参考以往的文章:
[Spring Boot实战] 如何快速地创建spring boot项目
2.1 引入 maven 依赖
为了使用 MyBatis-Plus,需要添加相关依赖:
<!--mybatis-plus--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>${mybaits-plus.version}</version></dependency>
同时因为需要数据库进行数据的存储,所以还需要添加下面的依赖(我们选择的MySQL数据库):
<!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency>
如果仅限于集成 MyBatis-Plus,这两个依赖就已经足够了。
2.2 增加属性配置
相关的属性配置到 application.yml
文件中:
spring:application:name: "demo-api"datasource:# MySql 8.0以上版本driver-class-name: com.mysql.cj.jdbc.Driver# 兼容以前的配置jdbc-url: jdbc:mysql://localhost:3306/your_database?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull&useTimezone=true&serverTimezone=GMT%2B8&allowMultiQueries=trueurl: ${spring.datasource.jdbc-url}username: your_usernamepassword: your_password
2.3 自动配置类
前面我们已经提过:ORM使用映射元数据
来描述对象关系的映射。所以我们需要对相关信息进行配置,比如:
- 使用的是什么数据库
- 数据库连接是什么
- Mapper 接口文件在哪里
- MyBatis 所依赖的XML文件到哪里去找
- MyBatis 的 SqlSessionFactory 如何创建(依赖数据源、MyBatis插件)
Spring Boot 中的配置一般以 @Configuration 进行标识。相关代码如下:
@Configuration
@MapperScan(basePackages = "com.xhm.demo.api.mapper")
public class DataSourceConfig {@ConfigurationProperties(prefix = "spring.datasource")@Beanpublic DataSource dataSource() {return DataSourceBuilder.create().build();}@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor());//注册乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource, MybatisPlusInterceptor interceptor) throws Exception {MybatisSqlSessionFactoryBean ssfb = new MybatisSqlSessionFactoryBean();ssfb.setDataSource(dataSource);ssfb.setPlugins(interceptor);//到哪里找xml文件ssfb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/*Mapper.xml"));return ssfb.getObject();}
}
配置类的 @MapperScan(basePackages = "com.xhm.demo.api.mapper")
指定了 Mapper 接口的存放位置。
第一个 Bean 用于创建数据源,会根据相关依赖自动判断数据库类型。@ConfigurationProperties(prefix = "spring.datasource")
会将以 spring.datasource
开头的属性配置赋值给数据源对象的对应属性。
第二个 Bean 用于注册 MyBatis-Plus 的相关插件(这里暂时只注册了 分页插件和 乐观锁插件)
第三个 Bean 用于创建 SqlSessionFactory
的实例。 SqlSessionFactory
是一个接口,负责数据库Session(会话)的管理,数据库会话通俗点讲就是客户端与数据库的单次连接。其依赖下面的信息:
- 数据源
- MyBatis-Plus 插件
- xml文件的存放位置(资源路径)
三、验证集成
下面是常见的三层架构的目录结构:
api
├── controller
├── dto
├── entity
├── mapper
└── service
其中最主要的目录自上而下依次是:
- controller :控制器目录(表示层)
- service:服务类目录(业务逻辑层)
- mapper:DAO目录(数据访问层)
另外两个目录的作用:
- entity:实体类目录
- dto:数据传输对象(DTO)目录
创建对应的表:
create table t_card_puncher
(id int(10) not null auto_increment,name varchar(15) comment '打卡人姓名',nick varchar(50) comment '打卡人昵称',avatar varchar(100) comment '头像',status smallint(2) default 10 comment '打卡人状态(10-已保存;20-已启用;0-已作废)',account_id int(10) comment '对应账号id',remark varchar(500) comment '备注',added_by int(10) comment '新增人id',added_by_name varchar(20) comment '新增人姓名',added_time datetime default CURRENT_TIMESTAMP comment '新增时间',last_modified_by int(10) comment '最后修改人id',last_modified_by_name varchar(20) comment '最后修改人姓名',last_modified_time datetime default CURRENT_TIMESTAMP comment '最后修改时间',last_modified_ip varchar(50) comment '最后修改IP',valid smallint(1) default 1 comment '是否有效(1-有效;0-无效)',primary key (id)
);alter table t_card_puncher comment '习惯打卡人表';
依次在上面的目录中创建相关类,实现一个简单的接口。我们将按照从上而下的顺序创建相关的类。
3.1 控制器
代码清单3.1-1:
// CardPuncherController.java@RestController
@RequestMapping("/cardPuncher")
public class CardPuncherController {@Resourceprivate CardPuncherService service;@PostMapping("/queryById")public BaseResponse<CardPuncher> queryById(@RequestBody @Valid IdRequest request){CardPuncher dto = service.queryCardPuncherById(request.getId());return BaseResponse.ok(dto);}
}
控制器类依赖下面三个类:
- IdRequest (DTO)
- CardPuncher (实体类)
- CardPuncherService (服务类–接口)
代码清单3.1-2:
// IdRequest.javaimport com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;import java.io.Serializable;
import javax.validation.constraints.NotNull;@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class IdRequest implements Serializable {private static final long serialVersionUID = 4111263664475615283L;/*** id*/@NotNull(message = "ID不能为空!")private Integer id;
}
3.2 服务类
控制器一般不含任何的业务逻辑,它只是将请求委托给相关的服务类。并且为了保持依赖的松散,控制器是不直接依赖于具体类的,而是依赖于接口。
代码清单3.2-1:
//打卡人服务类 :CardPuncherService.javaimport com.baomidou.mybatisplus.extension.service.IService;
import com.xhm.demo.api.entity.CardPuncher;public interface CardPuncherService extends IService<CardPuncher> {/*** 根据id查询打卡人** @param id 打卡人id* @return 打卡人DTO*/CardPuncher queryCardPuncherById(Integer id);
}
代码清单3.2-2,就是接口的对应实现:
// 打卡人服务实现类:CardPuncherServiceImpl.java
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhm.demo.api.entity.CardPuncher;
import com.xhm.demo.api.enums.ValidEnum;
import com.xhm.demo.api.mapper.CardPuncherMapper;
import com.xhm.demo.api.service.CardPuncherService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;@Service
@Slf4j
public class CardPuncherServiceImpl extends ServiceImpl<CardPuncherMapper, CardPuncher> implements CardPuncherService {@Overridepublic CardPuncher queryCardPuncherById(Integer id) {LambdaQueryWrapper<CardPuncher> queryWrapper = Wrappers.lambdaQuery();queryWrapper.eq(CardPuncher::getValid, ValidEnum.VALID.getCode());queryWrapper.eq(CardPuncher::getId, id);return this.getOne(queryWrapper);}
}
服务实现类依赖下面的类:
- ServiceImpl(MyBatis-Plus内置的服务实现类)
- CardPuncherService (服务接口类)
- CardPuncherMapper(Mapper接口)
- CardPuncher
- Wrappers (条件构造器)
3.3 Mapper接口类
Mapper接口类比较简单,因为我们没有自定义脚本,而是调用了 ServiceImpl.getOne
方法。所以 Mapper 接口类中是没有自己的方法的。
代码清单3.3-1:
// 打卡人 Mapper 接口类:CardPuncherMapper.javaimport com.baomidou.mybatisplus.core.mapper.BaseMapper;public interface CardPuncherMapper extends BaseMapper<CardPuncher> {}
3.4 实体类
实体类和数据表的字段是一一对应的,所以其是一个比较重要的类。相关代码如下:
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("t_card_puncher")
public class CardPuncher extends BaseEntity {private static final long serialVersionUID = 1L;/*** 打卡人姓名*/private String name;
}
其中需要重点强调的是:
当数据库中table的名称和实体类名称不一致时,一定需要使用注解
@TableName
进行显示声明表的名称。否则会提示相关的表不存在(例子中默认认为表名是
card_puncher
,而我们的表是有前缀t_
的)
其中的注解 @Accessors(chain = true)
的作用如下:
被该注解修饰的类,setters方法返回的该类的实例(即this),而不是void。所以可以链式地调用setters方法。
链式调用代码如下:
CardPuncher entity = new CardPuncher().setName("老书生");
上述类之间的关系如下图所示:
3.4 不要忘记XML文件
在讲自动配置类时,我们提到过需要指定xml文件的存放位置:
"classpath:/mapper/*Mapper.xml"
那么我们必须在mapper中创建对应的xml文件,否则就会报如下错误:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'cardPuncherController'
: Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException
: Error creating bean with name 'cardPuncherServiceImpl'
: Unsatisfied dependency expressed through field 'baseMapper'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException
: Error creating bean with name 'cardPuncherMapper' defined in file
...
nested exception is java.io.FileNotFoundException: class path resource [mapper/] cannot be resolved to URL because it does not exist
主要错误信息:
java.io.FileNotFoundException: class path resource [mapper/] cannot be resolved to URL because it does not exist
XML文件(CardPuncherMapper.xml)内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xhm.demo.api.mapper.CardPuncherMapper"></mapper>
启动Spring Boot 项目,观察控制台,发现多了MyBatis的banner。并且没有任何报错信息。
移步到端点,可以发现多一个db项:
表明项目中使用了数据库,并且数据库的类型是MySQL。
3.5 发起请求
使用 Postman 发起接口请求。
因为此时表中还没有数据,所以结果如下:
插入1条数据:
insert into my_database.t_card_puncher(`name`,nick,added_by,added_by_name,last_modified_by,last_modified_by_name)
values('老书生','leon',-1,'系统',-1,'系统');
再次请求,结果如下:
可以成功查出数据。到这里 MyBatis 的集成已经初步成功了。
之所以说初步成功,是因为还有一些问题需要解决。如上图中时间格式的问题,2024-06-21T09:31:00
这种时间格式有自己的专有名词:ISO日期时间格式
/ ISO 8601
。
还有一个问题:当Id为空时,没有返回期望的错误信息,而是报400错误:
四、技巧拓展
4.1 如何打印sql语句?
发送请求后,在项目的控制台没有出现期望的sql语句,那么该如何处理才能成功打印sql语句呢?
其实方法也很简单,在 application.yml
中添加如下配置:
# 查看sql
logging:level:com.xhm.demo.api.mapper: debug
其中的 com.xhm.demo.api.mapper
是 Mapper 接口所在的包名。设置其日志级别为debug
打印的sql脚本如下:
2024-06-23 00:26:49.147 DEBUG 40300 --- [nio-8080-exec-6] c.x.d.a.m.CardPuncherMapper.selectOne : ==> Preparing: SELECT id,name,added_by,added_by_name,added_time,last_modified_by,last_modified_by_name,last_modified_time,last_modified_ip,valid FROM t_card_puncher WHERE (valid = ? AND id = ?)
2024-06-23 00:26:49.188 DEBUG 40300 --- [nio-8080-exec-6] c.x.d.a.m.CardPuncherMapper.selectOne : ==> Parameters: 1(Integer), 1(Integer)
2024-06-23 00:26:49.226 DEBUG 40300 --- [nio-8080-exec-6] c.x.d.a.m.CardPuncherMapper.selectOne : <== Total: 1
脚本是出现了,但是似乎不那么完美。如果查询条件比较多,拼接起来还是比较麻烦的。有无其他办法能够查看拼接好的脚本呢?
可以试试一款IDEA插件:MyBatis Log Free
借助这款插件,可以查看完整的sql语句:
如果是第一次使用该插件,可以通过如下方式打开:
【Tools】-> 【MyBatis Log Plugin】
4.2 如何对参数增加非空验证?
非空校验不生效,有两种情况:
- 空条件直接传到sql中
- 接口返回400错误,控制台有
WARN
日志
第一种情况
如果 @NotNull注解在请求类的属性 (如IdRequest类)上。检查Controller的方法的入参是否遗漏 @Valid
注解。
如果已经增加了注解,非空校验依然没有生效,则有可能是maven依赖不完整,可能 pom 中只增加了如下依赖:
<dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId>
</dependency>
有两种解决方法:
-
增加
hibernate-validator
依赖
validation-api
中只定义了相关注解,具体的校验逻辑在hibernate-validator
中。所以需要添加如下依赖:org.hibernate.validator hibernate-validator
-
去除
validation-api
依赖,以下面的依赖进行替换:org.springframework.boot spring-boot-starter-validation
第二种情况
因为没有对 MethodArgumentNotValidException
异常进行处理而导致校验信息没有返回。具体的现象是响应报文的结果如下:
所以需要增加 统一异常处理类 。相关代码如下:
// exception/CommonExceptionHandler.java@Slf4j
@ControllerAdvice
public class CommonExceptionHandler {@ExceptionHandler({MethodArgumentNotValidException.class})@ResponseBodypublic BaseResponse<?> bindMethodArgumentNotValidException(MethodArgumentNotValidException ex) {String traceId = MDC.get("traceId");StringBuilder errorMessage = new StringBuilder();List<FieldError> errors = ex.getBindingResult().getFieldErrors();for (FieldError error : errors) {//只取错误信息errorMessage.append(error.getDefaultMessage()).append(";");}errorMessage.deleteCharAt(errorMessage.length() - 1);log.error(String.format("traceId: %s, Exception: [%s] %s, request error, parameters invalid:%s", traceId, ex.getParameter().getParameterName(), ex, errorMessage));return BaseResponse.error(BaseResultCodeEnum.ERROR.getCode(), errorMessage.toString());}
}
BaseResponse.java代码如下:
@Data
public class BaseResponse<T> implements Serializable {private static final long serialVersionUID = -5330932746124338859L;/*** 响应状态码*/private String code;/*** 响应消息*/private String message;/*** 响应数据*/private T data;public static <K> BaseResponse<K> ok() {return BaseResponse.result(BaseResultCodeEnum.SUCCESS.getCode(), BaseResultCodeEnum.SUCCESS.getMessage());}public static <K> BaseResponse<K> ok(K data) {BaseResponse<K> response = BaseResponse.ok();response.setData(data);return response;}public static <K> BaseResponse<K> error(String message) {return BaseResponse.result(BaseResultCodeEnum.ERROR.getCode(), message);}public static <K> BaseResponse<K> error(String code, String message) {return BaseResponse.result(code, message);}public static <K> BaseResponse<K> result(String code, String message) {BaseResponse<K> response = new BaseResponse<>();response.setCode(code);response.setMessage(message);return response;}
}
4.3 如何查看 Maven 依赖?
有两种查看 Maven 依赖的方式:
- mvn dependency:tree命令
- 使用Idea的
Dependency Analyzer
其中第二种方式依赖 IDEA的插件: Maven Helper
。
第一种方式的演示:
在终端输入如下命令:
mvn dependency:tree
输出结果如下:
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building demo-api 0.0.1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ demo-api ---
[INFO] com.xhm:demo-api:jar:0.0.1-SNAPSHOT
...
[INFO] +- org.projectlombok:lombok:jar:1.18.20:compile (optional)
...
[INFO] +- mysql:mysql-connector-java:jar:8.0.23:runtime
[INFO] - org.springframework.boot:spring-boot-starter-validation:jar:2.3.10.RELEASE:compile
[INFO] +- org.glassfish:jakarta.el:jar:3.0.3:compile
[INFO] - org.hibernate.validator:hibernate-validator:jar:6.1.7.Final:compile
[INFO] +- jakarta.validation:jakarta.validation-api:jar:2.0.2:compile
[INFO] +- org.jboss.logging:jboss-logging:jar:3.4.1.Final:compile
[INFO] - com.fasterxml:classmate:jar:1.5.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.018 s
[INFO] Finished at: 2024-06-25T16:12:36+08:00
[INFO] Final Memory: 26M/304M
[INFO] ------------------------------------------------------------------------
第二种方式的演示:
打开pom文件,从 Text
模式切换到 Dependency Analyzer
模式:
- 选择
All Dependencies as Tree
,点击 “Refresh UI” 按钮- 收缩树形结构(全部)
- 展开
spring-boot-starter-validation
,可以看到其依赖项。如图所示,其依赖于
hibernate-validator
,而hibernate-validator
又依赖于jakarta.validation-api
(替换validation-api
包含注解javax.validation.constraints.NotNull
)
4.3 如何解决时间格式问题?
前面我提到过接口返回的日期时间格式默认是:ISO日期时间格式
。而很多时候我们需要指定的日期时间格式。如:
- 当提到出生日期是,时间精度至少需要精确到天,在中国一般的日期格式是:
2024-06-20
- 但是当我们需要获知订单的创建时间时,可能需要这样的时间格式:
2024-06-21 08:30:50
要解决这个问题,其实也比较简单,可以使用 jackson-annotation
包中的注解 @JsonFormat
对日期时间格式进行自定义。
下面使用该注解对 BaseEntity
进行功能增强:
@Data
public class BaseEntity implements Serializable {
.../*** 新增时间*/@JsonFormat(pattern = "yyyy-MM-dd")private LocalDateTime addedTime;.../*** 最后修改时间*/@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime lastModifiedTime;
}
这里只是为了演示的方便,生产代码不建议这样写:
直接将实体类暴露给最终用户不是一个好的实践,因为一旦字段发生变动,就需要客户代码进行相应的调整。
普遍的做法是:引入DTO作为接口的数据载体。所以@JsonFormat
注解也是打在DTO类上。
4.4 如何快速增加 serialVersionUID
属性?
对于可序列化的类,一般强烈建议显式声明 serialVersionUID 值。因为默认计算得到的 serialVersionUID 值可能会引发 InvalidClassException
。那么有没有什么快速的方法去完成这件事情呢?
如果你使用的是 IDEA ,可以参考下面的方法:
- 打开 Settings 窗口,输入搜索词:
serial
。- 在【Editor】-【Inspections】中找到:【Java】- 【Serializatioin issues】。
- 然后勾选其中的
Serializable class without serialVersionUID
。
上面设置的作用是:如果一个类实现了Serializable接口,但是没有声明 serialVersionUID 值,就会告警。
F2 定位到告警信息后,再组合按键 Alt + Enter ,弹出上图的信息后,再按一次 Enter 后,就可以快速插入 serialVersionUID
值了。使用该方式生成的 serialVersionUID
能很好地避免重复的问题。
五、总 结
本文详细讲述了如何在Spring Boot 项目中集成 MyBatis-Plus,其中的设置和依赖都遵循最小功能集的原则。
增加集成相关的配置和依赖后,我们又创建了一个简单的接口,用于验证本次集成是否成功。其中谈到了SSM项目中基本的项目结构,相关代码都是从生产代码中抽象出来的,具有很强的参考意义。文中还以类图的形式给出了各个类之间的关系,可以帮助读者更好地理解代码结构。
接口测试时,我们使用了post工具,Postman是其中比较常见的一款。通过接口可以成功返回数据,但是数据的格式有一些问题。文章对这些问题的解决进行了细致地阐述。
最后还分享了实际开发中可能会用到的一些小技巧,希望可以启动抛砖引玉的作用。有交流意愿的小伙伴可以在评论区进行留言。
参考资料:
- iBatis详解以及和MyBatis区别
- MyBatis-Plus
- maven的mvn dependency依赖分析和常用命令介绍
- Spring Boot 中 validation-api…
- Oracle、SqlServer、Mysql、PostgreSQL数据库的选型
- ORM是什么?如何理解ORM
相关文章:
Spring Boot 集成MyBatis-Plus
文章目录 一、背景说明二、集成过程 2.1 引入 maven 依赖2.2 增加属性配置2.3 自动配置类 三、验证集成 3.1 控制器3.2 服务类3.3 Mapper接口类3.4 实体类3.4 不要忘记XML文件3.5 发起请求 四、技巧拓展 4.1 如何打印sql语句?4.2 如何对参数增加非空验证?…...
javacv将视频切分为m3u8视频并播放
学习链接 ffmpeg-demo 当前对应的 gitee代码 Spring boot视频播放(解决MP4大文件无法播放),整合ffmpeg,用m3u8切片播放。 springboot 通过javaCV 实现mp4转m3u8 上传oss 如何保护会员或付费视频?优酷是怎么做的? - HLS 流媒体加密 ffmpe…...
Docker 入门与实战:从安装到容器管理的完整指南
🚀 Docker 入门与实战:从安装到容器管理的完整指南 🌟 📖 简介 在现代软件开发中,容器化技术已经成为不可或缺的一部分。而 Docker 作为容器化领域的领头羊,以其轻量级、高效和跨平台的特性,深…...
计算机视觉:卷积神经网络(CNN)基本概念(二)
第一章:计算机视觉中图像的基础认知 第二章:计算机视觉:卷积神经网络(CNN)基本概念(一) 第三章:计算机视觉:卷积神经网络(CNN)基本概念(二) 第四章:搭建一个经典的LeNet5神经网络 接上一篇《计算机视觉&am…...
SQL SERVER的PARTITION BY应用场景
SQL SERVER的PARTITION BY关键字说明介绍 PARTITION BY关键字介绍具体使用场景排名计算累计求和分组求最值分组内百分比计算分组内移动平均计算分组内数据分布统计分组内数据偏移计算 总结 PARTITION BY关键字介绍 在SQL SERVER中,关键字PARTITION BY主要用于窗口函…...
【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第十二节】
ISO 14229-1:2023 UDS诊断服务测试用例全解析(TesterPresent_0x3E服务) 作者:车端域控测试工程师 更新日期:2025年02月14日 关键词:UDS协议、0x3E服务、会话保持、ISO 14229-1:2023、ECU测试 一、服务功能概述 0x3E服…...
gsoap实现webservice服务
gsoap实现webservice服务 在实现Web服务时,使用gSOAP是一个很好的选择,因为它提供了强大的工具和库来创建SOAP和RESTful服务。gSOAP是一个C和C语言开发的库,它支持SOAP协议的各种版本,包括SOAP 1.1和SOAP 1.2。下面是如何使用gSO…...
达梦:dmserver占用io高排查
目录标题 1. 使用达梦数据库的性能视图查询当前活动会话查询执行时间较长的 SQL 2. 使用 DM 性能监视工具3. 使用操作系统工具监控 I/Oiostat 工具dstat 工具 4. 优化查询和索引审查 SQL 执行计划优化索引 5. 调整数据库参数6. 分析数据库日志7. 硬件和存储检查总结 针对达梦数…...
MoE架构中的专家选择门控机制:稀疏激活如何实现百倍效率突破?
技术原理(数学公式与核心逻辑) 核心公式 门控网络输出: G ( x ) Softmax ( W g ⋅ x b g ) G(x) \text{Softmax}(W_g \cdot x b_g) G(x)Softmax(Wg⋅xbg) 最终输出: y ∑ i 1 n G i ( x ) ⋅ E i ( x ) (仅保留Top-…...
用python写一个聊天室程序
下面是一个简单的基于Socket的Python聊天室程序示例,包括服务器端和客户端: 服务器端代码: import socket import threadingdef handle_client(client, address):print(f"New connection from {address}")while True:msg client…...
七星棋牌全开源修复版源码解析:6端兼容,200种玩法全面支持
本篇文章将详细讲解 七星棋牌修复版源码 的 技术架构、功能实现、二次开发思路、搭建教程 等内容,助您快速掌握该棋牌系统的开发技巧。 1. 七星棋牌源码概述 七星棋牌修复版源码是一款高度自由的 开源棋牌项目,该版本修复了原版中的多个 系统漏洞&#…...
Vulhub靶机 ActiveMQ任意 文件写入(CVE-2016-3088)(渗透测试详解)
一、开启vulhub环境 docker-compose up -d 启动 docker ps 查看开放的端口 漏洞版本:ActiveMQ在5.14.0之前的版本(不包括5.14.0) 二、访问靶机IP 8161端口 默认账户密码都是admin 1、利用bp抓包,修改为PUT方法并在fileserver…...
Cloud: aws:network: limit 含有pps这种限制
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/troubleshooting-ena.html#statistics-ena 这个是调查网络问题的一个网页; 在里面,竟然含有pps这种限制:ethtool -S;其实是比较苛刻的安全相关的策略? [ec2-user ~]$ ethtool -S ethN NIC statistics:tx_timeout: …...
28、深度学习-自学之路-NLP自然语言处理-做一个完形填空,让机器学习更多的内容程序展示
import sys,random,math from collections import Counter import numpy as npnp.random.seed(1) random.seed(1) f open(reviews.txt) raw_reviews f.readlines() f.close()tokens list(map(lambda x:(x.split(" ")),raw_reviews))#wordcnt Counter() 这行代码的…...
观察者模式说明(C语言版本)
观察者模式主要是为了实现一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。下面使用C语言实现了一个具体的应用示例,有需要的可以参考…...
LC-搜索二维矩阵II、相交链表、反转链表、回文链表、环形链表、环形链表ll
搜索二维矩阵II 方法:从右上角开始搜索 我们可以从矩阵的右上角开始进行搜索。如果当前元素 matrix[i][j] 等于 target,我们直接返回 true。如果 matrix[i][j] 大于 target,说明 target 只能出现在左边的列,所以我们将列指针向左…...
如何查看 Linux 服务器的 MAC 地址:深入解析与实践指南
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...
国产FPGA开发板选择
FPGA开发板是学习和开发FPGA的重要工具,选择合适的开发板对学习效果和开发效率至关重要。随着国产FPGA的发展,淘宝上的许多FPGA开发板店铺也开始进行国产FPGA的设计和销售,本文将对国产FPGA和相关店铺做个简单梳理,帮助有需要使用…...
iOS 获取设备占用内存
获取应用占用内存 获取应用进程占用内存 - (NSUInteger)memoryUsage {task_vm_info_data_t vmInfo;mach_msg_type_number_t count TASK_VM_INFO_COUNT;kern_return_t result task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vmInfo, &count);if (result …...
用自己的数据训练yolov11目标检测
文章目录 概要理论知识整体架构流程架构优化多任务支持多参数体量 操作实操环境配置数据准备数据标注数据放置路径 训练预测 概要 官网:https://github.com/ultralytics/ultralytics?tabreadme-ov-file 提示:以 停车场空位检测 公开数据集示例&#x…...
golang如何将结构体和函数进行绑定?
在Go语言中,结构体和函数的绑定通常通过方法(method)来实现。方法是一种特殊的函数,它与某个类型关联,特别是结构体类型。下面是如何将结构体和函数进行绑定的具体步骤: 定义结构体:首先需要定义…...
【苍穹外卖】学习
软件开发整体介绍 作为一名软件开发工程师,我们需要了解在软件开发过程中的开发流程, 以及软件开发过程中涉及到的岗位角色,角色的分工、职责, 并了解软件开发中涉及到的三种软件环境。那么这一小节,我们将从 软件开发流程、角色…...
架构——LVS负载均衡主要模式及其原理、服务水平、优缺点
LVS(Linux Virtual Server)是一款高性能的开源负载均衡软件,支持多种负载均衡模式。以下是其主要模式及其原理、服务水平、优缺点: 1. NAT 模式(Network Address Translation) 原理: 请求流程…...
DFS算法篇:理解递归,熟悉递归,成为递归
1.DFS原理 那么dfs就是大家熟知的一个深度优先搜索,那么听起来很高大尚的一个名字,但是实际上dfs的本质就是一个递归,而且是一个带路径的递归,那么递归大家一定很熟悉了,大学c语言课程里面就介绍过递归,我…...
让编程变成一种享受-明基RD320U显示器
引言 作为一名有着多年JAVA开发经验的从业者,在工作过程中,显示器的重要性不言而喻。它不仅是我们与代码交互的窗口,更是影响工作效率和体验的关键因素。在多年的编程生涯中,我遇到过各种各样的问题。比如,在进行代码…...
C语言简单练习题
文章目录 练习题一、计算n的阶乘bool类型 二、计算1!2!3!...10!三、计算数组arr中的元素个数二分法查找 四、动态打印字符Sleep()ms延时函数system("cls")清屏函数 五、模拟用户登录strcmp()函数 六、猜数字小游戏产生一个随机数randsrandRAND_MAX时间戳time() 示例 …...
基于Python的深度学习音乐推荐系统(有配套论文)
音乐推荐系统 提供实时音乐推荐功能,根据用户行为和偏好动态调整推荐内容 Python、Django、深度学习、卷积神经网络 、算法 数据库:MySQL 系统包含角色:管理员、用户 管理员功能:用户管理、系统设置、音乐管理、音乐推荐管理、系…...
Java:单例模式(Singleton Pattern)及实现方式
一、单例模式的概念 单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来访问该实例,是 Java 中最简单的设计模式之一。该模式常用于需要全局唯一实例的场景,例如日志记录器、配置管理、线程池、数据库…...
解锁养生秘籍,拥抱健康生活
在这个快节奏的时代,人们行色匆匆,常常在忙碌中忽略了健康。其实,养生并非遥不可及,它就藏在生活的细微之处,等待我们去发现和实践。 规律作息是健康的基础。日出而作,日落而息,顺应自然规律&am…...
数据结构之堆(Heap)
数据结构之堆(Heap) 数据结构之堆(Heap)一、堆的核心概念1. 定义与性质2. 存储方式 二、核心操作与算法1. 操作复杂度概览2. 关键操作详解(1) 向上调整(Sift Up)(2) 向下调整(Sift Down…...
人工智能 - 机器学习、深度学习、强化学习是人工智能领域的理论基础和方法论
机器学习、深度学习、强化学习是人工智能领域的三大核心方向,各自具有独特的理论基础和方法论。以下是它们的核心理论知识总结: 一、机器学习(Machine Learning, ML) 1. 基础概念 目标:通过数据驱动的方式,让机器从经验中学习规律,完成预测、分类或决策任务。 核心范式…...
github上文件过大无法推送问题
GitHub 对文件大小有限制,超过 100 MB 的文件无法直接推送到仓库中。 解决思路: 使用 Git Large File Storage (Git LFS) 来管理大文件不上传对应的大文件 使用Git LFS: 1. 安装 Git LFS 首先,你需要安装 Git LFS。可以按照以…...
Elasticsearch:将 Ollama 与推理 API 结合使用
作者:来自 Elastic Jeffrey Rengifo Ollama API 与 OpenAI API 兼容,因此将 Ollama 与 Elasticsearch 集成非常容易。 在本文中,我们将学习如何使用 Ollama 将本地模型连接到 Elasticsearch 推理模型,然后使用 Playground 向文档提…...
【Linux】详谈 进程控制
目录 一、进程是什么 二、task_struct 三、查看进程 四、创建进程 4.1 fork函数的认识 4.2 2. fork函数的返回值 五、进程终止 5.1. 进程退出的场景 5.2. 进程常见的退出方法 5.2.1 从main返回 5.2.1.1 错误码 5.2.2 exit函数 5.2.3 _exit函数 5.2.4 缓冲区问题补…...
构建高效智能对话前端:基于Ant Design X 的deepseek对话应用
文章目录 实现的效果前言Ant Design X添加欢迎组件创建对话气泡存储对话历史渲染对话气泡 输入组件WebSocket 连接总结 实现的效果 待机页面: 等待页面: 完成页面: 前言 随着人工智能技术的飞速发展,大模型对话系统已成为…...
WordPress“更新失败,响应不是有效的JSON响应”问题的修复
在使用WordPress搭建网站时,许多人在编辑或更新文章时,可能会遇到一个提示框,显示“更新失败,响应不是有效的JSON响应”。这个提示信息对于不了解技术细节的用户来说,太难懂。其实,这个问题并不复杂&#x…...
华为交换机trunk简介配置
目录 一、Trunk 口简介二、Trunk 口配置案例及命令(一)组网需求(二)配置步骤(三)验证配置 三、注意事项 一、Trunk 口简介 Trunk 口是交换机中一种重要的端口类型,主要用于连接交换机与交换机、…...
DeepSeek从入门到精通(清华大学)
DeepSeek是一款融合自然语言处理与深度学习技术的全能型AI助手,具备知识问答、数据分析、编程辅助、创意生成等多项核心能力。作为多模态智能系统,它不仅支持文本交互,还可处理文件、图像、代码等多种格式输入,其知识库更新至2…...
【SpringBoot3】面向切面 AspectJ AOP 使用详解
文章目录 一、AspectJ介绍二、简单使用步骤 1、引入依赖2、定义一个Aspect3、开启AOP支持 三、AOP 核心概念四、切点(Pointcut) 1. execution2. within3. this & target4. args & args5. within & target & annotation 五、通知…...
容器运行常见数据库
一.涉及镜像压缩包 均为amd架构版本:mysql:5.7.42、postgres:13.16、dm8:20250206_rev257733_x86_rh6_64、oceanbase-ce:v4.0、opengauss:5.0.2 通过网盘分享的文件:db.tgz 链接: https://pan.baidu.com/s/1EBbFPZj1FxCA4_GxjVunWg?pwd563s 提取码: 5…...
OpenGL ES学习大纲
如果您想从头学习 OpenGL ES,以下是一个详细的学习大纲,涵盖了从基础到高级的知识点,循序渐进地帮助您掌握 OpenGL ES 的核心概念、API 使用、渲染管线、着色器编程、性能优化等内容。 1. 学习前的准备 1.1 基础知识 在学习 OpenGL ES 之前,您需要掌握以下基础知识: 数学…...
Kotlin 优雅的接口实现
1. 日常遇到的冗余的接口方法实现 日常开发中,经常会要实现接口,但是很多场景中,只需要用到其中一两个方法,例如 ActivityLifecycleCallbacks,它有很多个接口需要实现,但是很多时候我们只需要用到其中的一…...
数据结构实现顺序表的尾插,尾删,按值查找/修改/删除,按下标查找/增加/删除
头文件:head.h #ifndef __HEAD_H__ #define __HEAD_H__#include <stdio.h> #include <string.h> #include <stdlib.h> #define MAXSIZE 20enum num {success,false-1};typedef int datatype;typedef struct {int len;datatype data[MAXSIZE]; }S…...
qt实现文字跑马灯效果
实现跑马灯的方式多种多少样,可以通过定时器,或者animation等来实现。 本文通过定时器,将第一个文字,移动到最后一个这种方式来实现,还有其他方式哈。 直接上源码 h文件 #ifndef TEXTTICKER_H #define TEXTTICKER_…...
PyTorch Tensor 形状变化操作详解
PyTorch Tensor 形状变化操作详解 在深度学习中,Tensor 的形状变换是非常常见的操作。PyTorch 提供了丰富的 API 来帮助我们调整 Tensor 的形状,以满足模型输入、计算或数据处理的需求。本文将详细介绍 PyTorch 中常见的 Tensor 形状变换操作࿰…...
关于Node.js前端面试的试题概念、工作原理及实际应用
文章目录 1. 什么是Node.js?2. Node.js是如何工作的?3. Node.js与其他流行的框架相比有何优势?4. Node.js如何克服I/O操作阻塞的问题?5. 为什么Node.js是单线程的?6. 如果Node.js是单线程的,那么它是如何处…...
OpenCV机器学习(3)期望最大化(Expectation-Maximization, EM)算法cv::ml::EM
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::ml::EM 是 OpenCV 机器学习模块中的一部分,用于实现期望最大化(Expectation-Maximization, EM)算法。EM …...
Spring Boot 集成 Kettle
Kettle 简介 Kettle 最初由 Matt Casters 开发,是 Pentaho 数据集成平台的一部分。它提供了一个用户友好的界面和丰富的功能集,使用户能够轻松地设计、执行和监控 ETL 任务。Kettle 通过其强大的功能和灵活性,帮助企业高效地处理大规模数据集…...
Debezium同步之如何同步GIS数据
Debezium 可以用于同步数据库中的变更数据(CDC),包括GIS(地理信息系统)数据。GIS 数据通常存储在具有地理空间数据类型的表中,例如 PostGIS(PostgreSQL 的扩展)中的 geometry 或 geography 类型。通过 Debezium,可以实时捕获和同步这类数据的变更。本文章简单介绍Post…...
Java与C语言中取模运算符%的区别对比
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: Java 文章目录 💯前言💯C语言中的取模运算符 %基本行为示例 注意事项示例:负数取模 💯Java中的取模运算符 %基本行为示例 对浮点数的支持示例:浮点数取模 符…...