【尚庭公寓SpringBoot + Vue 项目实战】图片上传(十)

【尚庭公寓SpringBoot + Vue 项目实战】图片上传(十)


文章目录

      • 【尚庭公寓SpringBoot + Vue 项目实战】图片上传(十)
        • 1、图片上传流程
        • 2、图片上传接口查看
        • 3、代码开发
          • 3.1、配置Minio Client
          • 3.2、开发上传图片接口
        • 4、异常处理

1、图片上传流程

​ 由于公寓、房间等实体均包含图片信息,所以在新增或修改公寓、房间信息时,需要上传图片,因此我们需要实现一个上传图片的接口。

下图展示了新增房间或公寓时,上传图片的流程。

image-20240614211618302

可以看出图片上传接口接收的是图片文件,返回的Minio对象的URL

2、图片上传接口查看

image-20240614211817521

接口信息:

  • 请求地址: /admin/file/upload
  • 请求类型: POST
  • 请求内容类型: multipart/form-data

请求参数:

参数名称参数说明请求类型是否必须数据类型schema
file文件querytruefile

响应状态:

状态码说明
200OK

响应参数:

参数名称类型参数说明
codeinteger(int32)返回码
messagestring返回信息
datastring数据

响应示例:

{
  "code": 0,
  "message": "",
  "data": ""
}

解释:

  • 请求地址:此接口的请求地址是 /admin/file/upload,用于上传文件。
  • 请求类型POST 表示这是一个 POST 请求。
  • 请求内容类型multipart/form-data 表示请求数据需要以多部分表单数据格式发送。
  • 请求参数
    • file:文件,必须提供,用于上传的文件。
  • 响应状态:200 表示请求成功。
  • 响应参数
    • code:返回码,整数类型,表示请求的状态。
    • message:返回信息,字符串类型,描述请求的结果。
    • data:数据,字符串类型,通常包含上传文件的相关信息或 URL。
3、代码开发
3.1、配置Minio Client

引入依赖

common模块pom.xml文件增加如下内容:

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
</dependency>

配置Minio相关参数

application.yml中配置Minio的endpointaccessKeysecretKeybucketName等参数

minio:
  endpoint: http://<hostname>:<port>
  access-key: <access-key>
  secret-key: <secret-key>
  bucket-name: <bucket-name>

**注意:**上述<hostname><port>等信息需根据实际情况进行修改。

common模块中创建com.atguigu.lease.common.minio.MinioProperties,内容如下

@ConfigurationProperties(prefix = "minio")
@Data
public class MinioProperties {

    private String endpoint;

    private String accessKey;

    private String secretKey;
    
    private String bucketName;
}

common模块中创建com.atguigu.lease.common.minio.MinioConfiguration,内容如下

@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class MinioConfiguration {

    @Autowired
    private MinioProperties properties;

    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder().endpoint(properties.getEndpoint()).credentials(properties.getAccessKey(), properties.getSecretKey()).build();
    }
}
3.2、开发上传图片接口

编写Controller层逻辑

FileUploadController中增加如下内容

@Tag(name = "文件管理")
@RequestMapping("/admin/file")
@RestController
public class FileUploadController {

    @Autowired
    private FileService service;

    @Operation(summary = "上传文件")
    @PostMapping("upload")
    public Result<String> upload(@RequestParam MultipartFile file) {

        String url = service.upload(file);
        return Result.ok(url);
    }
}

说明:MultipartFile是Spring框架中用于处理文件上传的类,它包含了上传文件的信息(如文件名、文件内容等)。

编写Service层逻辑

FileService中增加如下接口

String upload(MultipartFile file);

FileServiceImpl中增加如下内容

@Autowired
private MinioProperties properties;

@Autowired
private MinioClient client;

@Override
public String upload(MultipartFile file) {

    try {
        boolean bucketExists = client.bucketExists(BucketExistsArgs.builder().bucket(properties.getBucketName()).build());
        if (!bucketExists) {
            client.makeBucket(MakeBucketArgs.builder().bucket(properties.getBucketName()).build());
            client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(properties.getBucketName()).config(createBucketPolicyConfig(properties.getBucketName())).build());
        }

        String filename = new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/" + UUID.randomUUID() + "-" + file.getOriginalFilename();
        client.putObject(PutObjectArgs.builder().
                bucket(properties.getBucketName()).
                object(filename).
                stream(file.getInputStream(), file.getSize(), -1).
                contentType(file.getContentType()).build());

        return String.join("/", properties.getEndpoint(), properties.getBucketName(), filename);

    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

private String createBucketPolicyConfig(String bucketName) {

    return """
            {
              "Statement" : [ {
                "Action" : "s3:GetObject",
                "Effect" : "Allow",
                "Principal" : "*",
                "Resource" : "arn:aws:s3:::%s/*"
              } ],
              "Version" : "2012-10-17"
            }
            """.formatted(bucketName);
}

由于公寓、房间的图片为公开信息,所以将其设置为所有人可访问。

4、异常处理

问题说明

上述代码只是对MinioClient方法抛出的各种异常进行了捕获,然后打印了异常信息,目前这种处理逻辑,无论Minio是否发生异常,前端在上传文件时,总是会受到成功的响应信息。可按照以下步骤进行操作,查看具体现象

关闭虚拟机中的Minio服务

systemctl stop minio

启动项目,并上传文件,观察接收的响应信息

问题解决思路

为保证前端能够接收到正常的错误提示信息,应该将Service方法的异常抛出到Controller方法中,然后在Controller方法中对异常进行捕获并处理。具体操作如下

Service层代码

@Override
public String upload(MultipartFile file) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException{

    boolean bucketExists = minioClient.bucketExists(
            BucketExistsArgs.builder()
                    .bucket(properties.getBucketName())
                    .build());
    if (!bucketExists) {
        minioClient.makeBucket(
                MakeBucketArgs.builder()
                        .bucket(properties.getBucketName())
                        .build());
        minioClient.setBucketPolicy(
                SetBucketPolicyArgs.builder()
                        .bucket(properties.getBucketName())
                        .config(createBucketPolicyConfig(properties.getBucketName()))
                        .build());
    }
    String filename = new SimpleDateFormat("yyyyMMdd").format(new Date()) +
            "/" + UUID.randomUUID() + "-" + file.getOriginalFilename();
    minioClient.putObject(
            PutObjectArgs.builder()
                    .bucket(properties.getBucketName())
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .object(filename)
                    .contentType(file.getContentType())
                    .build());

    return String.join("/",properties.getEndpoint(),properties.getBucketName(),filename);
}

Controller层代码

public Result<String> upload(@RequestParam MultipartFile file) {
    try {
        String url = service.upload(file);
        return Result.ok(url);
    } catch (Exception e) {
        e.printStackTrace();
        return Result.fail();
    }
}

全局异常处理

按照上述写法,所有的Controller层方法均需要增加try-catch逻辑,使用Spring MVC提供的全局异常处理功能,可以将所有处理异常的逻辑集中起来,进而统一处理所有异常,使代码更容易维护。

具体用法如下,详细信息可参考官方文档:

common模块中创建com.atguigu.lease.common.exception.GlobalExceptionHandler类,内容如下

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result error(Exception e){
        e.printStackTrace();
        return Result.fail();
    }
}

上述代码中的关键注解的作用如下

@ControllerAdvice用于声明处理全局Controller方法异常的类

@ExceptionHandler用于声明处理异常的方法,value属性用于声明该方法处理的异常类型

@ResponseBody表示将方法的返回值作为HTTP的响应体

注意:

全局异常处理功能由SpringMVC提供,因此需要在common模块pom.xml中引入如下依赖

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

修改Controller层代码

由于前文的GlobalExceptionHandler会处理所有Controller方法抛出的异常,因此Controller层就无序关注异常的处理逻辑了,因此Controller层代码可做出如下调整。

public Result<String> upload(@RequestParam MultipartFile file) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
    String url = service.upload(file);
  return Result.ok(url);
}

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

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

相关文章

【每日刷题】Day66

【每日刷题】Day66 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 小乐乐改数字_牛客题霸_牛客网 (nowcoder.com) 2. 牛牛的递增之旅_牛客题霸_牛客网 (nowcoder.com)…

算法体系-20 第二十节暴力递归到动态规划

前言 动态规划模型从尝试暴力递归到傻缓存到动态规划 四种模型和体系班两种模型一共六种模型 0.1 从左往右模型 0.2 范围讨论模型范围尝试模型 &#xff08;这种模型特别在乎讨论开头如何如何 结尾如何如何&#xff09; 玩家博弈问题&#xff0c;玩家玩纸牌只能那左或者右 0.3 …

Docker Jenkins(改错版本)

Devops:它强调开发(Development)和运维(Operations)团队之间的协作.实现更快,更可靠的软件交付部署. JenKins是一个开源的自动化服务器,广泛用于构建,测试和部署软件项目.它是持续集成(CI)和持续交付/部署(CD)的工具.JenKins是实现DevOps实践的重要工具. 前端项目部署一般流程:…

【javaEE-有关CPU进程和线程实现的并发编程及二者的区别】

&#x1f525;&#x1f525;&#x1f525;有关进程并发编程开发的成本问题 这次之前其实我们所有的写的程序都是使用单核心来运行的&#xff0c;但是一般我们的计算机都有很多核心&#xff0c;如果我们编程的时候&#xff0c;只使用一个核心的话&#xff0c;其实这是一个非常大…

通俗范畴论2 有向图与准范畴

退一步海阔天空&#xff0c;在正式进入范畴论之前&#xff0c;我们可以重新审视一下我们是如何认识世界的&#xff0c;有了这个对人类认识世界过程的底层理解&#xff0c;可以帮助我们更好地理解范畴论。 对于人类认识世界&#xff0c;最神奇的一点就是这个世界居然是可以认识…

【C语言】解决C语言报错:Race Condition

文章目录 简介什么是Race ConditionRace Condition的常见原因如何检测和调试Race Condition解决Race Condition的最佳实践详细实例解析示例1&#xff1a;缺乏适当的同步机制示例2&#xff1a;错误使用条件变量 进一步阅读和参考资料总结 简介 Race Condition&#xff08;竞争条…

element-ui input输入框和多行文字输入框字体不一样

页面中未作样式修改&#xff0c;但是在项目中使用element-ui input输入框和多行文字输入框字体不一样&#xff0c;如下图所示&#xff1a; 这是因为字体不一致引起的&#xff0c;如果想要为Element UI的输入框设置特定的字体&#xff0c;你可以在你的样式表中添加以下CSS代码…

尚品汇-(二)

本地域名解析器&#xff1a;当我们在浏览器输入域名的时候&#xff0c;它首先找的不是远程的DNS&#xff0c;而是去本地的host中去找这个域名有没有对应的&#xff0c;如果有对应的&#xff0c;那么就根据对应的ip进行访问 一&#xff1a;环境安装 1.安装JAVA 运行环境 第一…

MySQL之优化服务器设置(四)

优化服务器设置 InnoDB的IO配置 双写缓冲(Doublewrite Buffer) InnoDB用双写缓冲来避免页没写完整所导致的数据损坏。当一个磁盘写操作不能完整地完成时&#xff0c;不完整的页写入就可能发生&#xff0c;16KB的页可能只有一部分被写到磁盘上。有多种多样的原因(崩溃、Bug&am…

Obsidian 工作区Workspace:实现切换和管理工作区的多任务处理插件

工作区 工作区是Obsidian 的核心插件之一&#xff0c;旨在帮助用户更好地管理和组织他们的工作环境。 功能简介 工作区保存和切换&#xff1a;Workspace 插件允许用户保存当前的窗口布局和打开的笔记状态&#xff0c;用户可以随时切换到不同的工作区&#xff0c;这样可以根据…

Matlab|基于手肘法的kmeans聚类数的精确识别【K-means聚类】

主要内容 在电力系统调度研究过程中&#xff0c;由于全年涉及的风、光和负荷曲线较多&#xff0c;为了分析出典型场景&#xff0c;很多时候就用到聚类算法&#xff0c;而K-means聚类就是常用到聚类算法&#xff0c;但是对于K-means聚类算法&#xff0c;需要自行指定分类数&…

Google Earth Engine(GEE)——计算闪闪红星的ndvi的值和折线图(时序分析)

函数: ui.Chart.image.doySeries(imageCollection, region, regionReducer, scale, yearReducer, startDay, endDay)

中小学电子教材下载办法(202406最简单的)

官方版本 现在能阅读电子教材的官方网站挺多的&#xff0c;例如 人民教育出版社-电子教材&#xff0c;还有 国家中小学智慧教育平台 &#xff0c;其他还有很多可在阅读的网站。由于平台的原因不能直接贴链接&#xff0c;大家可以通过搜索关键词找到网站。 如何下载 据我所知…

idea搜索只显示100条、如何修改idea搜索的条数

文章目录 一、老版本的IDEA&#xff08;2021年之前的版本&#xff09;二、新版本的IDEA&#xff08;2021年及之后的版本&#xff09;2.1、方式一2.2、方式二 如下图&#xff1a;idea搜索的时候默认只显示100条 要解决IDEA搜索只显示100条的问题&#xff0c;可以通过修改搜索结…

【推荐】Perl入门教程特点功能文本处理读取文件替换文本写入文件分割字符数据库处理环境准备安装(包含示咧)

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

HashMap详解(含动画演示)

目录 HashMap1、HashMap的继承体系2、HashMap底层数据结构3、HashMap的构造函数①、无参构造②、有参构造1 和 有参构造2 (可以自定义初始容量和负载因子)③、有参构造3(接受一个Map参数)JDK 8之前版本的哈希方法&#xff1a;JDK 8版本的哈希方法 4、拉链法解决哈希冲突什么是拉…

监控室,屏幕显示不支持码流

1号屏&#xff0c;出现不支持码流 如下原因 老是录像机 无法关闭自动添加摄像头功能&#xff0c; 其他杂牌摄像头 会自动还ip 最终导致 ip冲突 更换ip 可以解决

Arnoldi Iteration 思考

文章目录 1. 投影平面2. Arnoldi Iteration3. python 代码 1. 投影平面 假设我们有一个向量q,我们需要关于向量q&#xff0c;构建一个投影平面P&#xff0c;使得给定任何向量v,可以通过公式 p P v pPv pPv&#xff0c;快速得到向量v在投影平面P上的投影向量p. 计算向量内积,…

部署LVS-DR群集...

目录 最后一台主机&#xff08;第四台&#xff09; 本地yum源安装httpd&#xff08;非必做&#xff09; 继续开始从最后一台主机开始&#xff08;第四台&#xff09; 转第二台主机 转第三台主机 回第二台 上传 转第三台主机 上传 回第二台 转第三台 转第一台主机…