JavaWeb合集23-文件上传

二十三 、 文件上传

实现效果:用户点击上传按钮、选择上传的头像,确定自动上传,将上传的文件保存到指定的目录中,并重新命名,生成访问链接,返回给前端进行回显。

1、前端实现

vue3+AntDesignVue实现

<template>
       <!--图片回显-->
          <a-avatar :size="100">
            <template #icon>
              <img :src="userStore.userInfo.avatar+'?' + new Date().getTime()" alt="">
            </template>
          </a-avatar>
          <!--图片上传按钮 -->
           <!--showUploadList=fales 不显示上传列表;:multiple="false" 只上传1个;accept=".png,.jpg" 限制文件格式-->
          <a-upload 
           name="file"
          :file-list="fileList"
          :showUploadList="false"
          :beforeUpload="beforeUpload" 
          :onChange="handleChange" 
          :multiple="false"  
          accept=".png,.jpg"
           >
            <a-button class="mt-4">
               上传头像
            </a-button>
          </a-upload>

</template>

<script setup lang="ts">
import type { UnwrapRef } from 'vue';
import { updateUserAvatarApi } from '~/api/file/file.ts';


const { t } = useI18n()
//文件列表
const fileList = ref([]);

//
async function beforeUpload(file){
 //文件类型,限制,可以不用写,因为,在accept=".png,.jpg" 已经限制了
var fileName = file.name.substring(file.name.lastIndexOf('.') + 1)
if (fileName!='png' && fileName!='jpg') {
  message.error('文件类型必须是png或jpg!')
return false
}

//文件大小(3M=3*1024KB*1024字节)
var fileSize=file.size;
if(fileSize > 3*1024*1024){
 message.error("图片大小不能大于3M");
 return false
}

try {  
    const formData = new FormData(); 
     formData.append('file', file); // 将文件添加到 FormData 对象中  
    // 假设updateUserAvatarApi返回的是一个Promise,且解析为包含fileUrl的对象  
    const response = await updateUserAvatarApi(formData);  
    if(response.data.code==1){
      fileList.value=[];  //清空文件列表(没用因为在beforeUpload中,我直接showUploadList="false"不显示列表)
      userStore.userInfo.avatar=response.data.data;
      
     message.success('头像上传成功');
    
    }else{
      message.error('头像上传失败,请重试');  
    }
     
  } catch (error) {  
    // 处理上传失败的情况  
    message.error(error);  
  }  
  // 返回false以阻止<a-upload>的默认上传行为  
  return false;  

}

// 处理文件上传或移除后的逻辑  
function handleChange(info) {  
  // info.fileList 是更新后的文件列表  
  // 但由于限制了multiple为false,所以这里fileList应该始终只有一个文件或为空  
  fileList.value = info.fileList.slice(-1);  
}  

</script>

请求函数

// 后面的方法是用户自己头像
export function updateUserAvatarApi(param: any) {
    return usePost<FileUrl>('/upload/uploadUserAvater', param, {
      // 设置为false的时候不会携带token
      token: true,
      // 开发模式下使用自定义的接口
      customDev: true,
      // 是否开启全局请求loading
      loading: false,
      // 设置请求头
    headers: {
      'Content-Type': 'multipart/form-data'
    }
    })
  }

  export interface FileUrl {
    data: string
  }

2、后端实现

配置拦截器的静态资源映射,方便对上传后的文件进行访问

/**
 * 配置拦截器的静态资源映射
 */
@Slf4j
@Configuration
public class ResourConfigure implements WebMvcConfigurer {
   
     // 静态资源映射
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        /**
         * 资源映射路径
         * addResourceHandler:访问映射路径
         * addResourceLocations:资源绝对路径
         */
        String osName=System.getProperty("os.name");
        String fileUploadResources="/static/**";
        String win="win";
        if(osName.toLowerCase().startsWith(win)){
            ApplicationHome applicationHome=new ApplicationHome(this.getClass());
            String pre="file:"+applicationHome.getDir().getParentFile().getParentFile()+ "\\src\\main\\resources\\static\\";

            registry.addResourceHandler(fileUploadResources)
                    .addResourceLocations(pre);
        }else {
            ApplicationHome applicationHome=new ApplicationHome(this.getClass());
            String pre="file:"+applicationHome.getDir().getParentFile().getParentFile()+ "/src/main/resources/static/";
            registry.addResourceHandler(fileUploadResources)
                    .addResourceLocations(pre);
        }
    }

}

写相关配置,在application.properties中,方便生成访问链接

#根据自己的需求进行修改即可
#端口号
server.port=8080   
#服务地址
server.address=localhost  
#访问路径
server.servlet.context-path=/    
#限制单个文件的上传大小
spring.servlet.multipart.max-file-size=5MB
#限制整个请求的最大大小
spring.servlet.multipart.max-request-size=5MB

创建文件上传工具类,方便对文件上传进行操作。

在此之前,确保这个目录的存在:(\src\main\resources\static\)可根据自己需求进行修改,在工具类中

/**
 * 文件上传工具类
 */
@Component
public class FileUpload {

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Value("${server.port}")
    private String serverPort;

    @Value("${server.address}")
    private String serverAddress;

    @Autowired
    private ServletContext servletContext;


    public String uploadFile(MultipartFile file, String folder) {
        // 获取图片的原始名字
        String originalFilename = file.getOriginalFilename();

        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        // 获取文件的后缀和新文件名
        String ext = "." + originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String fileName = uuid + ext;

        // 构建目标文件路径
        String pre = getResourcePath(folder);
        String filePath = pre + fileName;


        // 上传图片
        try {
            file.transferTo(new File(filePath));
            // 返回访问链接
            return getAccessPath(folder, fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    public String uploadFile(MultipartFile file, String folder, String fileName) {
        // 获取图片的原始名字
        String originalFilename = file.getOriginalFilename();

        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        // 获取文件的后缀和新文件名
        String ext = "." + originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
        fileName = fileName + ext;

        // 构建目标文件路径
        String pre = getResourcePath(folder);
        String filePath = pre + fileName;

        // 上传图片
        try {
            file.transferTo(new File(filePath));
            // 返回访问链接
            return getAccessPath(folder, fileName);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
    
    //获取上传路径
    private String getResourcePath(String folder) {
        // 获取操作系统的名称
        String osName = System.getProperty("os.name");
        String win = "win";

        // 获取项目的根目录
        String projectRoot = System.getProperty("user.dir");

        // 根据操作系统生成正确的路径
        String staticPath;
        if (osName.toLowerCase().startsWith(win)) {
            //windos系统
            staticPath = projectRoot + "\\src\\main\\resources\\static\\" + folder + "\\";
        } else {
            //Linux系统
            staticPath = projectRoot + "/src/main/resources/static/" + folder + "/";
        }


        // 如果目录不存在,就创建目录
        File dir = new File(staticPath);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        return staticPath;
    }

    //构建访问路径
    private String getAccessPath(String folder, String fileName) {
        // 构建访问路径
        return "http://" + serverAddress + ":" + serverPort + contextPath + "static/" + folder + "/" + fileName;
    }
}

可以设置一个常量类,来指定上传到的目录

public class FileUploadFolder {
    public static final String USER_AVATER_FOLDER = "user_avatar";
    public static final String  ACTIVITY_FOLDER = "activity";
}

后端接口编写:Controller层,根据自己的项目来即可

@Tag(name="文件上传接口")
@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {

    @Autowired
    private UserService userService;


    /**
     * 修改用户头像
     * @param file
     * @return
     */
    @Operation(summary = "修改用户头像")
    @PostMapping("/uploadUserAvater")
    public ResponseResult uploadUserAvater(@RequestParam("file") MultipartFile file){
        if(file.isEmpty()){
            return ResponseResult.error("头像为空,请重新选择");
        }
        String imgUrl = userService.uploadUserAvater(file);
        if(imgUrl==null){
            return ResponseResult.error("头像上传失败");
        }
        return ResponseResult.success(imgUrl);
    }

}

Service层:根据自己的项目来即可

@Slf4j
@Service
@Transactional
public class UserServiceImpl implements UserService {
    //根据自己的项目来,注入对应的Bean
    @Autowired
    private final UserMapper userMapper;

     //注入写好的工具类
    @Autowired
    private FileUpload fileUpload;

    /**
     * 修改用户头像
     * @param file
     * @return
     */
    @Override
    public String uploadUserAvater(MultipartFile file) {
        // 获取用户获取用户信息(根据自己的项目来,获取用户ID,来查询用户修改头像链接)
        Long uid = Long.parseLong(StpUtil.getLoginId().toString());
        UserInfo userInfo = userMapper.getUserById(uid);
        // 调用文件上传工具类,传入:文件,保存到的文件夹,文件名
        //设置文件名是为了替换旧的头像文件
            String imgUrl= fileUpload.uploadFile(file, FileUploadFolder.USER_AVATER_FOLDER,userInfo.getUsername());
            if(imgUrl!=null) {
                userInfo.setAvatar(imgUrl);
                userMapper.updateById(userInfo);
                log.info("头像上传成功:" + imgUrl);
                //返回生成的链接
                return imgUrl;
            }
      return null;
    }
    
}

3、测试与效果

上传后的图片

在这里插入图片描述

生成的访问链接,存入到数据库的样子

在这里插入图片描述

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

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

相关文章

设计模式-七个基本原则之一-开闭原则 + SpringBoot案例

开闭原则:(SRP) 面向对象七个基本原则之一 对扩展开放&#xff1a;软件实体&#xff08;类、模块、函数等&#xff09;应该能够通过增加新功能来进行扩展。对修改关闭&#xff1a;一旦软件实体被开发完成&#xff0c;就不应该修改它的源代码。 要看实际场景&#xff0c;比如组内…

图形几何之美系列:仿射变换矩阵(二)

“ 在几何计算、图形渲染、动画、游戏开发等领域&#xff0c;常需要进行元素的平移、旋转、缩放等操作&#xff0c;一种广泛应用且简便的方法是使用仿射变换进行处理。相关的概念还有欧拉角、四元数等&#xff0c;四元数在图形学中主要用于解决旋转问题&#xff0c;特别是在三维…

python识别ocr 图片和pdf文件

#识别图片 pip3 install paddleocr pip3 install paddlepaddle#识别pdf pip3 install PyMuPDF 重点&#xff1a;路径不能有中文&#xff0c;不然pdf文件访问不了 from paddleocr import PaddleOCR from rest_framework.response import Response from rest_framework.views im…

使用Ubuntu快速部署MinIO对象存储

想拥有自己的私有云存储&#xff0c;安全可靠又高效&#xff1f;MinIO是你的理想选择&#xff01;这篇文章将手把手教你如何在Ubuntu 22.04服务器上部署MinIO&#xff0c;并使用Nginx反向代理和Let’s Encrypt证书进行安全加固。 即使你是新手&#xff0c;也能轻松完成&#xf…

EasyUI弹出框行编辑,通过下拉框实现内容联动

EasyUI弹出框行编辑&#xff0c;通过下拉框实现内容联动 需求 实现用户支付方式配置&#xff0c;当弹出框加载出来的时候&#xff0c;显示用户现有的支付方式&#xff0c;datagrid的第一列为conbobox,下来选择之后实现后面的数据直接填充&#xff1b; 点击新增&#xff1a;新…

【神经科学学习笔记】基于分层嵌套谱分割(Nested Spectral Partition)模型分析大脑网络整合与分离的学习总结

一、前言 1.学习背景 最近在学习脑网络分析方法时&#xff0c;笔者偶然读到了一篇发表在Physical Review Letters上的文章&#xff0c;文章介绍了一种名为嵌套谱分割(Nested-Spectral Partition, NSP)的方法&#xff0c;用于研究大脑功能网络的分离和整合特性。 传统的脑网络分…

如何优雅处理异常?处理异常的原则

前言 在我们日常工作中&#xff0c;经常会遇到一些异常&#xff0c;比如&#xff1a;NullPointerException、NumberFormatException、ClassCastException等等。 那么问题来了&#xff0c;我们该如何处理异常&#xff0c;让代码变得更优雅呢&#xff1f; 1 不要忽略异常 不知…

海量数据迁移:Elasticsearch到OpenSearch的无缝迁移策略与实践

文章目录 一&#xff0e;迁移背景二&#xff0e;迁移分析三&#xff0e;方案制定3.1 使用工具迁移3.2 脚本迁移 四&#xff0e;方案建议 一&#xff0e;迁移背景 目前有两个es集群&#xff0c;版本为5.2.2和7.16.0&#xff0c;总数据量为700T。迁移过程需要不停服务迁移&#…

macOS开发环境配置与应用开发(详细讲解)

&#x1f4dd;个人主页&#x1f339;&#xff1a;一ge科研小菜鸡-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 1. 引言 macOS作为Apple公司推出的桌面操作系统&#xff0c;以其稳定性、优雅的用户界面和强大的开发工具吸引了大量开发者。对于…

【深度学习滑坡制图|论文解读3】基于融合CNN-Transformer网络和深度迁移学习的遥感影像滑坡制图方法

【深度学习滑坡制图|论文解读3】基于融合CNN-Transformer网络和深度迁移学习的遥感影像滑坡制图方法 【深度学习滑坡制图|论文解读3】基于融合CNN-Transformer网络和深度迁移学习的遥感影像滑坡制图方法 文章目录 【深度学习滑坡制图|论文解读3】基于融合CNN-Transformer网络和…

前端学习之ES6+

1.ES6是什么 ES6&#xff0c;全称是ECMAScript 6&#xff0c;是JavaScript语言的下一代标准&#xff0c;由ECMA国际组织在2015年6月正式发布。ES6也被称作ECMAScript 2015&#xff0c;从这个版本开始&#xff0c;ECMA组织决定每年发布一个新的ECMAScript版本&#xff0c;以使J…

查缺补漏----用户上网过程(HTTP,DNS与ARP)

&#xff08;1&#xff09;HTTP 来自湖科大计算机网络微课堂&#xff1a; ① HTTP/1.0采用非持续连接方式。在该方式下&#xff0c;每次浏览器要请求一个文件都要与服务器建立TCP连接当收到响应后就立即关闭连接。 每请求一个文档就要有两倍的RTT的开销。若一个网页上有很多引…

【广西】《广西壮族自治区本级政务信息化建设和运维项目预算支出标准》(桂财建〔2023〕102号)-省市费用标准解读系列09

《广西壮族自治区本级政务信息化建设和运维项目预算支出标准》&#xff08;桂财建〔2023〕102号&#xff09;是广西壮族自治区财政厅于2023年9月26日发布的费用标准&#xff08;了解更多可直接关注我们咨询&#xff09;。我司基于专业第三方信息化项目造价机构角度&#xff0c;…

Linux基础-常用操作命令详讲

Linux基础-常用操作命令详讲 一、openssl加密简单介绍 1. 生成加密的密码散列&#xff08;password hash&#xff09;​编辑 1.1 常见的选项总结表 1.2 加密参数详解 2. 自签名证书 3. 证书转换 二、文件管理 1. 创建空文件 ​编辑 2. 删除文件 4. 新建目录 ​编辑…

ALB搭建

ALB: 多级分发、消除单点故障提升应用系统的可用性&#xff08;健康检查&#xff09;。 海量微服务间的高效API通信。 自带DDoS防护&#xff0c;集成Web应用防火墙 配置&#xff1a; 1.创建ECS实例 2.搭建应用 此处安装的LNMP 3.创建应用型负载均衡ALB实例 需要创建服务关联角…

C语言笔记(字符串函数,字符函数,内存函数)

目录 前言 1.字符串函数 1.1.strlen 1.2.strcpy 1.3.strcat 1.4.strcmp 1.5.strncpy 1.6.strncat 1.7.strncmp 1.8.strstr 1.9.strtok 1.10.strerror 2.字符函数 2.1字符分类函数 2.2字符转换函数 3.内存函数 3.1.mencpy 3.2.memmove 3.3.memcmp 前言 本文重…

HCIP-HarmonyOS Application Developer V1.0 笔记(五)

弹窗功能 prompt模块来调用系统弹窗API进行弹窗制作。 当前支持3种弹窗API&#xff0c;分别为&#xff1a; 文本弹窗&#xff0c;prompt.showToast&#xff1b;对话框&#xff0c;prompt.showDialog&#xff1b;操作菜单&#xff0c;prompt.showActionMenu。 要使用弹窗功能&…

Linux相关概念和易错知识点(20)(dentry、分区、挂载)

目录 1.dentry &#xff08;1&#xff09;路径缓存的原因 &#xff08;2&#xff09;dentry的结构 ①多叉树结构 ②file和dentry之间的联系 ③路径概念存在的意义 2.分区 &#xff08;1&#xff09;为什么要确认分区 &#xff08;2&#xff09;挂载 ①进入分区 ②被挂…

Redis 缓存击穿

目录 缓存击穿 什么是缓存击穿&#xff1f; 有哪些解决办法&#xff1f; 缓存穿透和缓存击穿有什么区别&#xff1f; 缓存雪崩 什么是缓存雪崩&#xff1f; 有哪些解决办法&#xff1f; 缓存预热如何实现&#xff1f; 缓存雪崩和缓存击穿有什么区别&#xff1f; 如何保…

电信网关配置管理系统 upload_channels.php 文件上传致RCE漏洞复现

0x01 产品简介 中国电信集团有限公司(英文名称“China Telecom”、简称“中国电信”)成立于2000年9月,是中国特大型国有通信企业、上海世博会全球合作伙伴。电信网关配置管理系统是一个用于管理和配置电信网络中网关设备的软件系统。它可以帮助网络管理员实现对网关设备的远…