上传文件的基本操作
<form action="/upload" method="post" enctype="multipart/form-data">
<h1>登录</h1>
姓名:<input type="text" name="username" required><br>
年龄:<input type="text" name="age" required><br>
头像:<input type="file" name="file" required><br>
<input type="submit" value="提交">
</form>
// Java接收前端发来的文件
@RestController
public class UploadController {
private static final ch.qos.logback.classic.Logger log = (Logger) LoggerFactory.getLogger(UploadController.class);
@PostMapping(path = "/upload")
public Result upload(String username, Integer age, MultipartFile file){
log.info("接收参数:" + username + age + file);
return Result.success();
}
}
注意:springboot项目启动后,打开这个index.html的页面要输入:localhost:8080/index.html
接下来通过断点调试获取查看前端发送过来的文件
文件的”到此一游“:该文件所在的路径的文件夹是个临时文件夹,运行完毕后这个文件夹里的内容清空
前端上传文件本地存储
@PostMapping("/upload")
public Result upload(String name, Integer age, MultipartFile file) throws IOException {
// 记录接收到的参数,包括姓名、年龄和文件
log.info("接收参数: {}, {}, {}", name, age, file);
// 获取上传文件的原始文件名
String originalFilename = file.getOriginalFilename();
// 将文件保存到指定路径(D:/images/)并命名为原始文件名
file.transferTo(new File( "D:/idea/javacode/web/Getdata/" + originalFilename));
// 返回成功结果
return Result.success();
}
文件上传还存在一个要考虑的问题:如果两次提交的是不一样的文件,但是文件名称一样,那么第二次提交的图片会把第一次提交的文件给替换(覆盖)因此可以使用UUID命名来解决。
生成UUID
import java.util.UUID;
public class UUIDExample {
public static void main(String[] args) {
// 生成一个随机UUID
UUID uuid = UUID.randomUUID();
// 输出UUID
System.out.println("生成的UUID: " + uuid.toString());
}
}
使用UUID解决以上问题
@PostMapping("/upload")
public Result upload(String name, Integer age, MultipartFile file) throws IOException {
// 记录接收到的参数,包括姓名、年龄和文件
log.info("接收参数: {}, {}, {}", name, age, file);
// 获取上传文件的原始文件名,例如 "1.jpg" 或 "22.2.2.2.png"
String originalFilename = file.getOriginalFilename();
// 获取文件扩展名,从最后一个点后开始截取
String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
// 生成新的文件名,使用UUID并加上文件扩展名
String newFileName = UUID.randomUUID().toString() + extension;
// 将文件保存到指定路径(D:/images/)并命名为新的文件名
file.transferTo(new File("D:/images/" + newFileName));
// 返回成功结果
return Result.success();
}
file.transferTo(new File("D:/idea/javacode/web/Getdata/" + newFileName));
这个代码的路径最后一定要写个“/”,使得文件保存在那个文件夹下。
上传文件大小限制
默认上传文件的最大大小为1MB,超过该大小需要在配置文件配置
servlet:
multipart:
# 最大单个文件大小
max-file-size: 10MB
# 最大请求大小(包括所有文件和表单数据)
max-request-size: 100MB
阿里云OSS
阿里云对象存储oss(object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用oss
您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。
配置好相关密钥等配置后,创建bucket。接下来可以通过Java代码将自己电脑本地的文件上传到阿里云。
添加好下面的依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
具体的上传文件的代码
public static void main(String[] args) throws com.aliyuncs.exceptions.ClientException {
/**
* 基础配置:连接服务并验证个人身份
*/
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-shenzhen.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "q-buckets";
/**
* 配置具体文件上传信息
*/
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = "ph.webp"; // 可以修改名字
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
String filePath= "D:\\Mycode\\webcode\\imag\\nu.webp";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
try {
// 创建PutObjectRequest对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new File(filePath));
// 如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
// ObjectMetadata metadata = new ObjectMetadata();
// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
// metadata.setObjectAcl(CannedAccessControlList.Private);
// putObjectRequest.setMetadata(metadata);
// 上传文件。
PutObjectResult result = ossClient.putObject(putObjectRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
这样就可以在自己阿里云的bucket里面看到上传的文件
参考:后端之路
文件上传操作整合为工具类并在Controller中使用
具体代码如下
@Component // 方便依赖注入
public class AliyunOSSOperation {
// 指定阿里云OSS的服务地址,这里是深圳区域的地址
private String endpoint = "https://oss-cn-shenzhen.aliyuncs.com";
// 指定要上传到的存储桶名称
private String bucketName = "lwq-buckets";
// 指定阿里云的区域,这里是深圳区域
private String region = "cn-shenzhen";
/**
* 上传文件到阿里云OSS
* @param content 文件的字节数组内容
* @param originalFilename 原始文件名,用于生成新的文件名
* @return 上传后文件的访问路径
* @throws Exception 可能抛出的异常
*/
public String upload(byte[] content, String originalFilename) throws Exception {
// 从环境变量中获取访问密钥,确保在运行代码前设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET
EnvironmentVariableCredentialsProvider credentialsProvider =
CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 获取object对象路径,例如2024/06/21.png。Object类型中不能包含Bucket名称
String dir = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM"));
// 生成一个新的文件名,使用UUID确保唯一性,并保留原始文件的扩展名
String newFileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
String objectName = dir + "/" + newFileName; // 生成完整的对象名称
// 创建OSSClient实例
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4); // 设置签名版本为V4
// 使用OSSClientBuilder创建OSS客户端实例,配置包括端点、凭证提供者、客户端配置和区域
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// 上传文件内容到指定的存储桶和对象路径
ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content));
} finally {
// 确保无论上传是否成功,都会关闭OSS客户端
ossClient.shutdown();
}
// 生成并返回文件的完整访问路径
return endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + objectName;
}
}
使用该类
@Autowired // 自动注入AliyunOSSOperator实例
private AliyunOSSOperator aliyunOSSOperator;
@PostMapping("/upload") // 定义一个POST请求处理方法,映射到/upload路径
public Result upload(MultipartFile file) throws Exception {
// 记录上传文件的原始文件名到日志
log.info("文件上传: {}", file.getOriginalFilename());
// 调用aliyunOSSOperator的upload方法,将文件字节和文件名上传到OSS
String url = aliyunOSSOperator.upload(file.getBytes(), file.getOriginalFilename());
// 记录文件上传后返回的URL到日志
log.info("文件上传OSS, url: {}", url);
// 返回上传结果,包含文件的访问URL
return Result.success(url);
}
这样上传到阿里云的文件以年月划分了文件夹
参数配置进一步优化
- 指将一些需要灵活变化的参数,配置在配置文件中,然后通过 @Value 注解来注入外部配置的属性。
aliyun: oss: endpoint: https://oss-cn-beijing.aliyuncs.com bucketName: java-ai region: cn-beijing
以上配置信息配置在yml文件中
@Value("${aliyun.oss.endpoint}") private String endpoint; @Value("${aliyun.oss.bucketName}") private String bucketName; @Value("${aliyun.oss.region}") private String region;