Spring boot 项目(九)——文件上传下载

前言

当我们开发一个项目的时候,总会有需要文件操作的模块,本篇就进行Spring boot的文件上传下载的编写

操作流程

1、引入依赖

        <!--文件上传下载依赖-->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

2、新建FileUtil类

@Slf4j
public class FileUtil {
    /**
     * 文件上传路径前缀
     */
    public static String filePrefix;
    /**
     * 本地磁盘目录
     */
    public static String uploadFile;

    /**
     * @Title: uploadFile
     * @Description: 单文件上传到本地磁盘
     * @param: multipartFile
     * @return: java.lang.String
     * @throws:
     */
    public static String uploadFile(MultipartFile multipartFile) {
        if (multipartFile == null) {
            return null;
        }

        //生成文件名称,以免上传相同文件异常
        String fileName = getUploadFileName(multipartFile.getOriginalFilename());
        log.info(multipartFile.getOriginalFilename());

        /**
         // 获取当前日期
         String dateDir = DateUtil.format(null, DateUtil.PATTERN_yyyyMMdd);
         // 如果是今天第一次上传,则生成日期文件夹
         File destFileDir = new File(uploadLocalPath + File.separator + dateDir);
         // 文件夹不存在时,创建文件夹
         if (!destFileDir.exists()) {
         destFileDir.mkdirs();
         }
         **/

        try {
            // 获取上传后文件对象
            File destFile = new File(FileUtil.uploadFile + File.separator + fileName);

            /**
             * destFileDir.getAbsoluteFile():当前项目与src文件夹的绝对地址一致
             **/

            // 上传文件到磁盘指定位置
            multipartFile.transferTo(destFile);

            log.info("文件【" + multipartFile.getOriginalFilename() + "】上传成功");

            return fileName;

        } catch (IOException e) {
            log.error("文件上传异常:" + multipartFile.getOriginalFilename(), e);
            return null;
        }
    }
    /**
     * @Title: getUploadFilePath
     * @Description: 获取上传后的文件相对路径  --数据库存储该路径
     * @param: fileName
     * @return: java.lang.String
     * @throws:
     */
    public static String getUploadFileName(String fileName) {
        //20210626093729817  +   _   +   HU5WMH  +   .jpg
        return new StringBuilder()
                .append(DateUtil.format(null, DateUtil.PATTERN_yyyyMMddHHmmssSSS))
                .append("_").append(getRandomStrByNum(6))
                .append(getExtension(fileName))
                .toString();
    }


    /**
     * 获取文件扩展名
     *
     * @param fileName
     * @return
     */
    public static String getExtension(String fileName) {
        if (StringUtils.isEmpty(fileName)) {
            return null;
        }
        return fileName.substring(fileName.lastIndexOf("."));
    }

    public static String CHAR_STR = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    /**
     * @Title: getRandomStrByNum
     * @Description: 获取不同位数的随机字符串
     * @Author: lxt
     * @param: factor
     * @return: java.lang.String
     * @throws:
     */
    public static String getRandomStrByNum(int factor) {
        // 拼接字符串
        StringBuilder sb = new StringBuilder();
        // java随机数对象
        Random random = new Random();
        for (int i = 0; i < factor; i++) {
            int index = random.nextInt(36);
            System.out.println("========>:" + index);
            char c = CHAR_STR.charAt(index);
            System.out.println("========>:" + c);
            sb.append(c);
        }
        return sb.toString();
    }

3、新建DateUtil类(当然,你可以选择不建这个类)


public class DateUtil {
    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(DateUtil.class);
    /**
     * date format yyyy-MM-dd HH:mm:ss
     */
    public static final String PATTERN_24_h = "yyyy-MM-dd HH:mm:ss";
    /**
     * date format PATTERN_yyyyMMddHHmmss
     */
    public static final String PATTERN_yyyyMMddHHmmss = "yyyyMMddHHmmss";
    /**
     * date format yyyyMMddHHmmssSSS
     */
    public static final String PATTERN_yyyyMMddHHmmssSSS = "yyyyMMddHHmmssSSS";
    /**
     * date format yyyyMMdd
     */
    public static final String PATTERN_yyyyMMdd = "yyyyMMdd";
    public static final String PATTERN_yyyy_MM_dd = "yyyy-MM-dd";
    public static final String PATTERN_hhmmss = "hh:mm:ss";
    /**
     * date format yyyyMMdd
     */
    public static final String PATTERN_MMDD = "MMDD";
    /**
     * 月索引获取对应季度(月份减1),第一个0,用于占位
     */
    public static final int [] QUARTERS = {0,1,1,1,2,2,2,3,3,3,4,4,4};

    /**
     * 枚举时间单位
     */
    enum TimeUnits{
        YEAR,MONTH,DAY,HOUR,MINUTES,SECOND
    }
    /**
     * LocalDateTime->Date
     * @param localDateTime
     * @return
     */
    public static Date local2Date(LocalDateTime localDateTime){
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    /**
     *LocalDate->Date
     * @param localDate
     * @return
     */
    public static Date local2Date(LocalDate localDate){
        return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }
    /**
     *LocalDate->Date
     * @param localTime
     * @return
     */
    public static Date local2Date(LocalTime localTime){
        return Date.from(LocalDateTime.of(LocalDate.now(), localTime).atZone(ZoneId.systemDefault()).toInstant());
    }
    /**
     *Date->LocalDate
     * @param date
     * @return
     */
    public static LocalDate date2LocalDate(Date date){
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).toLocalDate();
    }
    /**
     *Date->LocalDate
     * @param date
     * @return
     */
    public static LocalDateTime date2LocalDateTime(Date date){
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }
    /**
     *Date->LocalTime
     * @param date
     * @return
     */
    public static LocalTime date2LocalTime(Date date){
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).toLocalTime();
    }
    /**
     * @Title: plusDate
     * @Description: 根据偏移量(大于0后移,小于0前移)获取时间
     * @param: date 基准时间,null为当前时间
     * @param: chronoUnit 单位
     * @param: count 数值
     * @return: java.time.LocalDateTime
     * @throws:
     */
    public static LocalDateTime plusDate(LocalDateTime localDateTime, ChronoUnit chronoUnit, int count){
        //默认取当前时间
        localDateTime = localDateTime == null ? LocalDateTime.now() : localDateTime;
        switch (chronoUnit){
            case YEARS:
                return localDateTime.plusYears(count);
            case MONTHS:
                return localDateTime.plusMonths(count);
            case DAYS:
                return localDateTime.plusDays(count);
            case HOURS:
                return localDateTime.plusHours(count);
            case MINUTES:
                return localDateTime.plusMinutes(count);
            case SECONDS:
                return localDateTime.plusSeconds(count);
            case NANOS:
                return localDateTime.plusNanos(count);
            default:
                return localDateTime.plusYears(count);
        }
    }
    
    /**
     * 获取某季度第一天
     * @param quarter eg:1、2、3、4季度
     * @return
     *  成功:返回正确的日期
     *  失败:返回null
     */
    public static LocalDate getQuarterOfFirstDay(int quarter){
        switch (quarter){
            case 1:
                return LocalDate.of(LocalDate.now().getYear(),1,1);
            case 2:
                return LocalDate.of(LocalDate.now().getYear(),4,1);
            case 3:
                return LocalDate.of(LocalDate.now().getYear(),7,1);
            case 4:
                return LocalDate.of(LocalDate.now().getYear(),10,1);
            default:
                return null;
        }
    }
    /**
     *获取某季度最后一天
     * @param quarter:1、2、3、4季度
     * @return
     *  成功:返回正确的日期
     *  失败:返回null
     */
    public static LocalDate getQuarterOfLastDay(int quarter){
        switch (quarter){
            case 1:
                return LocalDate.of(LocalDate.now().getYear(),3,1).with(TemporalAdjusters.lastDayOfMonth());
            case 2:
                return LocalDate.of(LocalDate.now().getYear(),6,1).with(TemporalAdjusters.lastDayOfMonth());
            case 3:
                return LocalDate.of(LocalDate.now().getYear(),9,1).with(TemporalAdjusters.lastDayOfMonth());
            case 4:
                return LocalDate.of(LocalDate.now().getYear(),12,1).with(TemporalAdjusters.lastDayOfMonth());
            default:
                return null;
        }
    }
    /**
     * 格式化时间
     * @param localDateTime
     * @param pattern 格式
     * @return
     */
    public static String format(LocalDateTime localDateTime, String pattern){
        //默认取当前时间
        localDateTime = localDateTime == null ? LocalDateTime.now() : localDateTime;
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }
    /**
     * @Title: getCurrentTime
     * @Description: 获取当前时间
     * @param: pattern
     * @return: java.lang.String
     * @throws: 
     */
    public static String getCurrentTime(String pattern){
        return format(null,pattern);
    }
    /**
     * 获取日期时间差endDate-startDate
     * @param startDate
     * @param endDate
     * @return
     * startDate before 0f  endDate =>正数
     * startDate after 0f  endDate =>负数
     */
    public static long bewteenTwoDays(LocalDate startDate, LocalDate endDate){
        return ChronoUnit.DAYS.between(startDate, endDate);
    }
    /**
     * 获取时间差endDateTime-startDateTime
     * @param startDateTime
     * @param endDateTime
     * @param chronoUnit ChronoUnit枚举类型
     * @return
     * startDateTime before 0f  endDateTime =>正数
     * startDateTime after 0f  endDateTime =>负数
     */
    public static long bewteenTwoTimes(LocalDateTime startDateTime, LocalDateTime endDateTime, ChronoUnit chronoUnit){
        switch (chronoUnit){
            case YEARS:
                return ChronoUnit.YEARS.between(startDateTime, endDateTime);
            case MONTHS:
                return ChronoUnit.MONTHS.between(startDateTime, endDateTime);
            case DAYS:
                return ChronoUnit.DAYS.between(startDateTime, endDateTime);
            case HOURS:
                return ChronoUnit.HOURS.between(startDateTime, endDateTime);
            case MINUTES:
                return ChronoUnit.MINUTES.between(startDateTime, endDateTime);
            case SECONDS:
                return ChronoUnit.SECONDS.between(startDateTime, endDateTime);
            case NANOS:
                return ChronoUnit.NANOS.between(startDateTime, endDateTime);
            default:
                return 0;
        }
    }
    
    /**
     * 
    * @Title: differentDays
    * @Description: TODO date2比date1多的天数
    * @param @param date1
    * @param @param date2
    * @param @return   
    * @return int    
    * @throws
     */
    public static int differentDays(Date date1, Date date2)
    {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);
        
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);
       int day1= cal1.get(Calendar.DAY_OF_YEAR);
        int day2 = cal2.get(Calendar.DAY_OF_YEAR);
        
        int year1 = cal1.get(Calendar.YEAR);
        int year2 = cal2.get(Calendar.YEAR);
        if(year1 != year2)   //同一年
        {
            int timeDistance = 0 ;
            for(int i = year1 ; i < year2 ; i ++)
            {
                if(i%4==0 && i%100!=0 || i%400==0)    //闰年            
                {
                    timeDistance += 366;
                }
                else    //不是闰年
                {
                    timeDistance += 365;
                }
            }
            
            return timeDistance + (day2-day1) ;
        }
        else    //不同年
        {
//            System.out.println("判断day2 - day1 : " + (day2-day1));
            return day2-day1;
        }
    }
}

4、在WebMvcConfig类中添加如下代码

    /**
     * 文件上传路径前缀
     */
    @Value("${application.filePrefix}")
    public String filePrefix;
    /**
     * 本地磁盘目录
     */
    @Value("${application.uploadFile}")
    public String uploadFile;

    /**
     * @Title: addResourceHandlers
     * @Description:  映射本地磁盘为静态目录
     * @param: registry
     * @throws:
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry){
        FileUtil.filePrefix = filePrefix;
        FileUtil.uploadFile = uploadFile;

        registry.addResourceHandler(filePrefix +"/**")
                .addResourceLocations("file:"+uploadFile);
    }

5、配置yml文件

spring:
  # 文件上传下载相关配置
  servlet:
    multipart:
      enabled: true
      max-file-size: 20MB
      max-request-size: 20MB
application:
  #文件上传前缀
  filePrefix: /
  #文件上传路径
  uploadFile: C:/Users/14193/Desktop/待办事项/Spring boot文件操作/

在这里插入图片描述
6、编码controller文件

@Slf4j
@RestController
@RequestMapping("file")
public class FileController {

    @Resource
    private FileService fileService;
    @Resource
    private HttpServletRequest request;
    @Resource
    private SysUserService sysUserService;
    /**
     * 上传文件
     *
     * @param file
     * @return
     */
    @ResponseBody
    @RequestMapping("upload")
    public ResultJson upload(@RequestParam("file") MultipartFile file) throws Exception {
        if (file == null) {
            return ResultJson.error("文件上传失败");
        }
        Map<String, String> r = new HashMap<>();
        // 调用上传方法返回可访问的路径
        String filePath = FileUtil.uploadFile(file);
        // 上传后的路径
        r.put("filePath", filePath);
        // 文件原名
        r.put("fileName", file.getOriginalFilename());
        // 文件大小
        r.put("fileSize", file.getSize() + "");

		/**
        * 相应的数据入数据库
        **/
        FileOperation uploadFile = new FileOperation();
        uploadFile.setFileName(file.getOriginalFilename());
        uploadFile.setUploadTime(LocalDateTime.now());
        String token =request.getHeader("token");
        Long uid = Long.valueOf(JwtUtil.getAudience(token));
        uploadFile.setUserId(uid);
        uploadFile.setFilePath(filePath);
        fileService.save(uploadFile);
        SysUser user=new SysUser();
        user.setId(uid);
        user.setPhoto(filePath);
        sysUserService.saveOrUpdate(user);


        return ResultJson.ok("文件上传成功", r);
    }
    @NoNeedToken
    @ResponseBody
    @RequestMapping("downloadByFilePath")
    public ResponseEntity<byte[]> download(String filePath) throws IOException {
        if (StringUtils.isEmpty(filePath)) {
            throw new RuntimeException("路径不可为空!");
        }
        /**
         * 获取磁盘路径
         */
        // 磁盘根路径 + 相对路径  获取绝对路径
        String localPath = FileUtil.uploadFile + filePath;
        log.info("**********----------"+localPath);
        File file = new File(localPath);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentDispositionFormData("attachment",
                new String(file.getName().getBytes(StandardCharsets.UTF_8), "iso-8859-1"));
        headers.add("Access-Control-Expose-Headers", "Content-Disposition");
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        // 获取文件的字节数组 - 需要使用commons-io依赖包
        byte[] content = FileUtils.readFileToByteArray(file);
        // 返回下载的二进制内容
        return new ResponseEntity<>(content, headers, HttpStatus.OK);
    }
}

测试

上传:
在这里插入图片描述
在这里插入图片描述
下载:
在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

--流星。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值