JavaWeb合集23-文件上传

二十三 、 文件上传

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

1、前端实现

vue3+AntDesignVue实现

html 复制代码
<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>

请求函数

ts 复制代码
// 后面的方法是用户自己头像
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、后端实现

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

java 复制代码
/**
 * 配置拦截器的静态资源映射
 */
@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中,方便生成访问链接

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\)可根据自己需求进行修改,在工具类中

java 复制代码
/**
 * 文件上传工具类
 */
@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;
    }
}

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

java 复制代码
public class FileUploadFolder {
    public static final String USER_AVATER_FOLDER = "user_avatar";
    public static final String  ACTIVITY_FOLDER = "activity";
}

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

java 复制代码
@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层:根据自己的项目来即可

java 复制代码
@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、测试与效果

上传后的图片

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

相关推荐
zjw_rp11 分钟前
Spring-AOP
java·后端·spring·spring-aop
Oneforlove_twoforjob24 分钟前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
TodoCoder32 分钟前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
向宇it41 分钟前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行43 分钟前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
星河梦瑾2 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富2 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想2 小时前
JMeter 使用详解
java·jmeter
言、雲2 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇2 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表