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: /apiflyway:enabled: true #开启数据迁移table: flyway_schema_history #用于存储迁移历史记录的表名,默认为flyway_schema_historybaseline-on-migrate: true #当迁移数据库存在但没有元数据的表时,自动执行基准迁移,新建flyway_schema_history表locations: classpath:db/migration #数据库迁移脚本的位置,默认为classpath:db/migration,classpath 羡慕resources目录clean-disabled: true #用于控制是否禁用 Flyway 的 clean 操作。datasource:username: rootpassword: rooturl: jdbc:mysql://127.0.0.1:3306/java_iot?serverTimezone=GMT%2b8config:activate:on-profile: dev #开发环境servlet:multipart:enabled: true # 允许文件上传max-file-size: 20971520 # 单文件最大限制 20Mmax-request-size: 52428800 # 单次请求最大限制 50M
file:upload:path: E:\project-java\java-upload  # 文件上传保存服务器绝对路径suffix: jpg,jpeg,png,bmp,xls,xlsx,pdf  # 文件上传保存路径is-thumb: true  # 是否开启缩略图 true falseproportion: 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前缀@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix(pathPrefix, c -> c.isAnnotationPresent(RestController.class));}//静态资源图片上传,虚拟路径返回@Overridepublic 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;@AutowiredHttpServletRequest request;@AutowiredFileMapper fileMapper;//文件上传@Overridepublic 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;}//获取文件md5String 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;}//生成缩率图@Overridepublic 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 {@AutowiredFileServer 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同名

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring分析工具_springboot startup analyze的部署和使用

工具是开源工具 ,可以放心使用 我是从开源中国OCSChina看到的顺便安利一下 部署 教程 https://github.com/linyimin0812/spring-startup-analyzer 直接下载地址 https://github.com/linyimin0812/spring-startup-analyzer/releases/download/v3.0.0/spring-startup-analyzer.…

c++------类和对象(下)包含了this指针、构造函数、析构函数、拷贝构造等

文章目录 前言一、this指针1.1、this指针的引出1.2、 this指针的特性 二、类的默认的六个构造函数2.1、构造函数简述2.2构造函数 三、析构函数3.1、析构函数引出3.2、特点&#xff1a; 四、拷贝构造4.1、引入4.2、特征&#xff1a;4.3、默认拷贝构造函数 总结 前言 在本节中&a…

BUUCTF中的密码题目解密

BUUCTF 1.MD5 题目名称就是MD5&#xff0c;这个题目肯定和md5密码有关&#xff0c;下载题目&#xff0c;打开后发现这确实是一个md5加密的密文 Md5在线解密网站&#xff1a;md5在线解密破解,md5解密加密 经过MD5在线解密网站解密后&#xff0c;获取到flag为&#xff1a;flag{…

burp插件new_xp_capcha识别验证码的简易安装

1.new_xp_capcha 插件是大佬开发的可以正常白嫖&#xff0c;感谢大佬&#xff0c;我找了个不需要任何高级操作就可以做的安装手法&#xff0c;因为我在网上搜了一下就发现这个的安装过程攻略都还蛮复杂&#xff0c;我这里用了个简单的手法 2.安装 下载地址&#xff1a;smxia…

【软件设计师】2022年上半年真题解析

​​冯诺依曼计算机体系结构的基本特点是&#xff1a; A. 程序指令和数据都采用二进制表示 - 这是正确的&#xff0c;因为冯诺依曼架构下的计算机使用二进制形式来表示和处理所有信息&#xff0c;包括指令和数据。 B. 程序指令总是存储在主存中&#xff0c;而数据则存储在高速…

二维数组传参时不用二级指针接收

先放结论&#xff1a; 1. 二维数组数组名指向的类型是 int [x] 类型&#xff0c;int** 指针指向类型是 int* &#xff0c;如果用二级指针接收会导致访问错误&#xff0c;因为 int [x] 类型和 int* 类型不同。 2. 指向什么类型的指针1就按照该类型的字节数1移动。 最近在学…

Kafka 集群 KRaft 模式搭建

一、Kafka 集群 KRaft 介绍 Kafka的KRaft模式是一种新的元数据管理方式&#xff0c;旨在去除对ZooKeeper的依赖&#xff0c;使Kafka成为一个完全自包含的系统。在Kafka的传统模式下&#xff0c;元数据管理依赖于ZooKeeper&#xff0c;这增加了部署和运维的复杂性。为了解决这个…

MySQL—函数(介绍)—字符串函数(基础)

一、引言 提到函数&#xff0c;在SQL分类中DQL语句中有一个聚合函数&#xff0c;如COUNT()、SUM()、MAX()等等。这些都是一些常见的聚合函数&#xff0c;而聚合函数只是函数的一种&#xff0c;接下来会详细的学习和介绍一下函数的应用场景和以及 mysql 当中文件的函数有哪些。 …

大学生Python自救课程总结

因为一些事情的缘故&#xff0c;我已经几乎没有更新很久了&#xff0c;然后现在快到期末了&#xff0c;不知道各位学习python的同志们慌不慌【坏笑】。 本学期&#xff0c;我只是简单的讲了讲python的基础用法。当然&#xff0c;可能有些地方总结的并不全面&#xff0c;很多知…

.gitignore 文件

一.什么是 .gitignore 文件 在任何当前工作的 Git 仓库中&#xff0c;每个文件都是这样的&#xff1a; 追踪的&#xff08;tracked&#xff09;- 这些是 Git 所知道的所有文件或目录。这些是新添加&#xff08;用 git add 添加&#xff09;和提交&#xff08;用 git commit 提…

allure测试报告用例数和 pytest执行用例数不相同问题

我出现的奇怪问题&#xff1a; pytest执行了9条用例&#xff0c;但是测试报告确只显示3条用例 我将其中的一个代码删除后&#xff0c;发现allure测试报告又正常了 我觉得很奇怪这个代码只是删除了二维数组的第一列&#xff0c;我检查了半天都找不到问题&#xff0c;只有降低版本…

【自撰写,国际象棋入门】第1课、棋盘和棋子

第1课 棋盘和棋子 一、国际象棋的棋盘 国际象棋的棋盘为一8乘8的黑、白格相间的棋盘&#xff0c;8条竖线的编号分别为A-H&#xff0c;8条横线的编号分别为1-8&#xff0c;在记谱时用竖线编号横线编号的方式表示棋盘上的格子&#xff0c;例如a1格、h8格等.棋盘上有几条重要的大…

【数据密集型系统设计】软件系统的可靠性、可伸缩性、可维护性

文章目录 一. 数据密集型程序的特点以及遇到的问题二. 可靠性 : 即使出现问题&#xff0c;也能继续正确工作1 硬件故障2. 软件错误3. 人为错误 二. 可伸缩性1. 描述负载与推特的例子2. 描述性能-延迟和响应时间3. 应对负载的方法 四. 可维护性1. 可操作性&#xff1a;人生苦短&…

汇编:调用Win32 API

在32位汇编程序中使用 Win32 API 是很常见的&#xff0c;特别是在开发 Windows 应用程序时调用的频率很高&#xff0c;Win32 API 提供了访问 Windows 操作系统功能的接口&#xff0c;包括窗口、消息处理、文件操作、网络通信等等。以下是使用 Win32 API 的一般步骤&#xff1a;…

数据结构与算法03-散列表(哈希表)

介绍 散列表&#xff08;Hash table&#xff0c;也叫哈希表&#xff09;&#xff0c;是根据键&#xff08;Key&#xff09;而直接访问在存储器存储位置的数据结构。也就是说&#xff0c;它通过计算出一个键值的函数&#xff0c;将所需查询的数据映射到表中一个位置来让人访问&…

队列——一种操作受限的线性表

队列 队列&#xff08;Queue&#xff09;简称队&#xff0c;也是一种操作受限的线性表&#xff0c;只允许在表的一端进行插入&#xff0c;而在表的另一端进行删除。向队列中插入元素称为入队或进队&#xff0c;删除元素称为出队或离队。队列中的元素是先进先出&#xff08;Fir…

win_os_linux不能用于文件名的保留字符

windows 在 Windows 文件系统中&#xff0c;以下字符是保留字符&#xff0c;不能用于文件名或目录名&#xff1a; < (小于号)> (大于号): (冒号)" (双引号)/ (斜杠)\ (反斜杠)| (竖线)? (问号)* (星号) 此外&#xff0c;文件名不能以空格或句点 (.) 结尾&#x…

关于Golang中自定义包的简单使用-Go Mod

1. go env 查看 GO111MODULE 是否为 on&#xff0c;不是修改成on go env -w GO111MODULEon 2 .自定义包的目录格式 3. test.go 内容 package calc func Add(x, y int) int { // 首字母大写表示公有方法return x y }func Sub(x, y int) int {return x - y } 4.生成calc目…

动规算法-地下城游戏

在刷题练习专栏中&#xff0c;已经写了两篇文章实现对动态规划入门题目的讲解了&#xff0c;动态规划这类题目很难很好的掌握&#xff0c;今天给大家带来稍微深入的题目&#xff0c;帮助大家更好的理解动态规划的算法思想&#xff0c;加深对该算法的理解&#xff0c;建议看每道…

高考试卷押运车视频监控解决方案

一、引言 高考作为我国教育领域的重要事件&#xff0c;其公正、公平和安全性一直备受社会关注。试卷押运作为高考的重要环节&#xff0c;其安全性直接关系到高考的顺利进行和考生的切身利益。因此&#xff0c;对高考试卷押运车实施视频监控解决方案&#xff0c;对于确保试卷安…