超全分析MybatisPlus中的MetaObjectHandler全局字段填充的基本知识(附Demo及实战)

news2025/4/4 4:22:23

目录

  • 前言
  • 1. 源码及API
  • 2. Demo架构
  • 3. 全局字段填充(实战)
  • 4. 局部字段不填充(实战)

前言

对于Java的相关知识推荐阅读:

  1. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
  2. 【Java项目】实战CRUD的功能整理(持续更新)

MetaObjectHandler 是 MyBatis-Plus 提供的一个接口,用于处理在插入更新操作时的一些公共字段的自动填充

在这里插入图片描述

比如,在插入记录时自动填充 createTime 字段,在更新记录时自动填充 updateTime 字段
(一开始实战过程中莫名其妙的填充了这两个数据值,但是查找数据库触发器确没有这个,好奇哪里触发的,给我上了一课,对此详细研究并且科普该知识点)

1. 源码及API

通过源码分析各个方法:

/*
 * Copyright (c) 2011-2023, baomidou (jobob@qq.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.baomidou.mybatisplus.core.handlers;

import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import org.apache.ibatis.reflection.MetaObject;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * 元对象字段填充控制器抽象类,实现公共字段自动写入<p>
 * <p>
 * 所有入参的 MetaObject 必定是 entity 或其子类的 MetaObject
 *
 * @author hubin
 * @since 2016-08-28
 */
public interface MetaObjectHandler {

    /**
     * 是否开启了插入填充
     */
    default boolean openInsertFill() {
        return true;
    }

    /**
     * 是否开启了更新填充
     */
    default boolean openUpdateFill() {
        return true;
    }

    /**
     * 插入元对象字段填充(用于插入时对公共字段的填充)
     *
     * @param metaObject 元对象
     */
    void insertFill(MetaObject metaObject);

    /**
     * 更新元对象字段填充(用于更新时对公共字段的填充)
     *
     * @param metaObject 元对象
     */
    void updateFill(MetaObject metaObject);

    /**
     * 通用填充
     *
     * @param fieldName  java bean property name
     * @param fieldVal   java bean property value
     * @param metaObject meta object parameter
     */
    default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) {
        if (Objects.nonNull(fieldVal) && metaObject.hasSetter(fieldName)) {
            metaObject.setValue(fieldName, fieldVal);
        }
        return this;
    }

    /**
     * get value from java bean by propertyName
     *
     * @param fieldName  java bean property name
     * @param metaObject parameter wrapper
     * @return 字段值
     */
    default Object getFieldValByName(String fieldName, MetaObject metaObject) {
        return metaObject.hasGetter(fieldName) ? metaObject.getValue(fieldName) : null;
    }

    /**
     * find the tableInfo cache by metaObject </p>
     * 获取 TableInfo 缓存
     *
     * @param metaObject meta object parameter
     * @return TableInfo
     * @since 3.3.0
     */
    default TableInfo findTableInfo(MetaObject metaObject) {
        return TableInfoHelper.getTableInfo(metaObject.getOriginalObject().getClass());
    }

    /**
     * @param metaObject metaObject meta object parameter
     * @return this
     * @since 3.3.0
     */
    default <T, E extends T> MetaObjectHandler strictInsertFill(MetaObject metaObject, String fieldName, Class<T> fieldType, E fieldVal) {
        return strictInsertFill(findTableInfo(metaObject), metaObject, Collections.singletonList(StrictFill.of(fieldName, fieldType, fieldVal)));
    }

    /**
     * @param metaObject metaObject meta object parameter
     * @return this
     * @since 3.3.0
     */
    default <T, E extends T> MetaObjectHandler strictInsertFill(MetaObject metaObject, String fieldName, Supplier<E> fieldVal, Class<T> fieldType) {
        return strictInsertFill(findTableInfo(metaObject), metaObject, Collections.singletonList(StrictFill.of(fieldName, fieldVal, fieldType)));
    }

    /**
     * @param metaObject metaObject meta object parameter
     * @return this
     * @since 3.3.0
     */
    default MetaObjectHandler strictInsertFill(TableInfo tableInfo, MetaObject metaObject, List<StrictFill<?, ?>> strictFills) {
        return strictFill(true, tableInfo, metaObject, strictFills);
    }

    /**
     * @param metaObject metaObject meta object parameter
     * @return this
     * @since 3.3.0
     */
    default <T, E extends T> MetaObjectHandler strictUpdateFill(MetaObject metaObject, String fieldName, Supplier<E> fieldVal, Class<T> fieldType) {
        return strictUpdateFill(findTableInfo(metaObject), metaObject, Collections.singletonList(StrictFill.of(fieldName, fieldVal, fieldType)));
    }

    /**
     * @param metaObject metaObject meta object parameter
     * @return this
     * @since 3.3.0
     */
    default <T, E extends T> MetaObjectHandler strictUpdateFill(MetaObject metaObject, String fieldName, Class<T> fieldType, E fieldVal) {
        return strictUpdateFill(findTableInfo(metaObject), metaObject, Collections.singletonList(StrictFill.of(fieldName, fieldType, fieldVal)));
    }

    /**
     * @param metaObject metaObject meta object parameter
     * @return this
     * @since 3.3.0
     */
    default MetaObjectHandler strictUpdateFill(TableInfo tableInfo, MetaObject metaObject, List<StrictFill<?, ?>> strictFills) {
        return strictFill(false, tableInfo, metaObject, strictFills);
    }

    /**
     * 严格填充,只针对非主键的字段,只有该表注解了fill 并且 字段名和字段属性 能匹配到才会进行填充(null 值不填充)
     *
     * @param insertFill  是否验证在 insert 时填充
     * @param tableInfo   cache 缓存
     * @param metaObject  metaObject meta object parameter
     * @param strictFills 填充信息
     * @return this
     * @since 3.3.0
     */
    default MetaObjectHandler strictFill(boolean insertFill, TableInfo tableInfo, MetaObject metaObject, List<StrictFill<?, ?>> strictFills) {
        if ((insertFill && tableInfo.isWithInsertFill()) || (!insertFill && tableInfo.isWithUpdateFill())) {
            strictFills.forEach(i -> {
                final String fieldName = i.getFieldName();
                final Class<?> fieldType = i.getFieldType();
                tableInfo.getFieldList().stream()
                    .filter(j -> j.getProperty().equals(fieldName) && fieldType.equals(j.getPropertyType()) &&
                        ((insertFill && j.isWithInsertFill()) || (!insertFill && j.isWithUpdateFill()))).findFirst()
                    .ifPresent(j -> strictFillStrategy(metaObject, fieldName, i.getFieldVal()));
            });
        }
        return this;
    }

    /**
     * 填充策略,默认有值不覆盖,如果提供的值为null也不填充
     *
     * @param metaObject metaObject meta object parameter
     * @param fieldName  java bean property name
     * @param fieldVal   java bean property value of Supplier
     * @return this
     * @since 3.3.0
     */
    default MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) {
        if (getFieldValByName(fieldName, metaObject) == null) {
            setFieldValByName(fieldName, fieldVal, metaObject);
        }
        return this;
    }

    /**
     * 严格模式填充策略,默认有值不覆盖,如果提供的值为null也不填充
     *
     * @param metaObject metaObject meta object parameter
     * @param fieldName  java bean property name
     * @param fieldVal   java bean property value of Supplier
     * @return this
     * @since 3.3.0
     */
    default MetaObjectHandler strictFillStrategy(MetaObject metaObject, String fieldName, Supplier<?> fieldVal) {
        if (metaObject.getValue(fieldName) == null) {
            Object obj = fieldVal.get();
            if (Objects.nonNull(obj)) {
                metaObject.setValue(fieldName, obj);
            }
        }
        return this;
    }
}

对应的代码都较为简单,此处以API的概念属性以及如何调用进行讲解

方法名概念作用参数调用方式
openInsertFill()检查是否开启插入填充返回布尔值,表示是否在插入时进行字段填充boolean open = metaObjectHandler.openInsertFill();
openUpdateFill()检查是否开启更新填充返回布尔值,表示是否在更新时进行字段填充boolean open = metaObjectHandler.openUpdateFill();
insertFill(MetaObject metaObject)插入操作时填充元对象字段定义插入时的字段自动填充逻辑MetaObject metaObject: 元对象metaObjectHandler.insertFill(metaObject);
updateFill(MetaObject metaObject)更新操作时填充元对象字段定义更新时的字段自动填充逻辑MetaObject metaObject: 元对象metaObjectHandler.updateFill(metaObject);
setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)通用字段填充方法根据字段名设置字段值String fieldName: 字段名
Object fieldVal: 字段值
MetaObject metaObject: 元对象
metaObjectHandler.setFieldValByName(“fieldName”, fieldVal, metaObject);
getFieldValByName(String fieldName, MetaObject metaObject)获取字段值根据字段名获取字段值String fieldName: 字段名
MetaObject metaObject: 元对象
Object value = metaObjectHandler.getFieldValByName(“fieldName”, metaObject);
findTableInfo(MetaObject metaObject)获取表信息根据元对象查找表信息缓存MetaObject metaObject: 元对象TableInfo tableInfo = metaObjectHandler.findTableInfo(metaObject);
strictInsertFill(MetaObject metaObject, String fieldName, Class fieldType, E fieldVal)严格模式插入填充在插入操作时严格填充指定字段MetaObject metaObject: 元对象
String fieldName: 字段名
Class fieldType: 字段类型
E fieldVal: 字段值
metaObjectHandler.strictInsertFill(metaObject, “fieldName”, fieldType, fieldVal);
strictInsertFill(MetaObject metaObject, String fieldName, Supplier fieldVal, Class fieldType)严格模式插入填充在插入操作时严格填充指定字段MetaObject metaObject: 元对象
String fieldName: 字段名
Supplier fieldVal: 字段值提供者
Class fieldType: 字段类型
metaObjectHandler.strictInsertFill(metaObject, “fieldName”, fieldVal, fieldType);
strictInsertFill(TableInfo tableInfo, MetaObject metaObject, List<StrictFill<?, ?>> strictFills)严格模式插入填充在插入操作时严格填充指定字段TableInfo tableInfo: 表信息
MetaObject metaObject: 元对象
List<StrictFill<?, ?>> strictFills: 填充信息列表
metaObjectHandler.strictInsertFill(tableInfo, metaObject, strictFills);
strictUpdateFill(MetaObject metaObject, String fieldName, Supplier fieldVal, Class fieldType)严格模式更新填充在更新操作时严格填充指定字段MetaObject metaObject: 元对象
String fieldName: 字段名
Supplier fieldVal: 字段值提供者
Class fieldType: 字段类型
metaObjectHandler.strictUpdateFill(metaObject, “fieldName”, fieldVal, fieldType);
strictUpdateFill(MetaObject metaObject, String fieldName, Class fieldType, E fieldVal)严格模式更新填充在更新操作时严格填充指定字段MetaObject metaObject: 元对象
String fieldName: 字段名
Class fieldType: 字段类型
E fieldVal: 字段值
metaObjectHandler.strictUpdateFill(metaObject, “fieldName”, fieldType, fieldVal);
strictUpdateFill(TableInfo tableInfo, MetaObject metaObject, List<StrictFill<?, ?>> strictFills)严格模式更新填充在更新操作时严格填充指定字段TableInfo tableInfo: 表信息
MetaObject metaObject: 元对象
List<StrictFill<?, ?>> strictFills: 填充信息列表
metaObjectHandler.strictUpdateFill(tableInfo, metaObject, strictFills);
strictFill(boolean insertFill, TableInfo tableInfo, MetaObject metaObject, List<StrictFill<?, ?>> strictFills)严格填充策略根据表信息和元对象进行严格的插入或更新填充boolean insertFill: 插入/更新标志
TableInfo tableInfo: 表信息
MetaObject metaObject: 元对象
List<StrictFill<?, ?>> strictFills: 填充信息列表
metaObjectHandler.strictFill(insertFill, tableInfo, metaObject, strictFills);
fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal)填充策略根据策略填充字段值,默认是字段值为null时才填充MetaObject metaObject: 元对象
String fieldName: 字段名
Object fieldVal: 字段值
metaObjectHandler.fillStrategy(metaObject, “fieldName”, fieldVal);
strictFillStrategy(MetaObject metaObject, String fieldName, Supplier<?> fieldVal)严格模式填充策略严格填充字段值,只有在当前字段值为null时才填充MetaObject metaObject: 元对象
String fieldName: 字段名
Supplier<?> fieldVal: 字段值提供者
metaObjectHandler.strictFillStrategy(metaObject, “fieldName”, fieldVal);

方法包括检查是否开启填充、具体的填充实现、字段值的设置和获取策略

2. Demo架构

具体的示例如下:

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        System.out.println("start insert fill ....");
        // 使用 strictInsertFill 方法插入时间字段
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        System.out.println("start update fill ....");
        // 使用 strictUpdateFill 方法更新时间字段
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

常用的填充方法如下:

  • strictInsertFill: 严格模式下的插入填充,只有在字段为 null 时才会填充,避免覆盖已有值
  • strictUpdateFill: 严格模式下的更新填充,只有在字段为 null 时才会填充,避免覆盖已有值
  • fillStrategy::指定填充策略,可选值包括 NOT_NULL(仅当字段为 null 时填充)和 DEFAULT(无条件填充)

对应的实体类如下:

@TableName("user")
public class User {

    @TableId(type = IdType.AUTO)
    private Long id;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    // getters and setters
}

上述注解的说明如下(源码说明):

public enum FieldFill {
    /**
     * 默认不处理
     */
    DEFAULT,
    /**
     * 插入时填充字段
     */
    INSERT,
    /**
     * 更新时填充字段
     */
    UPDATE,
    /**
     * 插入和更新时填充字段
     */
    INSERT_UPDATE
}

对应还需要增加一个配置类:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MetaObjectHandler metaObjectHandler() {
        return new MyMetaObjectHandler();
    }
}

最终执行插入操作并更新:

User user = new User();
userMapper.insert(user);
// user.getCreateTime() 会被自动填充
userMapper.updateById(user);

此种情况下自动填充属性会失效

  • 字段未使用 @TableField 注解:未使用 @TableField 注解或 fill 属性未设置为 FieldFill.INSERTFieldFill.UPDATE,自动注入将不会生效

  • 未实现 MetaObjectHandler 接口:MyBatis-Plus 将不知道如何处理自动填充逻辑。

  • 未在配置类中注册 MetaObjectHandler:即使实现了 MetaObjectHandler 接口,如果未在 Spring 配置类中进行注册,自动填充也不会生效

3. 全局字段填充(实战)

一些开源项目经常会让我们在创建表的过程中需要保留一些字段,究其原因是属性的自动填充

对于项目中

public class DefaultDBFieldHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
    
        if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
            BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();

            LocalDateTime current = LocalDateTime.now();
            // 创建时间为空,则以当前时间为插入时间
            if (Objects.isNull(baseDO.getCreateTime())) {
                baseDO.setCreateTime(current);
            }
            // 更新时间为空,则以当前时间为更新时间
            if (Objects.isNull(baseDO.getUpdateTime())) {
                baseDO.setUpdateTime(current);
            }
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 更新时间为空,则以当前时间为更新时间
        Object modifyTime = getFieldValByName("updateTime", metaObject);
        if (Objects.isNull(modifyTime)) {
            setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
        }
    }
}

其中BaseDO是我的一些固有属性类:

@Data
@JsonIgnoreProperties(value = "transMap") // 避免 Jackson 在 Spring Cache 反序列化报错
public abstract class BaseDO implements Serializable, TransPojo {

    /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    /**
     * 最后更新时间
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    /**
     * 创建者,目前使用 SysUser 的 id 编号
     *
     * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
     */
    @TableField(fill = FieldFill.INSERT, jdbcType = JdbcType.VARCHAR)
    private String creator;
    /**
     * 更新者,目前使用 SysUser 的 id 编号
     *
     * 使用 String 类型的原因是,未来可能会存在非数值的情况,留好拓展性。
     */
    @TableField(fill = FieldFill.INSERT_UPDATE, jdbcType = JdbcType.VARCHAR)
    private String updater;
    /**
     * 是否删除
     */
    @TableLogic
    private Boolean deleted;

}

同步增加其配置类:

public class MybatisAutoConfiguration {

    @Bean
    public MetaObjectHandler defaultMetaObjectHandler(){
        return new DefaultDBFieldHandler(); // 自动填充参数类
    }
}

对应正式的功能如下:

@Service
@Validated
public class GoodsStoragePlanServiceImpl implements GoodsStoragePlanService {

    @Resource
    private GoodsStoragePlanMapper goodsStoragePlanMapper;

    @Resource
    private AdminUserService userService;


    @Override
    public Long createGoodsStoragePlan(GoodsStoragePlanSaveReqVO createReqVO) {
        // 插入
        GoodsStoragePlanDO goodsStoragePlan = BeanUtils.toBean(createReqVO, GoodsStoragePlanDO.class);
        goodsStoragePlanMapper.insert(goodsStoragePlan);
    }
}

后续便会自动填充相应的属性

4. 局部字段不填充(实战)

代码和第三章的实战差不多,在上面代码的改进

需求:

上面的创建是增加时间和修改时间都会被自动注入
由于我这个只需要增加时间自动注入,修改时间只有在创建的时候自动注入,创建的时候需要为空

增加临时禁用全局字段的填充机制:引入一个上下文变量来控制是否启用字段填充

  1. 创建一个 ThreadLocal 变量来控制是否启用字段填充:
    ThreadLocal 变量为每个线程提供了独立的变量副本,从而保证了线程安全
    每个线程可以独立地访问其 ThreadLocal 变量副本,而不会影响其他线程
/**
 * FieldFillContext 类用于控制全局字段填充机制。
 * 使用 ThreadLocal 变量来保证线程安全,实现线程独立的变量副本。
 */
public class FieldFillContext {

    /**
     * ThreadLocal 变量,用于存储每个线程是否启用字段填充的状态。
     * 初始值为 true,即默认启用字段填充。
     */
    private static final ThreadLocal<Boolean> ENABLE_FIELD_FILL = ThreadLocal.withInitial(() -> true);

    /**
     * 设置当前线程是否启用字段填充。
     *
     * @param enable 如果为 true,则启用字段填充;如果为 false,则禁用字段填充。
     */
    public static void setEnableFieldFill(boolean enable) {
        ENABLE_FIELD_FILL.set(enable);
    }

    /**
     * 获取当前线程是否启用字段填充的状态。
     *
     * @return 如果启用字段填充,则返回 true;否则返回 false。
     */
    public static boolean isEnableFieldFill() {
        return ENABLE_FIELD_FILL.get();
    }

    /**
     * 清除当前线程的 ThreadLocal 变量,防止内存泄漏。
     */
    public static void clear() {
        ENABLE_FIELD_FILL.remove();
    }
}
  1. 修改 MetaObjectHandler 使用上下文变量
    在 MetaObjectHandler 中检查上下文变量的值,决定是否进行字段填充:
public class DefaultDBFieldHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        if (!FieldFillContext.isEnableFieldFill()) {
            return;
        }
        
        /**
        * 以下没变动
        */ 
        if (Objects.nonNull(metaObject) && metaObject.getOriginalObject() instanceof BaseDO) {
            BaseDO baseDO = (BaseDO) metaObject.getOriginalObject();

            LocalDateTime current = LocalDateTime.now();
            // 创建时间为空,则以当前时间为插入时间
            if (Objects.isNull(baseDO.getCreateTime())) {
                baseDO.setCreateTime(current);
            }
            // 更新时间为空,则以当前时间为更新时间
            if (Objects.isNull(baseDO.getUpdateTime())) {
                baseDO.setUpdateTime(current);
            }
        }
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 更新时间为空,则以当前时间为更新时间
        Object modifyTime = getFieldValByName("updateTime", metaObject);
        if (Objects.isNull(modifyTime)) {
            setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
        }
    }
}

对应功能如下:

@Service
@Validated
public class GoodsStoragePlanServiceImpl implements GoodsStoragePlanService {

    @Resource
    private GoodsStoragePlanMapper goodsStoragePlanMapper;

    @Resource
    private AdminUserService userService;


    @Override
    public Long createGoodsStoragePlan(GoodsStoragePlanSaveReqVO createReqVO) {
        // 插入
        GoodsStoragePlanDO goodsStoragePlan = BeanUtils.toBean(createReqVO, GoodsStoragePlanDO.class);
        
        goodsStoragePlan.setCreateTime(LocalDateTime.now());
        goodsStoragePlan.setUpdateTime(null);
        
        // 禁用全局字段填充
        FieldFillContext.setEnableFieldFill(false);
        try {
            goodsStoragePlanMapper.insert(goodsStoragePlan);
        } finally {
            // 恢复全局字段填充
            FieldFillContext.clear();
        }

        // 返回
        return goodsStoragePlan.getId();
    }
}

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

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

相关文章

消息队列的应用场景有哪些

通常来说&#xff0c;使用消息队列主要能为我们的系统带来下面三点好处&#xff1a; 异步处理 削峰/限流 降低系统耦合性 除了这三点之外&#xff0c;消息队列还有其他的一些应用场景&#xff0c;例如实现分布式事务、顺序保证和数据流处理。 异步处理 通过异步处理提高系…

Vue3、Element Plus使用v-for循环el-form表单进行校验

在开发中遇到了这样一个需求 有一个form是通过v-for生成出来的&#xff0c;并且数量不确定&#xff0c;每个表单中的字段都需要做校验&#xff0c;就将自己的解决方法记录了下来。 完整代码如下 <template><div class"for-form"><el-button type&quo…

【python】tkinter GUI开发: 多行文本Text,单选框Radiobutton,复选框Checkbutton,画布canvas的应用实战详解

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

将MAE方法用于reflacx数据集--MMpretrain/slurm

MAE—reflacx 问题问题一 对数据集reflacx的了解问题二 MAE实现的是有监督&#xff0c;还是无监督任务问题三 实验流程问题四 实验目的 一、从github上fork我师兄的项目30min&#xff08;github账号的注册什么的&#xff0c;可以去参考b站&#xff09;1.1 点开下面这个链接…

PyTorch -- 最常见激活函数的选择

首先&#xff0c;简单复习下什么是梯度&#xff1a;梯度是偏微分的集合 举例说明&#xff1a;对于 z y 2 − x 2 : ∇ z ( ∂ z ∂ x , ∂ z ∂ y ) &#xff08; 2 x , 2 y &#xff09; z y^2-x^2: \nabla z (\frac{\partial z}{\partial x}, \frac{\partial z}{\partia…

vue3+vite+ts 使用webrtc-streamer播放海康rtsp监控视频

了解webrtc-streamer webrtc-streamer 是一个使用简单机制通过 WebRTC 流式传输视频捕获设备和 RTSP 源的项目&#xff0c;它内置了一个小型的 HTTP server 来对 WebRTC需要的相关接口提供支持。相对于ffmpegflv.js的方案&#xff0c;延迟降低到了0.4秒左右&#xff0c;画面的…

PyTorch学习9:卷积神经网络

文章目录 前言一、说明二、具体实例1.程序说明2.代码示例 总结 前言 介绍卷积神经网络的基本概念及具体实例 一、说明 1.如果一个网络由线性形式串联起来&#xff0c;那么就是一个全连接的网络。 2.全连接会丧失图像的一些空间信息&#xff0c;因为是按照一维结构保存。CNN是…

Shell环境下的脚本编程与应用

Shell是什么&#xff1f; Shell 是一个命令行解释器&#xff0c;它接收用户输入的命令&#xff08;如 ls、cd、mkdir 等&#xff09;&#xff0c;然后执行这些命令。Shell 同时还是一种功能强大的编程语言&#xff0c;允许用户编写由 shell 命令组成的脚本&#xff08;script&…

Windows搭建nacos集群

Nacos是阿里巴巴的产品&#xff0c;现在是SpringCloud中的一个组件。相比Eureka功能更加丰富&#xff0c;在国内受欢迎程度较高。 下载地址&#xff1a;Tags alibaba/nacos GitHub 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;8888 解压文件夹 目录说明&am…

基于条件谱矩的时间序列分析(以轴承故障诊断为例,MATLAB)

谱矩方法可以对数据的表面形貌做较为细致的描述&#xff0e;它以随机过程为理论基础&#xff0c;用各阶谱矩及统计不变量等具体的参数表征表面的几何形态&#xff0c;算术平均顶点曲率是一种基于四阶谱矩的统计不变量。 鉴于此&#xff0c;采用条件谱矩方法对滚动轴承进行故障诊…

[大模型]MiniCPM-2B-chat Lora Full 微调

MiniCPM-2B-chat 介绍 MiniCPM 是面壁智能与清华大学自然语言处理实验室共同开源的系列端侧大模型&#xff0c;主体语言模型 MiniCPM-2B 仅有 24亿&#xff08;2.4B&#xff09;的非词嵌入参数量。 经过 SFT 后&#xff0c;MiniCPM 在公开综合性评测集上&#xff0c;MiniCPM …

【C++题解】1469. 数的统计

问题&#xff1a;1469. 数的统计 类型&#xff1a;嵌套循环 题目描述&#xff1a; 试计算在区间 1 到 n 的所有整数中&#xff0c;数字 x ( 0≤x≤9 )共出现了多少次&#xff1f; 例如&#xff0c;在 1 到 11 中&#xff0c;即在 1,2,3,4,5,6,7,8,9,10,11 中&#xff0c;数字…

HCIA 10 网络安全之结合ACL访问控制列表登录Telnet及FTP

ACL 本质上是一种报文过滤器&#xff0c;规则是过滤器的滤芯。设备基于这些规则进行报文匹配&#xff0c;可以过滤出特定的报文&#xff0c;并根据应用 ACL 的业务模块的处理策略来允许或阻止该报文通过。 1.实验介绍及拓扑 R3 为telnet服务器&#xff0c;R1 为客户端&#…

简单的基于Transformer的滚动轴承故障诊断(Pytorch)

递归神经网络在很长一段时间内是序列转换任务的主导模型&#xff0c;其固有的序列本质阻碍了并行计算。因此&#xff0c;在2017年&#xff0c;谷歌的研究人员提出了一种新的用于序列转换任务的模型架构Transformer&#xff0c;它完全基于注意力机制建立输入与输出之间的全局依赖…

计算机图形学入门09:深度缓存

在前面知道了怎么将一个三角形显示到屏幕上&#xff0c;那么如果有很多三角形&#xff0c;各自距离相机的远近也不一样&#xff0c;并且三角形会相互遮挡。也就是三维空间中有很多物体&#xff0c;通常近处的物体会遮挡住远处的物体&#xff0c;那么在计算机渲染中该如何处理呢…

出现 Error creating bean with name xxx defined in class 的解决方法

目录 1. 问题所示2. 原理分析3. 解决方法4. Demo1. 问题所示 此类问题来自私信,本着探究问题的缘由,理性分析了下,让大家也学会分析Bug解决Bug 问题如下所示: Error creating bean with name xxx defined in class截图如下所示: 2. 原理分析 通用的原理进行分析 出现…

【C语言初阶】数组

&#x1f31f;博主主页&#xff1a;我是一只海绵派大星 &#x1f4da;专栏分类&#xff1a;C语言 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、一维数组的创建和初始化 1、数组的创建 1.1数组的创建方式 1.2数组创建的实例 2、数组的初始化 二、一维数组的使用…

vue.js+node.js+mysql在线聊天室源码

vue.jsnode.jsmysql在线聊天室源码 技术栈&#xff1a;vue.jsElement UInode.jssocket.iomysql vue.jsnode.jsmysql在线聊天室源码

word怎么单页横向设置(页码不连续版)

打开word&#xff0c;将光标放在第一页的最后位置。 然后点击布局下的分隔符&#xff0c;选择下一页。 将光标放在第二页的开头&#xff0c;点击布局下的纸张方向&#xff0c;选择横向即可。 效果展示。 PS&#xff1a;如果那一页夹在两页中间&#xff0c;那么在…

基于C#开发web网页管理系统模板流程-主界面密码维护功能完善

点击返回目录-> 基于C#开发web网页管理系统模板流程-总集篇-CSDN博客 前言 紧接上篇->基于C#开发web网页管理系统模板流程-主界面统计功能完善-CSDN博客 一个合格的管理系统&#xff0c;至少一定存在一个功能——用户能够自己修改密码&#xff0c;理论上来说密码只能有用…