【实际开发03】- dto + vo - 先处理 dto , 后处理 vo ( 通常少一注解 )

news2024/11/30 8:34:53

目录

0. 建议 : 多用组合 , 少用继承

1. @EqualsAndHashCode(callSuper = true) - 解决允许调用父类

2. 序列化 ID : private static final long serialVersionUID = 1L;

1. serialVersionUID 作用 : 序列化时为了保持版本的兼容性

3. 数据概览 ( 统计 ) : XxxxProfileVO

1. 统计数据添加默认值 0 - ( 避免返回 null )

4. dto-vo 层添加 Swagger 注释 - 方便前端查看 - ★

5. Java 反射 + 注解 : 实现 Entity 类与 Dto 类相互转换

1. BeanUtils.copyProperties(iotHouseDTO,iotHouse);

6. 警告 : VO 数据 赋值 问题

1. 通过继承得到的父类私有 ( private ) 属性数据 , 需 get / set 访问

/**
 * @author menghuan
 * @since 2020-04-20
 */
@Data
@ApiModel(value = "会议信息传输对象")
@EqualsAndHashCode(callSuper = true)
public class IotMeetingDTO extends IotMeeting implements Serializable {

    private static final long serialVersionUID = 1L;

}

DTO 修改为 VO 的操作:

1、删除 @EqualsAndHashCode(callSuper = true)

2、将传输对象 - 改为 - 展示对象

/**
 * @author menghuan
 * @since 2020-04-20
 */
@Data
@ApiModel(value = "会议信息展示对象")
public class IotMeetingVO extends IotMeeting implements Serializable {

    private static final long serialVersionUID = 1L;

}


0. 建议 : 多用组合 , 少用继承


1. @EqualsAndHashCode(callSuper = true) - 解决允许调用父类

在类是继承父类的情况下:

EqualsAndHashCode 实则就是在比较两个对象的属性;

当 @EqualsAndHashCode(callSuper = false) 时,不会比较其继承的父类的属性可能会导致错误判断;

当 @EqualsAndHashCode(callSuper = true) 时,会比较其继承的父类的属性;

1、此注解会生成equals(Object other) 和 hashCode()方法。

2、它默认使用非静态 , 非瞬态的属性

3、可通过参数 exclude 排除一些属性

4、可通过参数 of 指定仅使用哪些属性

5、它默认仅使用该类中定义的属性 , 且不调用父类的方法

6、可通过 callSuper=true 解决上一点问题。让其生成的方法中调用父类的方法。

@Data 相当于 @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode 这5个注解的合集


2. 序列化 ID : private static final long serialVersionUID = 1L;

在 java 对象序列化时 , 如果没有设置 SerialversionUID , 他会给一个默认的值 , 但是通常是建议设置默认的建议自定义一个serialVersionUID ,

因为默认的 serialVersinUID 对于 class 的细节非常敏感 , 反序列化时可能会导致 InvalidClassException 这个异常。

如果没有设置 SerialversionUID 值的话 , 在序列化后反序列化前对类进行了修改 , 类对应的 SerialversionUID 也会变化 , 而序列化和反序列化就是通过对比其SerialversionUID 来进行的 , 一旦 SerialversionUID 不匹配 , 反序列化就无法成功。

详见《Java primary concepts (概念)》


1. serialVersionUID 作用 : 序列化时为了保持版本的兼容性

serialVersionUID 作用 :

序列化时为了保持版本的兼容性 , 即在版本升级时反序列化仍保持对象的唯一性。

serialVersionUID 用作 Serializable 类中的版本控件。

如果您没有显式声明 serialVersionUID , JVM 将根据您的 Serializable 类的各个方面自动为您执行此操作 ,

如 : Java(TM)对象序列化规范中所述。


3. 数据概览 ( 统计 ) : XxxxProfileVO

/**
 * 应急事件概览展示对象
 *
 * @author makejava
 * @since 2020-10-13 09:35:04
 */
@Data
@ApiModel(value = "应急事件概览展示对象")
public class EventProfileVO {

    private static final long serialVersionUID = 1L;

    /** 应急事件总数统计 */
    private Integer sumNumber;

    /** 未处理数量统计 */
    private Integer waitDealCount;

    /** 已处理数量统计 */
    private Integer hasDealCount;

    /** 待核实数量统计 */
    // private Integer waitVerifyCount;

    /** 处理中数量统计 */
    // private Integer dealingCount;

    /** 已结束数量统计 */
    // private Integer finishCount;

}
/**
 * @Description 资源概览
 * @Author: menghuan
 * @Date: 2020/9/10 10:27
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class ResourceProfileVO {

    private static final long serialVersionUID = 1L;


    /** 资源(对应状态)统计 */
    private Map<String ,  Integer> resourceCount;

    /** 资源(对应状态)占比统计 */
    private List resourcePercent;

    /** 资源上架趋势统计分析 */
    private Map<String ,  ArrayList> resourceTrend;

    /** 资源租售势统计分析 */
    private Map<String ,  ArrayList> rentTrend;

    /** 设施设备/资源类型 柱状图 */
    private Map<String ,  ArrayList> facilitiesCount;

}


1. 统计数据添加默认值 0 - ( 避免返回 null )

思路 1 : 实体类 引用 (new XxxEntity) 时 , 便为指定属性添加自定义默认值

思路 2 : 对结果进行 if else 判null 赋值 0 处理

优化 : 使用三元表达式

    for (ResourceMapVO resourceMapVO : resourceMapVOS) {
        /*resourceMapVO.setWaitCheckCount(waitCheckCount.get(resourceMapVO.getStructureIdentity()));
                resourceMapVO.setWaitRentCount(waitRentCount.get(resourceMapVO.getStructureIdentity()));
                resourceMapVO.setHasRentCount(hasRentCount.get(resourceMapVO.getStructureIdentity()));
                resourceMapVO.setHasRemoveCount(hasRemoveCount.get(resourceMapVO.getStructureIdentity()));
                resourceMapVO.setAddressPath(addressPathInfo.get(resourceMapVO.getStructureIdentity()));*/
        resourceMapVO.setWaitCheckCount(null != waitCheckCount.get(resourceMapVO.getStructureIdentity()) ? waitCheckCount.get(resourceMapVO.getStructureIdentity()) : 0);
        resourceMapVO.setWaitRentCount(null != waitRentCount.get(resourceMapVO.getStructureIdentity()) ? waitRentCount.get(resourceMapVO.getStructureIdentity()) : 0);
        resourceMapVO.setHasRentCount(null != hasRentCount.get(resourceMapVO.getStructureIdentity()) ? hasRentCount.get(resourceMapVO.getStructureIdentity()) : 0);
        resourceMapVO.setHasRemoveCount(null != hasRemoveCount.get(resourceMapVO.getStructureIdentity()) ? hasRemoveCount.get(resourceMapVO.getStructureIdentity()) : 0);
        resourceMapVO.setAddressPath(addressPathInfo.get(resourceMapVO.getStructureIdentity()));
        if (gisInfo.get(resourceMapVO.getStructureIdentity()) != null) {
            resourceMapVO.setGisMap(gisInfo.get(resourceMapVO.getStructureIdentity()));
        }else{
            resourceMapVO.setGisMap("[]");
        }
    }

思路 3 : 执行统计 sql 直接添加 默认值 : 0


4. dto-vo 层添加 Swagger 注释 - 方便前端查看 - ★

@ApiModelProperty(value = "应急事件总数统计" , name = "sumNumber")


5. Java 反射 + 注解 : 实现 Entity 类与 Dto 类相互转换

序言

近期在工作中管理代码时发现,在项目中从 Dao 层到 Service 层数据传递中通过大量的 get() , set() 方法去一个一个的去拿值去赋值,导致代码篇幅过长,对此甚是讨厌,并且严重消耗开发时间。

起初找过些关于这块的资料,现在大部分都是 Entity 类和 Dto 类的属性名相同的前提下,利用反射实现,太局限了,如果要改成同名,按目前项目的程度去整改工作量太大,不现实。

后面看了 Spring 注解的实现,然后结合找到反射实现资料,突想奇发尝试着用自定义注解+反射方式的去实现,事实证明这方法是可行的。

整体实现三步骤:

1.自定义注解

2.工具类方法实现反射

3.使用(测试)

1、自定义注解

import java.lang.annotation.*;

@Target({ElementType.FIELD,ElementType.TYPE}) // Target 注解的使用域,FIELD表示使用在属性上面,TYPE表示使用在类上面
@Retention(RetentionPolicy.RUNTIME) // Retention 设置注解的生命周期 ,这里定义为RetentionPolicy.RUNTIME 非常关键
@Documented
public @interface RelMapper {
    //自定义属性
    String value() default "";
    String type() default "";  // value : status(标记属性值为Y/N的属性) / date(标记属性类型为时间)
}

自定义属性,大家可以根据自己项目中的需求增加不同的属性

2、工具类方法实现

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Date;


/**
 * Java反射+注解实现Entity类与Dto类相互转换
 *      情景:在项目中从Dao层到Service层数据传递中通过大量的get(),set()方法去一个一个的去拿值去赋值,导致代码篇幅过长,并且严重消耗开发时间;
 *      尝试:现在大部分都是Entity类和Dto类的属性名相同的前提下,利用反射实现,太局限了,如果要改成同名,按目前项目的程度去整改工作量太大,不现实;
 *      解决:看了Spring注解的实现,然后结合找到反射实现资料,突想奇发尝试着用自定义注解+反射方式的去实现,事实证明这方法是可行的。
 * @Author: menghuan
 * @Date: 2021/6/28 14:41
 */
public class RelationMapperUtils {

    public static Object entryAndDtoMapper(Object entity, Object dto) throws Exception{
        return EnAndDtoMapper(entity, dto,true);
    }

    public static Object entryAndDtoMapper(Object entity, Object dto,boolean enToDto) throws Exception{
        return EnAndDtoMapper(entity, dto,false);
    }
    /**
     * Entity and Dto Mapper
     * @param entry
     * @param dto
     * @param enToDto
     *             ture  : Entity To Dto (defult)
     *             false : Dto To Entry
     *     Rule:
     *         实现相互转换前提: Dto field name(dto和entry的field name相同并且 类上有@RelMapper) 或 field的@RelMapper(value="Entity field name") 满足其一即可转换
     * @return
     * @throws Exception
     */
    // last version
    public static Object EnAndDtoMapper(Object entry, Object dto,boolean enToDto) throws Exception{
        if(enToDto == true ? entry == null : dto == null){ return null;}
        Class<? extends Object> entryclazz = entry.getClass();    //获取entity类
        Class<? extends Object> dtoclazz = dto.getClass();    //获取dto类
        boolean dtoExistAnno = dtoclazz.isAnnotationPresent(RelMapper.class);    //判断类上面是否有自定义注解
        Field[] dtofds = dtoclazz.getDeclaredFields();    //dto fields
        Field [] entryfds = entryclazz.getDeclaredFields();    //entity fields
        Method entrys[] = entryclazz.getDeclaredMethods();    //entity methods
        Method dtos[] = dtoclazz.getDeclaredMethods();    //dto methods
        String mName,fieldName,dtoFieldType=null,entFieldType=null,dtoMapName = null,dtoFieldName =null;Object value = null;
        for(Method m : (enToDto ? dtos : entrys)) {    //当 enToDto=true 此时是Entity转为Dto,遍历dto的属性
            if((mName=m.getName()).startsWith("set")) {    //只进set方法
                fieldName = mName.toLowerCase().charAt(3) + mName.substring(4,mName.length());  //通过set方法获得dto的属性名
                tohere:
                for(Field fd: dtofds) {
                    fd.setAccessible(true);    //setAccessible是启用和禁用访问安全检查的开关
                    if(fd.isAnnotationPresent(RelMapper.class)||dtoExistAnno){    //判断field上注解或类上面注解是否存在
                        //获取与Entity属性相匹配的映射值(两种情况:1.该field上注解的value值(Entity的field name 和Dto 的field name 不同)  2.该field本身(本身则是Entity的field name 和Dto 的field name 相同))
                        dtoMapName = fd.isAnnotationPresent(RelMapper.class) ? (fd.getAnnotation(RelMapper.class).value().toString().equals("")?fd.getName().toString():fd.getAnnotation(RelMapper.class).value().toString()):fd.getName().toString();
                        if(((enToDto ? fd.getName() : dtoMapName)).toString().equals(fieldName)) {
                            dtoFieldType = fd.getGenericType().toString().substring(fd.getGenericType().toString().lastIndexOf(".") + 1); // 获取dto属性的类型(如 private String field 结果 = String)
                            for(Field fe : entryfds) {
                                fe.setAccessible(true);
                                if(fe.getName().toString().equals(enToDto ? dtoMapName : fieldName) ) {//遍历Entity类的属性与dto属性注解中的value值匹配
                                    entFieldType = fe.getGenericType().toString().substring(fe.getGenericType().toString().lastIndexOf(".") + 1); //获取Entity类属性类型
                                    dtoFieldName = enToDto ? dtoMapName : fd.getName().toString();
                                    break tohere;
                                }
                            }
                        }
                    }
                }
                if(dtoFieldName!= null && !dtoFieldName.equals("null")) {
                    for(Method md : (enToDto ? entrys : dtos)) {
                        if(md.getName().toUpperCase().equals("GET"+dtoFieldName.toUpperCase())){
                            dtoFieldName = null;
                            if(md.invoke(enToDto ? entry : dto) == null) { break;} //去空操作
                            //Entity类field 与Dto类field类型不一致通过TypeProcessor处理转换
                            value = (entFieldType.equals(dtoFieldType))? md.invoke(enToDto ? entry : dto) :TypeProcessor(entFieldType, dtoFieldType,md.invoke(enToDto ? entry : dto),enToDto ? true : false);
                            m.invoke(enToDto ? dto : entry, value); //得到field的值 通过invoke()赋值给要转换类的对应属性
                            value = null;
                            break;
                        }
                    }
                }
            }
        }
        return enToDto ? dto : entry;
    }

    // 类型转换处理
    public static Object TypeProcessor(String entFieldType,String dtoFieldType, Object obj,boolean enToDto) {
        if(entFieldType.equals(dtoFieldType)) return obj;

        if(!entFieldType.equals(dtoFieldType)) {
            switch(entFieldType) {
                case "Date":
                    return (enToDto)?TypeConverter.dateToString((Date) obj):TypeConverter.stringToDate(obj.toString());
                case "Timestamp":
                    return TypeConverter.timestampToTimestampString((Timestamp)obj);
                case "Integer":
                    return (enToDto) ? obj.toString() : Integer.parseInt((String)obj) ;
            }
        }
        return obj;
    }

}

上面 EnAndDtoMapper() 方法的实现是 Entity 和 Dto 之间互相转换结合在一起,enToDto = true 表示的是 Entity 转 Dto 实现,false 则相反。

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * TypeConverter 转换工具类
 * @Author: menghuan
 * @Date: 2021/6/30 11:13
 */
public class TypeConverter {

    private static Pattern linePattern = Pattern.compile("_([a-z])");

    private static Pattern humpPattern = Pattern.compile("\\B(\\p{Upper})(\\p{Lower}*)");

    /**
     * 将Date转换为String类型
     * 提示:Object类中为我们提供了toString方法,然而该方法对Date类进行转换时,往往达不到我们想要的效果
     * @param var 入参
     * @return
     */
    public static String dateToString(Date var){
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        return sf.format(var);
    }

    /**
     * 将String转换为Date类型
     * @param var 时间字符串
     * @return
     */
    public static Date stringToDate(String var){
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            //使用SimpleDateFormat的parse()方法生成Date
            Date date = sf.parse(var);
            return date;
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将Timestamp转换为指定格式的String
     * @param var 时间戳
     * @return
     */
    public static String timestampToTimestampString(Timestamp var){
        SimpleDateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");//定义日期显示格式
        return df.format(var);
    }

    /**
     * 将String转换为指定格式的Timestamp
     * @param var 字符串,格式必须为:"yyyy-MM-dd HH:mm:ss"
     * @return
     */
    public static Timestamp timestampStringToTimestamp(String var){
        Timestamp t_time = Timestamp.valueOf(var);
        // String-->Timestamp:2010-08-08 06:06:06.0
        // System.out.println("String-->Timestamp:"+t_time);
        return t_time;
    }

    /**
     * 实体对象转成Map
     *
     * @param obj 实体对象
     * @return
     */
    public static Map<String, Object> object2Map(Object obj) {
        Map<String, Object> map = new HashMap<>();
        if (obj == null) {
            return map;
        }
        @SuppressWarnings("rawtypes")
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                map.put(field.getName(), field.get(obj));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * Map转成实体对象
     *
     * @param map   map实体对象包含属性
     * @param clazz 实体对象类型
     * @return
     */
    public static Object map2Object(Map<String, Object> map, Class<?> clazz) {
        if (map == null) {
            return null;
        }
        Object obj = null;
        try {
            obj = clazz.newInstance();

            Field[] fields = obj.getClass().getDeclaredFields();
            for (Field field : fields) {
                int mod = field.getModifiers();
                if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
                    continue;
                }
                field.setAccessible(true);
                field.set(obj, map.get(field.getName()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }


    /**
     * 下划线转驼峰
     *
     * @param str
     * @return
     */
    public static String lineToHump(String str) {
        Matcher matcher = linePattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }


    /**
     * 驼峰转下划线(Map)
     *
     * @param str
     * @return
     */
    public static String humpToLine(String str) {
        Map<String, Object> map = JSONObject.parseObject(str);
        Map<String, Object> newMap = Maps.newHashMap();
        Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            StringBuffer sb = new StringBuffer();
            Map.Entry<String, Object> entry = it.next();
            String key = entry.getKey();
            Matcher matcher = humpPattern.matcher(key);
            while (matcher.find()) {
                matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
            }
            matcher.appendTail(sb);
            newMap.put(sb.toString(), entry.getValue());
        }
        return JSON.toJSONString(newMap);

    }

    /**
     * 驼峰转下划线(List)
     *
     * @param str
     * @return
     */
    @SuppressWarnings("all")
    public static String humpToLineList(String str) {
        List<Map> list = JSONObject.parseArray(str, Map.class);
        List<Map<String, Object>> res = new ArrayList<>();
        list.stream().forEach(p -> {
            Map<String, Object> newMap = Maps.newHashMap();
            Iterator<Map.Entry<String, Object>> it = p.entrySet().iterator();
            while (it.hasNext()) {
                StringBuffer sb = new StringBuffer();
                Map.Entry<String, Object> entry = it.next();
                String key = entry.getKey();
                Matcher matcher = humpPattern.matcher(key);
                while (matcher.find()) {
                    matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
                }
                matcher.appendTail(sb);
                newMap.put(sb.toString(), entry.getValue());
            }
            res.add(newMap);
        });
        return JSON.toJSONString(res);
    }

}

3、如何使用

Entity 类 与 Dto 类对应


1. BeanUtils.copyProperties(iotHouseDTO,iotHouse);


6. 警告 : VO 数据 赋值 问题


1. 通过继承得到的父类私有 ( private ) 属性数据 , 需 get / set 访问

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

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

相关文章

CAD常用命令:对象选择过滤器(FILTER)

CAD软件中为了方便绘图&#xff0c;有效地提升绘图效率&#xff0c;提供了很多CAD命令快捷键&#xff0c;而CAD对象选择过滤器作为CAD常见命令之一&#xff0c;在日常的CAD绘图过程中经常能用到&#xff0c;你知道CAD对象选择过滤器怎么用吗&#xff1f;本文小编就来给大家分享…

Qt解析Json数据

目录前言1.下载 jsoncpp 源码2.编译3.JSON数据读写示例4.jsoncpp核心类详解前言 本文主要介绍了使用Qt框架编程时如何解析JSON数据的一种方法。JSON是英文JavaScript Object Notation 的缩写&#xff0c;它是一种轻量级的数据交换格式&#xff0c;具有方便阅读和编写的优点&am…

Jenkins 项目的 gpg: signing failed: Bad passphrase 错误

因为我们项目需要使用 Jenkins 对文件进行签名。但是我们遇到了gpg: signing failed: Bad passphrase错误。原因和解决通常这个问题的原因是 Key 已经配置成功并且已经被命令行找到了。主要原因是你的秘钥密码配置的问题。这个配置有 2 个地方&#xff0c;第一个地方是项目的 P…

2022年度牛奶乳品行业数据:十大热门品牌销量排行榜

当前&#xff0c;随着经济的发展及人民生活水平的提高&#xff0c;牛奶乳品已经日趋成为人们在日常饮食中不可缺少的食物之一&#xff0c;市面上的产品种类也越来越多。并且&#xff0c;随着人们消费习惯的转变&#xff0c;牛奶乳品的消费场景也日益多元化。未来&#xff0c;预…

jdk1.8之函数式接口

l[TOC] 函数式接口概述 jdk1.8 引入了一个核心概念&#xff1a;函数式接口&#xff08;Functional Interface&#xff09;。如果一个接口有且只有一个未实现的方法&#xff0c;那这个接口就称为函数式接口。并且引入了一个新的注解&#xff1a;FunctionalInterface &#xff0…

一、Gradle入门

文章目录一、Gradle入门1.1 Gradle 简介1.2 常见的项目构建工具1.3 Gradle 安装1.3.1 Gradle 安装说明1.3.2 安装 JDK1.3.3 下载并解压到指定目录1.3.4 配置环境变量1.3.5 检测是否安装成功1.4 Gradle 项目目录结构1.5 Gradle 创建第一个项目1.5.1 Gradle 中的常用命令1.5.2 修…

【MySQL进阶教程】视图/存储过程/触发器

前言 本文为 【MySQL进阶教程】视图/存储过程/触发器 相关知识&#xff0c;下边将对视图&#xff0c;存储过程&#xff0c;存储函数&#xff0c;触发器等进行详尽介绍~ &#x1f4cc;博主主页&#xff1a;小新要变强 的主页 &#x1f449;Java全栈学习路线可参考&#xff1a;【…

MySQL高级【存储函数触发器】

1&#xff1a;存储函数1.1&#xff1a;介绍存储函数是有返回值的存储过程&#xff0c;存储函数的参数只能是IN类型的。具体语法如下&#xff1a; CREATE FUNCTION 存储函数名称 ([ 参数列表 ]) RETURNS type [characteristic ...] BEGIN -- SQL语句 RETURN ...; END ;character…

如何管理存量用户?

存量市场的老客户对于企业来说如同一座金矿&#xff0c;好好运营老客户&#xff0c;可以给企业带来源源不断的新客户&#xff0c;企业所获得的收益远比拉新所获收益要高的多。 前言 存量客户是指某个时间段里原先已有的客户&#xff0c;与新增客户相对应&#xff0c;通俗点说&…

Python开发Web扫描器实战

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是Python开发Web扫描器实战。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未…

机器学习--模型评估、过拟合和欠拟合、模型验证

目录 一、模型评估 模型指标 常见关于分类的指标 准确率 精确率(精确度) 召回率 F1 score PR曲线&#xff1a; ROC AUC 二、过拟合和欠拟合 训练与泛化误差的区别 什么样的情况会导致欠拟合与过拟合&#xff1f; 模型的复杂度&#xff08;能够拟合各种各样函…

分组加密模式 ECB CBC OFB CFB

多个分组加密互相之间如何关联 ECB模式 每个分组之间单独加密&#xff0c;互不关联 2个分组明文一样&#xff0c;结果也一样&#xff0c;那么只需爆破其中1个就可以了 每个分组互不关联&#xff0c;可以分段同时来爆破&#xff0c;不安全 可以通过替换某段密文来达到替换明…

11.Isaac教程--在docker中模拟训练姿势估计模型

在docker中模拟训练姿势估计模型 文章目录在docker中模拟训练姿势估计模型怎么运行的主机设置硬件要求软件要求NGC Docker 注册表设置第一次运行数据集生成配置您的工作区Jupyter 变量设置开始训练添加您自己的 3D 模型故障排除接下来物体检测和 3D 姿态估计在机器人技术中起着…

『精』EditorConfig 小老鼠 跨编辑器 | IDE 保持一致的编码风格

『精』EditorConfig 小老鼠 跨编辑器 | IDE 保持一致的编码风格 文章目录『精』EditorConfig 小老鼠 跨编辑器 | IDE 保持一致的编码风格一、什么是EditorConfig二、文件识别符三、风格属性控制四、不同规则参考1)、简洁通用2)、前端Vue项目3)、前端React项目4)、前端Angular项…

Linux常用命令——nm命令

在线Linux命令查询工具(http://www.lzltool.com/LinuxCommand) nm 显示二进制目标文件的符号表 补充说明 nm命令被用于显示二进制目标文件的符号表。 语法 nm(选项)(参数)选项 -A&#xff1a;每个符号前显示文件名&#xff1b; -D&#xff1a;显示动态符号&#xff1b; …

成员变量-java循环机构

1.概念所谓的成员变量&#xff0c;是指在类中(不是方法或其他代码块)直接定义的变量。根据是否带有static关键字&#xff0c;成员变量又分为静态变量(类变量)、实例变量(对象变量)。成员变量在整个类的内部都有效&#xff0c;可以在当前类的任何方法中使用。另外如果成员变量不…

NFS介绍及服务器搭建

一、NFS 简介 NFS&#xff0c;英文全称 Network File System&#xff0c;主要功能&#xff1a;通过网络&#xff0c;让不同的机器、不同的操作系统可以共享文件。类似windows的共享文件夹 ​ NFS服务器共享本机目录&#xff0c;客户端机器挂载该目录后&#xff0c;就可以像自…

AI+OCR赋能古彝文数字化—让经典重新跳动

1️⃣ 彝文与古彝文概况文化是一个民族社会历史发展到一定程度的产物&#xff0c;代表着文明发展的程度&#xff0c;而文字是文化的一种载体&#xff0c;文字的出现是社会进入文明阶段的重要标志之一&#xff0c;其生动记录着一个民族的智慧成果&#xff0c;深刻反映着一个民族…

Unity 3D 环境特效||Unity 3D 游戏场景设计实例

Unity 3D 环境特效 一般情况下&#xff0c;要在游戏场景中添加雾特效和水特效较为困难&#xff0c;因为需要开发人员懂得着色器语言且能够熟练地使用它进行编程。 Unity 3D 游戏开发引擎为了能够简单地还原真实世界中的场景&#xff0c;其中内置了雾特效并在标准资源包中添加…

mmLab系列使用方法

mmLab系列使用方法环境搭建mmdetection检查数据集运行部署mmdeploy环境搭建使用mmOCRmmsegmentation环境搭建 Windows最推荐安装方法&#xff1a; 首先需要查好自己gpu的CUDA版本&#xff0c;根据版本到pytorch官方网站查找对应的pytorch版本(!!!只查找不下载&#xff01;)ht…