[推荐]SpringBoot java实现文件/附件上传下载 服务器 数据库 拿来就用,简单实用

推荐一个思路非常简单又很实用的文件上传下载方式,代码十分简练,可以开箱即用,下面是使用到的一些工具类和业务代码;

1.文件上传实现

判断文件类型的工具类,一些使用到的实体类我会凡在文末,需要可以的自取

    public static int fileType(String fileName) {if (fileName == null) {return 0;} else {// 获取文件后缀名并转化为写,用于后续比较String fileType = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();// 创建图片类型数组String img[] = {"bmp", "jpg", "jpeg", "png", "tiff", "gif", "pcx", "tga", "exif", "fpx", "svg", "psd","cdr", "pcd", "dxf", "ufo", "eps", "ai", "raw", "wmf"};for (int i = 0; i < img.length; i++) {if (img[i].equals(fileType)) {return 1;}}// 创建文档类型数组String document[] = {"txt", "doc", "docx", "xls", "htm", "html", "jsp", "rtf", "wpd", "pdf", "ppt"};for (int i = 0; i < document.length; i++) {if (document[i].equals(fileType)) {return 2;}}// 创建视频类型数组String video[] = {"mp4", "avi", "mov", "wmv", "asf", "navi", "3 gp", "mkv", "f4v", "rmvb", "webm"};for (int i = 0; i < video.length; i++) {if (video[i].equals(fileType)) {return 3;}}// 创建音乐类型数组String music[] = {"mp3", "wma", "wav", "mod", "ra", "cd", "md", "asf", "aac", "vqf", "ape", "mid", "ogg","m4a", "vqf"};for (int i = 0; i < music.length; i++) {if (music[i].equals(fileType)) {return 4;}}}return 0;}

1.2 Controller层代码

部分小伙伴因为是springboot项目且版本大于2.3,@Valid注解报错找不到,需要手动添加依赖,如果对“优雅的Java参数校验”感兴趣的伙伴可以见我另一篇文章优雅的参数校验@Validated 实战 + 统一异常处理返回前端json 最全解析

        <dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>2.0.1.Final</version></dependency>
@Api(tags = "附件管理")
@RestController
@RequestMapping("/attach")
public class AttachmentController {@Autowiredprivate AttachmentService attachmentService;@PostMapping("/upload")@ApiOperation(value = "上传文件")public ResponseResult upload(@RequestPart("file") MultipartFile file,@RequestParam(value = "bussinessId") @Valid @NotBlank(message = "业务id不能为空") String bussinessId) throws Exception {return attachmentService.upload(file, bussinessId);}

1.3 Service层业务代码

接口类

import com.yuncheng.entity.ResponseResult;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;public interface AttachmentService {ResponseResult upload(MultipartFile file, String bussinessId) throws Exception;}

实现类,注释很清晰了


import com.yuncheng.entity.ResponseResult;
import com.yuncheng.entity.enums.AppHttpCodeEnum;
import com.yuncheng.pc.entity.UploadFile;
import com.yuncheng.pc.mapper.UploadFileMapper;
import com.yuncheng.pc.service.AttachmentService;
import com.yuncheng.utils.Tools;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;import lombok.extern.slf4j.Slf4j;@Slf4j
@Service
public class AttachmentServiceImpl implements AttachmentService {private static final String LOCAL_HOST = "http://10.11.0.104:8866/";@Autowiredprivate UploadFileMapper uploadFileMapper;@Override@Transactionalpublic ResponseResult upload(MultipartFile multipartFile, String bussinessId) throws Exception {if (multipartFile.isEmpty()) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID,"上传文件为空");}UploadFile uploadFile = new UploadFile();// 保存原文件名称,文件列表展示需要用到uploadFile.setFileName(multipartFile.getOriginalFilename());// 生成系统文件名称,不可重复,防止同名文件上传覆盖问题String name = RandomStringUtils.randomAlphanumeric(32) + multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".")).toLowerCase();uploadFile.setName(name.substring(0, name.lastIndexOf(".")));uploadFile.setFileSuffix(multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".")).toLowerCase());// 判断文件类型int fileType = Tools.fileType(name);uploadFile.setType(fileType);uploadFile.setDomain(LOCAL_HOST + "resource/files/");//这种方式比类型强转效率更高String pathExt = System.currentTimeMillis()+"";uploadFile.setPath(LOCAL_HOST + "resource/files/" + pathExt);uploadFile.setPathExt(pathExt);// 获取文件大小uploadFile.setSize((int)multipartFile.getSize());uploadFile.setBussinessId(bussinessId);uploadFile.setStatus(1);uploadFile.setCreateTime(new Date());uploadFile.setId(Tools.getCode32());uploadFileMapper.insert(uploadFile);// 将文件保存到本目录/resources/files/下// DateUtil.today()得到得是当天日期如:20230715,这个会在/resources/files/下再以日期生成一层目录File newFile = new File("./resources/files/"+ pathExt +  "/" + name);// 保证这个文件的父文件夹必须要存在if (!newFile.getParentFile().exists()) {newFile.getParentFile().mkdirs();}newFile.createNewFile();// 将文件内容写入到这个文件中InputStream is = multipartFile.getInputStream();FileOutputStream fos = new FileOutputStream(newFile);try {int len;byte[] buf = new byte[1024];while ((len = is.read(buf)) != -1) {fos.write(buf, 0, len);}} finally {// 关流顺序,先打开的后关闭fos.close();is.close();}// 返回文件信息给前端Map resultMap = new HashMap();resultMap.put("id", uploadFile.getId());resultMap.put("path", uploadFile.getPath());return ResponseResult.okResult(resultMap);}
}

1.4 Mapper层代码

import com.yuncheng.pc.entity.UploadFile;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper
public interface UploadFileMapper {void insert(@Param("uploadFile") UploadFile uploadFile);
}

对应sql语句

    <insert id="insert">insert into "SYSDBA"."ATTACHMENT"("ID", "CREATE_BY", "CREATE_TIME", "STATUS", "UPDATE_BY","UPDATE_TIME", "NAME", "FILE_NAME", "FILE_SUFFIX", "TYPE","DOMAIN", "PATH", "PATH_EXT", "SIZE", "BUSSINESS_ID")VALUES(#{uploadFile.id},#{uploadFile.createBy},#{uploadFile.createTime},#{uploadFile.status},#{uploadFile.updateBy},#{uploadFile.updateTime},#{uploadFile.name},#{uploadFile.fileName},#{uploadFile.fileSuffix},#{uploadFile.type},#{uploadFile.domain},#{uploadFile.path},#{uploadFile.pathExt},#{uploadFile.size},#{uploadFile.bussinessId})</insert>

1.5 测试功能

至此文件上传代码就写好了,我们去postman测试一下,记住选post类型且文件类型要选对
在这里插入图片描述
点击发送即上传成功
在这里插入图片描述

2 文件下载代码

2.1 controller层代码

    @GetMapping("/download")@ApiOperation(value = "下载文件")public void download(HttpServletResponse response,@Valid @NotBlank(message = "id不能为空") String id) throws Exception {attachmentService.download(response, id);}

2.2 Service层代码

接口


ResponseResult download(HttpServletResponse response, String id) throws Exception;

实现类

    @Overridepublic ResponseResult download(HttpServletResponse response, String id) throws Exception {List<UploadFile> uploadFiles = uploadFileMapper.selectOne(id, null, 1);if (CollectionUtils.isEmpty(uploadFiles)) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "查询文件为空");}// 去./resources/files/目录下取出文件File downloadFile = new File("./resources/files/" +uploadFiles.get(0).getPathExt() +  "/" + uploadFiles.get(0).getName() + uploadFiles.get(0).getFileSuffix());if (!downloadFile.exists() || downloadFile.length() == 0) {return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "查询文件为空");}InputStream is = null;OutputStream os = null;try {// 判断是否是图片,如果是图片加上 response.setContentType("image/jpeg"),这样就可以直接在浏览器打开而不是下载if (uploadFiles.get(0).getType() == 1) {response.setContentType("image/jpeg");}response.addHeader("Content-Length", "" + downloadFile.length());is = new FileInputStream(downloadFile);os = response.getOutputStream();IOUtils.copy(is, os);} catch (Exception e) {log.error("下载图片发生异常", e);} finally {try {if (os != null) {os.flush();os.close();}if (is != null) {is.close();}} catch (IOException e) {log.error("关闭流发生异常", e);}}return ResponseResult.okResult("下载成功");}

2.3 Mapper层代码

    List<UploadFile> selectOne(@Param("id") String id, @Param("bussinessId") String bussinessId, @Param("status") Integer status);

对应SQL语句

    <select id="selectOne" resultType="com.yuncheng.pc.entity.UploadFile">select *from "SYSDBA"."ATTACHMENT"where status = #{status}<if test="id != null and id != ''">and id = #{id}</if><if test="bussinessId != null and bussinessId != ''">and bussiness_id = #{bussinessId}</if></select>

2.4 测试功能

在这里插入图片描述

下面是一些使用到的实体类和建表语句,有需要的小伙伴可以自取,如果觉得文章对您有用的话记得点赞 收藏 关注哦!!!,主页全是实用文章待你来取!

文件上传实体类

import lombok.Data;import java.util.Date;@Data
public class UploadFile {private String id;//文件在系统中的名称private String name;//文件名称private String fileName;//文件后缀private String fileSuffix;//文件类型private Integer type;//主目录private String domain;//完整目录private String path;//扩展目录private String pathExt;//文件大小private Integer size;//关联的业务idprivate String bussinessId;//逻辑删除状态private Integer status;private Date createTime;private String createBy;private Date updateTime;private String updateBy;
}

统一结果返回bean

import com.yuncheng.entity.enums.AppHttpCodeEnum;
import lombok.Data;import java.io.Serializable;/*** 通用的结果返回类* @param <T>*/
@Data
public class ResponseResult<T> implements Serializable {private String token;private Integer code;private String message;private T data;private String status;public ResponseResult() {this.code = 200;}public ResponseResult(Integer code, T data) {this.code = code;this.data = data;}public ResponseResult(Integer code, String msg, T data) {this.code = code;this.message = msg;this.data = data;}public ResponseResult(Integer code, String msg) {this.code = code;this.message = msg;}public static ResponseResult okResult(int code, String msg) {ResponseResult result = new ResponseResult();return result.ok(code, null, msg);}public static ResponseResult okResult(int code, Object data,String msg) {ResponseResult result = new ResponseResult();return result.ok(code, data, msg);}public static ResponseResult okResult(Object data) {ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getMessage());if(data!=null) {result.setData(data);}return result;}public static ResponseResult errorResult(int code, String msg) {ResponseResult result = new ResponseResult();return result.error(code, msg);}public static ResponseResult errorResult(AppHttpCodeEnum enums){return setAppHttpCodeEnum(enums,enums.getMessage());}public static ResponseResult errorResult(AppHttpCodeEnum enums, String message){return setAppHttpCodeEnum(enums,message);}public static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums){return okResult(enums.getCode(),enums.getMessage());}private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String message){return okResult(enums.getCode(),message);}public ResponseResult<?> error(Integer code, String msg) {this.code = code;this.message = msg;return this;}public ResponseResult<?> ok(Integer code, T data) {this.code = code;this.data = data;return this;}public ResponseResult<?> ok(Integer code, T data, String msg) {this.code = code;this.data = data;this.message = msg;return this;}public ResponseResult<?> ok(T data) {this.data = data;return this;}
}

状态码枚举类

package com.yuncheng.entity.enums;public enum AppHttpCodeEnum {// 成功段固定为200SUCCESS(200,"操作成功"),// 登录段1~50NEED_LOGIN(1,"需要登录后操作"),LOGIN_PASSWORD_ERROR(2,"密码错误"),// TOKEN50~100TOKEN_INVALID(50,"无效的TOKEN"),TOKEN_EXPIRE(51,"TOKEN已过期"),TOKEN_REQUIRE(52,"TOKEN是必须的"),// SIGN验签 100~120SIGN_INVALID(100,"无效的SIGN"),SIG_TIMEOUT(101,"SIGN已过期"),// 参数错误 500~1000PARAM_REQUIRE(500,"缺少参数"),PARAM_INVALID(501,"无效参数"),PARAM_IMAGE_FORMAT_ERROR(502,"图片格式有误"),SERVER_ERROR(503,"服务器内部错误"),// 数据错误 1000~2000DATA_EXIST(1000,"数据已经存在"),AP_USER_DATA_NOT_EXIST(1001,"ApUser数据不存在"),DATA_NOT_EXIST(1002,"数据不存在"),DATA_DUPLICATE(1003,"数据重复"),OPERATION_FAILED(1004,"操作失败"),// 数据错误 3000~3500NO_OPERATOR_AUTH(3000,"无权限操作"),NEED_ADMIND(3001,"需要管理员权限");int code;String message;AppHttpCodeEnum(int code, String errorMessage){this.code = code;this.message = errorMessage;}public int getCode() {return code;}public String getMessage() {return message;}
}

建表语句

CREATE TABLE "SYSDBA"."ATTACHMENT"
(
"ID" VARCHAR2(64) NOT NULL,
"CREATE_BY" VARCHAR(64),
"CREATE_TIME" TIMESTAMP(0),
"STATUS" INTEGER,
"UPDATE_BY" VARCHAR(64),
"UPDATE_TIME" TIMESTAMP(0),
"NAME" VARCHAR(100),
"FILE_NAME" VARCHAR(100),
"FILE_SUFFIX" VARCHAR(50),
"TYPE" INTEGER,
"DOMAIN" CHARACTER(100),
"PATH" VARCHAR(100),
"PATH_EXT" VARCHAR(50),
"SIZE" INTEGER,
"BUSSINESS_ID" VARCHAR(100) NOT NULL) STORAGE(ON "MAIN", CLUSTERBTR) ;COMMENT ON TABLE "SYSDBA"."ATTACHMENT" IS '附件表';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."BUSSINESS_ID" IS '业务id';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."CREATE_BY" IS '创建人';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."CREATE_TIME" IS '创建日期';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."DOMAIN" IS '主目录';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."FILE_NAME" IS '原文件名';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."FILE_SUFFIX" IS '文件后缀';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."ID" IS '业务id';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."NAME" IS '系统文件名';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."PATH" IS '路径';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."PATH_EXT" IS '扩展目录';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."SIZE" IS '文件大小';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."STATUS" IS '删除标志';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."TYPE" IS '类型';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."UPDATE_BY" IS '更新人';
COMMENT ON COLUMN "SYSDBA"."ATTACHMENT"."UPDATE_TIME" IS '修改时间';

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

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

相关文章

吴恩达《机器学习》4-1->4-5:多变量线性回归

一、引入多维特征 在多维特征中&#xff0c;我们考虑的不再是单一的特征&#xff0c;而是一组特征&#xff0c;例如房价模型中可能包括房间数、楼层等多个特征。这些特征将组成一个向量&#xff0c;表示为(&#x1d465;₁, &#x1d465;₂, . . . , &#x1d465;ₙ)&#x…

nodelist 与 HTMLCollection 的区别

原地址 https://cloud.tencent.com/developer/article/2013289 节点与元素 根据 W3C 的 HTML DOM 标准&#xff0c;HTML 文档中的所有内容都是节点&#xff1a; 整个文档是一个文档节点每个 HTML 元素是元素节点HTML 元素内的文本是文本节点每个 HTML 属性是属性节点注释是注…

ts 简易封装 axios,统一 API

文章目录 为什么要封装目标文件结构封装通用请求方法获得类型提示http 方法文件上传使用示例实例化post 请求类型提示文件上传 总结完整代码&#xff1a; 为什么要封装 axios 本身已经很好用了&#xff0c;看似多次一举的封装则是为了让 axios 与项目解耦。比如想要将网络请求…

视频增强和修复工具 Topaz Video AI mac中文版功能

Topaz Video AI mac是一款使用人工智能技术对视频进行增强和修复的软件。它可以自动降噪、去除锐化、减少压缩失真、提高清晰度等等。Topaz Video AI可以处理各种类型的视频&#xff0c;包括低分辨率视频、老旧影片、手机录制的视频等。 使用Topaz Video AI非常简单&#xff0c…

突破防火墙的一种方法

当Linux防火墙阻止来自某个ip的数据时&#xff0c;它应该是根据ip数据报里“源IP地址”字段取得的对方ip吧&#xff0c;那对方就不能通过篡改“源IP地址”来绕过防火墙吗&#xff1f;NAT模式下的路由器就修改了这个字段。 但这样的话&#xff0c;攻击者是收不到服务器返回的数…

学 Java 怎么进外企?

作者&#xff1a;**苍何&#xff0c;CSDN 2023 年 实力新星&#xff0c;前大厂高级 Java 工程师&#xff0c;阿里云专家博主&#xff0c;土木转码&#xff0c;现任部门技术 leader&#xff0c;专注于互联网技术分享&#xff0c;职场经验分享。 &#x1f525;热门文章推荐&#…

麒麟KYLINIOS软件仓库搭建01-新创建软件仓库服务器

原文链接&#xff1a;麒麟KYLINIOS软件仓库搭建01-新创建软件仓库服务器 hello&#xff0c;大家好啊&#xff0c;今天给大家带来麒麟桌面操作系统软件仓库搭建的文章01-新创建软件仓库服务器&#xff0c;本篇文章主要给大家介绍了如何在麒麟桌面操作系统2203-x86版本上搭建内网…

docker 下安装mysql8.0

在docker中查询mysql镜像 PS C:\Users\admin> docker search mysql NAME DESCRIPTION STARS OFFICIAL AUTOMATED mysql MySQL is a widely used, open-source relation……

【Python_GraphicsView 学习笔记(一)】Graphics View框架的基本介绍

【Python_GraphicsView 学习笔记&#xff08;一&#xff09;】Graphics View框架的基本介绍 前言正文1、Graphics View框架简介2、Graphics View框架与QPainter类的区别3、Graphics View框架的三个组成部分4、场景QGraphicsScene类5、视图QGraphicsView类6、图形项QGraphicsIte…

深度学习_3 数据操作之线代,微分

线代基础 标量 只有一个元素的张量。可以通过 x torch.tensor(3.0) 方式创建。 向量 由多个标量组成的列表&#xff08;一维张量&#xff09;。比如 x torch.arange(4) 就是创建了一个1*4的向量。可以通过下标获取特定元素&#xff08;x[3]&#xff09;&#xff0c;可以通…

Vue3入门指南:零基础小白也能轻松理解的学习笔记

文章目录 创建项目开发环境项目目录模板语法属性绑定条件渲染列表渲染事件处理内联事件处理器方法事件处理器&#xff08;常用&#xff09; 事件参数获取 event 事件事件传参 事件修饰符阻止默认事件阻止事件冒泡 数组变化侦测变更方法替换一个数组 计算属性class 绑定单对象绑…

野火霸天虎 STM32F407 学习笔记_1 stm32介绍;调试方法介绍

STM32入门——基于野火 F407 霸天虎课程学习 前言 博主开始探索嵌入式以来&#xff0c;其实很早就开始玩 stm32 了。但是学了一段时间之后总是感觉还是很没有头绪&#xff0c;不知道在学什么。前前后后分别尝试了江协科技、正点原子、野火霸天虎三次 stm32 的课程学习。江协科…

多模态 多引擎 超融合 新生态!2023亚信科技AntDB数据库8.0产品发布

9月20日&#xff0c;以“多模态 多引擎 超融合 新生态”为主题的亚信科技AntDB数据库8.0产品发布会成功举办&#xff0c;从技术和生态两个角度全方位展示了AntDB数据库第8次大型能力升级和生态建设成果。浙江移动、用友、麒麟软件、华录高诚、金云智联等行业伙伴及业界专家共同…

如何做好网页配色,分享一些配色方案和方法

很多网页设计师在选择网页配色方案时&#xff0c;会纠结于用什么网页UI配色方案来吸引客户的注意力&#xff0c;传达信息。选择正确的颜色是网页设计不可或缺的一部分。本指南将从色彩理论和色彩心理学入手&#xff0c;分享三个网页UI配色的简单步骤。 网页UI配色方法有很多&a…

关于msvcp120.dll丢失的解决方法详解,快速解决dll丢失问题

在计算机使用过程中&#xff0c;经常会遇到“msvcp120.dll丢失”的错误提示。这个错误提示通常出现在运行某些程序或游戏时&#xff0c;造成相关应用程序可能无法正常启动或运行。那么&#xff0c;究竟是什么原因导致了msvcp120.dll文件的丢失呢&#xff1f;本文将详细解析msvc…

在 Linux 中更改 echo 的输出颜色

文章目录 前言一、快速入门二、基本使用2.1 对于常规的输出2.2 对于字体加粗的输出2.3 对于字体斜体的输出2.4 对于带下划线的输出2.5 对于闪烁效果的输出 三、小结 前言 在计算机编程世界中&#xff0c;颜色不仅仅是一种视觉效果&#xff0c;它也是一种信息传递的工具。特别是…

Doris:StreamLoad导入数据

目录 1.基本原理 2.支持数据格式 3.StreamLoad语法 3.1.请求参数 3.2.返回参数 4.StreamLoad实践 4.1.使用 curl命令 4.2.使用Java代码 Stream load 是一个同步的导入方式&#xff0c;用户通过发送 HTTP 协议发送请求将本地文件或数据流导入到 Doris 中。Stream load 主…

免费记课时小程序-全优学堂

1. 教师使用小程序记上课 使用步骤 创建了员工账号&#xff0c;员工需设置为教师为班级进行排课使用系统账号绑定小程序&#xff0c;记上课 #1.1 创建员工账号 通过系统菜单’机构设置->员工管理‘&#xff0c;添加本机构教师及其他员工。 添加过程中&#xff0c;可设置…

ffmpeg mp3截取命令,视频与mp3合成带音频视频命令

从00:00:03.500开始截取往后长度到结尾的mp3音频&#xff08;这个更有用&#xff0c;测试好用&#xff09; ffmpeg -i d:/c.mp3 -ss 00:00:03.500 d:/output.mp3 将两个音频合并成一个音频&#xff08;测试好用&#xff09; ffmpeg -i "concat:d:/c.mp3|d:/output.mp3&…

CSS3设计动画样式

CSS3动画包括过渡动画和关键帧动画&#xff0c;它们主要通过改变CSS属性值来模拟实现。我将详细介绍Transform、Transitions和Animations 3大功能模块&#xff0c;其中Transform实现对网页对象的变形操作&#xff0c;Transitions实现CSS属性过渡变化&#xff0c;Animations实现…