springboot基础及上传组件封装

简介

本文主要以文件上传为demo,介绍了一些 springboot web 开发的入门的技术栈。

对应刚接触 springboot 的可以参考下。

主要包括文件md5比对、生成图片缩略图、数据库迁移、文件记录持久化、请求全局异常处理等功能。

准备工作

  • idea 中创建项目,java8 , springboot 2

  • maven 所需依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.bimcc</groupId>
    <artifactId>iot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>iot</name>
    <description>iot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.6.13</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--数据库迁移 -->
        <dependency>
            <groupId>org.flywaydb</groupId>
            <artifactId>flyway-core</artifactId>
            <version>5.2.4</version>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!--请求验证-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
            <version>2.7.8</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>20.0</version>
        </dependency>

        <!--工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.4.0</version>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.bimcc.iot.IotApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

  • 创建项目目录

在这里插入图片描述

目录意义如下:

请添加图片描述

  • 修改 application.yml 配置:

---
# 开发环境的配置
server:
  port: 9090
spring:
  controller:
    api-prefix: /api
  flyway:
    enabled: true #开启数据迁移
    table: flyway_schema_history #用于存储迁移历史记录的表名,默认为flyway_schema_history
    baseline-on-migrate: true #当迁移数据库存在但没有元数据的表时,自动执行基准迁移,新建flyway_schema_history表
    locations: classpath:db/migration #数据库迁移脚本的位置,默认为classpath:db/migration,classpath 羡慕resources目录
    clean-disabled: true #用于控制是否禁用 Flyway 的 clean 操作。
  datasource:
    username: root
    password: root
    url: jdbc:mysql://127.0.0.1:3306/java_iot?serverTimezone=GMT%2b8
  config:
    activate:
      on-profile: dev #开发环境
  servlet:
    multipart:
      enabled: true # 允许文件上传
      max-file-size: 20971520 # 单文件最大限制 20M
      max-request-size: 52428800 # 单次请求最大限制 50M
file:
  upload:
    path: E:\project-java\java-upload  # 文件上传保存服务器绝对路径
    suffix: jpg,jpeg,png,bmp,xls,xlsx,pdf  # 文件上传保存路径
    is-thumb: true  # 是否开启缩略图 true false
    proportion: 5  # 缩略图缩放比例
    path-pattern: uploads  # 访问虚拟目录
log:
  level: INFO # INFO DEBUG ERROR
---

# 当前启用的配置
spring:
  application:
    name: iot # 应用平台
  profiles:
    active: dev   # 当前环境
  • 创建数据表迁移文件

在这里插入图片描述

写入以下内容:

CREATE TABLE sys_file
(
    id         INT AUTO_INCREMENT COMMENT 'id',
    file_name  VARCHAR(255) NOT NULL COMMENT '文件名称',
    ip         VARCHAR(255) COMMENT '上传ip',
    file_path  VARCHAR(255) NOT NULL COMMENT '文件路径',
    thumb_path  VARCHAR(255) COMMENT '缩略图文件路径',
    file_size  INT COMMENT '字节大小',
    file_type  VARCHAR(255) COMMENT '文件类型',
    file_ext   CHAR(36) COMMENT '文件后缀',
    file_md5   VARCHAR(255) COMMENT '文件md5',
    created_at DATETIME COMMENT '创建时间',
    updated_at DATETIME COMMENT '修改时间',
    deleted_at DATETIME COMMENT '删除时间',
    PRIMARY KEY (id)
) ENGINE = InnoDB DEFAULT CHARSET = UTF8MB4;

创建上传实体类

  • dto目录 创建 BaseEntity FileEntity 实体类

BaseEntity 写入以下内容:


// 省略 package import 

@Data
public class BaseEntity implements Serializable {

    @TableId(value = "id",type = IdType.AUTO)
    private Integer id;


    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") //格式化时间,空值不会格式化
    @TableField(value = "created_at",fill = FieldFill.INSERT)
    @JsonProperty("created_at") //json格式化显示字段
    private Date createdAt;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @TableField(value = "updated_at",fill = FieldFill.INSERT_UPDATE)
    @JsonProperty("updated_at")
    private Date updatedAt;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @JsonProperty("deleted_at")
    @TableField(value = "deleted_at")
    @TableLogic(value = "null",delval = "now()")
    private Date deletedAt;

}

FileEntity 写入以下内容:

// 省略 package import 
@Data
@TableName("sys_file")
public class FileEntity extends BaseEntity {
    @TableField(value = "file_name")
    private String fileName;
    @TableField(value = "ip")
    private String ip;
    @TableField(value = "file_path")
    private String filePath;
    @TableField(value = "thumb_path")
    private String thumbPath;
    @TableField(value = "file_size")
    private Long fileSize;
    @TableField(value = "file_type")
    private String fileType;
    @TableField(value = "file_ext")
    private String fileExt;
    @TableField(value = "file_md5")
    private String fileMd5;
}


  • 创建 mapper , 在 mapper 目录创建 FileMapper 接口类
// 省略 package import 

@Mapper
public interface FileMapper extends BaseMapper<FileEntity> {

    FileEntity queryByMd5(String md5);
}

  • 创建 mapper xml 文件。在 resources 目录下面创建 mapper 目录,然后再创建 FileMapper.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.bimcc.iot.mapper.FileMapper">

    <!-- 询的结果集字段和实体类的user属性名不一致,自定义查询结果集的映射规则   -->
    <resultMap id="queryFile" type="com.bimcc.iot.dto.FileEntity">
        <id property="id" column="id"/>
        <result property="fileName" column="file_name"/>
        <result property="ip" column="ip"/>
        <result property="filePath" column="file_path"/>
        <result property="fileSize" column="file_size"/>
        <result property="fileType" column="file_type"/>
        <result property="fileExt" column="file_ext"/>
        <result property="fileMd5" column="file_md5"/>
        <result property="createdAt" column="created_at"/>
        <result property="updatedAt" column="updated_at"/>
        <result property="deletedAt" column="deleted_at"/>
    </resultMap>

    <select id="queryByMd5" resultMap="queryFile">
        select * from sys_file where file_md5 = #{md5} and deleted_at is null
    </select>


</mapper>

全局异常处理

  • exceptin 目录里面创建 ServiceException 类,编写如下代码:
// 省略 package import 

//专用于处理业务层的异常基类
public class ServiceException extends RuntimeException{
    public ServiceException() {
        super();
    }

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public ServiceException(Throwable cause) {
        super(cause);
    }

    protected ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

  • controller 目录里面创建 BaseController 基类,后续 controller 继承他
// 省略 package import 

@ControllerAdvice
public class BaseController {
    public static final int OK = 200;

    /**
     * 全局手动抛出异常处理
     * 1.当出现了value内的异常之一,就会将下方的方法作为新的控制器方法进行执行
     *   因此该方法的返回值也同时是返回给前端的页面
     * 2.此外还自动将异常对象传递到此方法的参数列表中,这里使用Throwable e来接收
     **/
    @ExceptionHandler(ServiceException.class) //统一处理抛出的异常
    public ResJson<Void> handleException(Throwable e){
        ResJson<Void> result = new ResJson<>(e);
        result.setCode(5000); //数据库或服务器有问题
        return result;
    }


}

注册配置

config 目录创建 GlobalControllerPathPrefixConfig 类,写入以下内容:

// 省略 package import 

//群集统一配置接口前缀
@Configuration
public class GlobalControllerPathPrefixConfig implements WebMvcConfigurer {


    @Value("${spring.controller.api-prefix}")
    private String pathPrefix;

    @Value("${file.upload.path-pattern}")
    private String pathPattern;

    @Value("${file.upload.path}")
    private String fileUploadPath;

    //全局接口注册 api前缀
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer.addPathPrefix(pathPrefix, c -> c.isAnnotationPresent(RestController.class));
    }

    //静态资源图片上传,虚拟路径返回
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //将匹配上/files/**虚拟路径的url映射到文件上传到服务器的目录,获取静态资源
        registry.addResourceHandler("/" +pathPattern + "/**").addResourceLocations("file:" + fileUploadPath+File.separator);
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }


}

创建工具类

  • 创建一个全局返回类。在 utils 里面创建一个 ResJson 类型
// 省略 import

@Data
public class ResJson<E> implements Serializable {
    /**
     * 状态码
     */
    private Integer code;
    /**
     * 提示信息
     */
    private String message;
    /**
     * 返回数据
     */
    private E data;

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

    public ResJson(Throwable e) {
        this.message = e.getMessage();
    }

    public ResJson(Integer code,String message,E data) {
        this.code = code;
        this.data = data;
        this.message = message;
    }

}

  • 创建一个 md5 加密类。在 utils 里面创建一个 PasswordEncryptedUtils 类型
// 省略 package import 
public class PasswordEncryptedUtils {

    public static String getPasswordByMD5(String pwd,String salt){
        for (int i = 0; i < 3 ; i++) {
            //md5加密算法的调用
            pwd =  DigestUtils.md5DigestAsHex((salt + pwd + salt).getBytes()).toUpperCase();
        }
        //返回经过加密的结果
        return pwd;
    }
}

创建上传服务

  • server目录里面创建FileServer 接口类
// 省略 package import 

public interface FileServer {

    FileEntity upload(MultipartFile file);

    String createThumb(String fileDir,String filePath,String fileName,String suffix);

}

  • server目录里面创建impl目录并在里面创建FileServerImpl类实现上面的接口功能

// 省略 package import 

@Service
public class FileServerImpl implements FileServer {

    public static final int maxWidth = 100;

    //拦截的url,虚拟路径
    public String pathPattern = "uploads";

    //文件磁盘路径
    @Value("${file.upload.path}")
    private String fileUploadPath;

    @Value(value = "${file.upload.suffix:jpg,jpeg,png,bmp,xls,xlsx,pdf}")
    private String fileUploadSuffix;

    @Value(value = "${file.upload.is-thumb}")
    private Boolean isThumb;

    @Value(value = "${file.upload.proportion}")
    private Integer proportion;

    @Autowired
    HttpServletRequest request;

    @Autowired
    FileMapper fileMapper;

    //文件上传
    @Override
    public FileEntity upload(MultipartFile file) {
        FileEntity fileRes = new FileEntity();

        if (file.isEmpty()) {
            // log.error("the file to be uploaded is empty");
            return fileRes;
        }
        List<String> suffixList = Lists.newArrayList(fileUploadSuffix.split(","));

        try {
            //校验文件后缀
            String originalFilename = file.getOriginalFilename();
            //获取文件类型
            String type = FileUtil.extName(originalFilename);
            //文件后缀
            String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
            if (!suffixList.contains(suffix)) {
                //log.error("unsupported file format");
                return fileRes;
            }

            //获取文件md5
            String md5 = SecureUtil.md5(file.getInputStream());

            // 从数据库查询是否存在相同的记录
            FileEntity dbFiles = fileMapper.queryByMd5(md5);
            if (dbFiles != null) { // 文件已存在
                return dbFiles;
            }


            String year = new SimpleDateFormat("yyyy").format(new Date());
            String month = new SimpleDateFormat("MM").format(new Date());
            String day = new SimpleDateFormat("dd").format(new Date());

            String fileDir = fileUploadPath;
            String filePath = File.separator + year + File.separator + month + File.separator + day + File.separator;

            //首次需生成目录
            File folder = new File(fileDir + filePath);
            if (!folder.exists()) {
                folder.mkdirs();
            }

            AtomicInteger counter = new AtomicInteger(0);
            String uniqueString = String.valueOf(Instant.now().toEpochMilli());

            String fileName = uniqueString + "." + suffix;
            String absolutePath = fileDir + filePath + fileName;
            file.transferTo(new File(absolutePath));
            //网页路径
            String dataFilePath = pathPattern + "/" + year + "/" + "/" + month + "/" + day + "/" + fileName;

            fileRes.setFilePath(dataFilePath);
            fileRes.setFileName(fileName);
            fileRes.setIp(request.getRemoteAddr());
            fileRes.setFileSize(file.getSize() / 1024);
            fileRes.setFileType(type);
            fileRes.setFileExt(suffix);
            fileRes.setFileMd5(md5);

            //判断是否生成缩率图
            if (isThumb) {
                createThumb(fileDir, filePath, uniqueString, suffix);
                String dataFileThumbPath = pathPattern + "/" + year + "/" + "/" + month + "/" + day + "/" + uniqueString + "_thumb." + suffix;
                fileRes.setThumbPath(dataFileThumbPath);
            }
            fileMapper.insert(fileRes);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
        return fileRes;
    }

    //生成缩率图
    @Override
    public String createThumb(String fileDir, String filePath, String fileName, String suffix) {
        String localPath = fileDir + filePath + fileName + "." + suffix;
        String thumbPath = fileDir + filePath + fileName + "_thumb." + suffix;

        //判断缩略图是否存在
        Path path = Paths.get(thumbPath);
        if (Files.exists(path)) {
            return filePath + fileName + "_thumb." + suffix;
        }

        File originalFile = new File(localPath);
        try {
            BufferedImage originalImage = ImageIO.read(originalFile);
            int imageWidth = originalImage.getWidth();
            int imageHeight = originalImage.getHeight();

            double thumbWidth = 0;
            double thumbHeight = 0;
            if (imageWidth > maxWidth || imageHeight > maxWidth) {
                thumbWidth = (double) imageWidth / (double) proportion;
                thumbHeight = (double) imageHeight / (double) proportion;
            }
            if (thumbHeight > 0) {
                // 创建缩略图
                BufferedImage thumbnail = new BufferedImage((int) thumbWidth, (int) thumbHeight, BufferedImage.TYPE_INT_RGB);
                Graphics graphics = thumbnail.createGraphics();
                graphics.drawImage(originalImage.getScaledInstance((int) thumbWidth, (int) thumbHeight, Image.SCALE_SMOOTH), 0, 0, null);
                graphics.dispose();

                // 输出到文件
                ImageIO.write(thumbnail, suffix, new File(thumbPath));
                return filePath + fileName + "_thumb." + suffix;
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
        return "";
    }


}

上传

  • 创建一个上传控制器UploadController,写入以下内容:
// 省略 package import 

@RestController
public class UploadController extends BaseController {

    @Autowired
    FileServer fileServer;


    @PostMapping("/upload")
    public ResJson<FileEntity> upload(@RequestParam MultipartFile file){
       FileEntity fileRes= fileServer.upload(file);
       return new ResJson<>(OK,"上传成功!",fileRes);
    }

}

  • 测试

通过 postman 接口测试,调用上面的上传接口

查看application.yml里面配置的上传目录,是否有文件

通过网络路径访问图片

总结

本文适合 springboot 入门的初学者。

以文件上传为demo,衍生出了一些常用功能,包含:文件上传,入库,请求。异常处理,api前缀,数据迁移,生成缩略图,等功能。

希望能对初学者有一个参考的作用。

– 欢迎点赞、关注、转发、收藏【我码玄黄】,gonghao同名

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

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

相关文章

十大排序 —— 快速排序

十大排序 —— 快速排序 快速排序一些坑快速排序的性能优点&#xff1a;缺点&#xff1a;性能优化&#xff1a; 我们今天来看看十大排序中很出名的一个算法——快速排序&#xff1a; 快速排序 快速排序&#xff08;Quick Sort&#xff09;是一种经典的、高效的排序算法&#…

centos8stream 编译安装 php-rabbit-mq模块

官方GitHub&#xff1a;https://github.com/php-amqp/php-amqp 环境依赖安装 dnf install cmake make -y 1.安装rabbitmq-c cd /usr/local/src/ wget https://github.com/alanxz/rabbitmq-c/archive/refs/tags/v0.14.0.tar.gz tar xvf v0.14.0.tar.gz cd rabbitmq-c-0.14.0/…

Linux下多线程的相关概念

&#x1f916;个人主页&#xff1a;晚风相伴-CSDN博客 &#x1f496;如果觉得内容对你有帮助的话&#xff0c;还请给博主一键三连&#xff08;点赞&#x1f49c;、收藏&#x1f9e1;、关注&#x1f49a;&#xff09;吧 &#x1f64f;如果内容有误或者有写的不好的地方的话&…

php反序列化入门

一&#xff0c;php面向对象。 1.面向对象&#xff1a; 以“对象”伪中心的编程思想&#xff0c;把要解决的问题分解成对象&#xff0c;简单理解为套用模版&#xff0c;注重结果。 2.面向过程&#xff1a; 以“整体事件”为中心的编程思想&#xff0c;把解决问题的步骤分析出…

实时监控电脑屏幕的软件是什么?三款超受欢迎的电脑监控软件

实时监控电脑屏幕的软件在现代企业管理中扮演着至关重要的角色&#xff0c;它们不仅帮助管理者实时监控员工的工作状态&#xff0c;提高工作效率&#xff0c;还通过数据分析和报告功能&#xff0c;为企业提供了优化管理流程和决策支持的依据。以下将介绍几款市面上广泛使用的实…

Redis过期策略数据淘汰策略

过期策略 一、设置过期时间 redis有四种命令可以用于设置键的生存时间和过期时间&#xff1a; EXPIRE : 将键的生存时间设为 ttl 秒 PEXPIRE :将键的生存时间设为 ttl 毫秒 EXPIREAT :将键的过期时间设为 timestamp 所指定的秒数时间戳 PEXPIREAT : 将键的过期时间设为 times…

GNU Radio创建qt time plot python OOT块

文章目录 前言一、创建自定义的 OOT 块1、安装相应依赖2、创建 OOT 块3、修改相关4、编译及安装 OOT 块 二、测试1、grc 图2、运行结果 三、资源自取 前言 官方提供的绘制时域波形的 block 名字叫做 QT GUI Time Sink&#xff0c;其底层实现是用 C 写的&#xff0c;但是我发现…

virtualbox中ubuntu22.04网络配置

第一&#xff1a;添加两个网卡&#xff0c;网卡1是NAT方式&#xff0c;网卡2是仅主机模式&#xff08;两个顺序不能颠倒&#xff09; 第二步&#xff1a;启动ifconfig查看网络

『 Linux 』文件系统

文章目录 磁盘构造磁盘抽象化 磁盘的寻址方式磁盘控制器磁盘数据传输文件系统Inode数据块(Data Blocks)超级块(SuperBlock)块组描述符(Group Descriptor) 磁盘构造 磁盘内部构造由磁头臂,磁头,主轴,盘片,盘面,磁道,柱面,扇区构成; 磁头臂&#xff1a;控制磁头的移动,可以精确地…

Exce 两列一组对齐呈现,缺失补 0

Excel 里有 多 组数据&#xff0c;每组 2 列&#xff0c;每组长度不同。第 1 列是编号&#xff0c;列之间的编号有重复。 ABCDEFGH1Mass10Mass11Mass12Mass132802200581309088146532802225938133306824779282975598142002482273148413154988335698822331305832720485110460842…

go解析yaml

go解析yaml文件关键就是结构体的创建 初学go tag字段要和yaml文件中的key对应起来&#xff0c;每个层级都要创建对应的结构体&#xff0c;有点烦 package configimport ("gopkg.in/yaml.v3""os" )type Config struct {MysqlConfig MysqlConfig yaml:&q…

Spring Boot 开发 -- 过滤器与拦截器详解

引言 在Web开发中&#xff0c;经常需要对请求进行预处理或在响应后进行后处理&#xff0c;Spring Boot提供了过滤器和拦截器两种机制来实现这一需求。虽然它们都可以用来处理HTTP请求和响应&#xff0c;但在使用场景、执行顺序和配置方式上存在明显的差异。本文将详细讲解Spri…

【UML用户指南】-01-UML基本元素的介绍(一)

1、UML的词汇表 &#xff08;1&#xff09;事物&#xff1b; &#xff08;2&#xff09;关系&#xff1b; &#xff08;3&#xff09;图。 事物是对模型中首要成分的抽象&#xff1b;关系把事物结合在一起&#xff1b;图聚集了相关的事物。 注&#xff1a;事物也称为元素 2…

东芝机械人电池低报警解除与机器人多旋转数据清零

今天启动一台设备&#xff0c;触摸屏一直显示机器人报警&#xff08;翻译过后为电池电量低&#xff09;&#xff0c;更换电池后关机重启后也不能消除&#xff0c;所以打开示教器&#xff0c;下面就来说说怎么解决此项问题&#xff08;可以参考官方发的手册&#xff0c;已手册为…

携程梁建章:持续投资创新与AI,开启旅游行业未来增长

5月30至31日&#xff0c;携程集团在上海和张家界举办Envision 2024全球合作伙伴大会&#xff0c;邀请超50个国家和地区的1600余名外籍旅游业嘉宾与会&#xff0c;共同探讨中国跨境旅游市场发展机遇&#xff0c;讲好中国故事。 携程国际业务增速迅猛&#xff0c;创新与AI解锁未…

IntelliJ IDEA / Android Studio 方法显示Git提交人

显示方法&#xff1a; 设置 > 编辑器 > 嵌入提示 > Code Vision > 代码作者&#xff08;勾选&#xff09; IntelliJ IDEA Android Studio

css-表头筛选的特定样式

背景 饿了么的表头筛选样式比较简单&#xff0c;如图1&#xff0c;产品觉得不够醒目&#xff08;觉得用户可能不知道这是筛选&#xff0c;我表示不理解&#xff09; 要求改进筛选的样式&#xff0c;达到图2的效果&#xff0c;主要是状态列&#xff0c;既希望这列的宽度固定&a…

git应用最佳实践

插&#xff1a; AI时代&#xff0c;程序员或多或少要了解些人工智能&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家(前言 – 人工智能教程 ) 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家…

Linux内网中安装jdk1.8详细教程

本章教程,主要介绍如何在内网环境中配置JDK1.8环境变量 一、下载Linux版压缩包 下载地址:https://www.oracle.com/java/technologies/downloads/#java8 下载完成之后,通过XFTP等工具,将安装包上传到内网服务器 二、安装配置步骤 1、解压压缩包 tar -zxvf /usr/local/jdk-…

jpeg编码学习

正点原子stm32教程提到过jpeg解码库libjpeg&#xff0c;但是没有提到jpeg编码&#xff0c;我也好奇jpeg编码怎么实现&#xff0c;用代码怎么生成jpeg文件的。所以最近学习了jpeg编码&#xff0c;在这里做记录。 参考文章 jpeg图片格式详解 https://blog.csdn.net/yun_hen/art…