欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > 【笔记】SpringBoot实现图片上传和获取图片接口

【笔记】SpringBoot实现图片上传和获取图片接口

2025/4/24 16:18:58 来源:https://blog.csdn.net/qq_26082507/article/details/147366905  浏览:    关键词:【笔记】SpringBoot实现图片上传和获取图片接口

上传图片接口

在这里插入图片描述
接口接收图片文件和布尔类型的是否生成缩略图参数。

  1. 生成保存图片文件的文件夹,文件夹的命名为上传图片的日期“根目录\file\cover\202504”,如果文件夹已存在则不生成。
  2. 接下来拼接文件名,生成30位的随机数拼接到原文件名防止文件名相同的情况,保存图片到目标目录。
  3. 通过第二个参数判断是否需要生成缩略图,如果需要则执行createThumbnail(String filePath)
    (下面会介绍这个函数)。
  4. 最后返回保存图片的文件路径。
@RequestMapping("/uploadImage")
public ResponseVO uploadImage(@NotNull MultipartFile file,@NotNull Boolean thumbnail) throws IOException, BusinessException {String month = DateUtils.format(new Date(), DateTimePatternEnum.YYYYMM.getPattern());// 根目录/file/cover/日期String folder = appConfig.getProjectFolder() + Constants.FILE_FOLDER + Constants.FILE_COVER + month;File folderFile = new File(folder);if(!folderFile.exists()){folderFile.mkdirs();}String fileName = file.getOriginalFilename();String fileSuffix = StringTools.getFileSuffix(fileName);String realFileName = StringTools.getRandomNumber(30) + fileSuffix;String filePath = folder + "/" + realFileName;file.transferTo(new File(filePath));if(thumbnail){fFmpegUtils.createThumbnail(filePath);}// cover/日期/realFileNamereturn getSuccessResponseVO(Constants.FILE_COVER + month + "/" + realFileName);
}

createThumbnail(String filePath) 负责拼接ffmpeg指令,把指令丢给 executeCommand(String cmd, Boolean showLog) 函数执行命令。

public void createThumbnail(String filePath) throws BusinessException {String CMD = "ffmpeg -i \"%s\" -vf scale=200:-1 \"%s\" ";CMD = String.format(CMD,filePath,filePath+ Constants.IMAGE_THUMBNAIL_SUFFIX);ProcessUtils.executeCommand(CMD,false);
}

executeCommand 函数传入指令是否打印日志这两个参数:

  1. 判断当前系统类型是Windows还是Linux,Windows:直接执行命令,Linux:用 sh -c 包装命令。
  2. 异步读取输出流和错误流,必须要取出ffmpeg在执行命令过程中产生的输出信息,如果不取的话当输出流信息填满jvm存储输出留信息的缓冲区时,线程就回阻塞住。
  3. 等待ffmpeg命令执行完,拼接输出的结果,如果需要打印日志则输出。
  4. 在finally里摧毁FFmpeg进程。
ublic class ProcessUtils {private static final Logger logger = LoggerFactory.getLogger(ProcessUtils.class);private static final String osName = System.getProperty("os.name").toLowerCase();public static String executeCommand(String cmd, Boolean showLog) throws BusinessException {if (StringTools.isEmpty(cmd)) {return null;}Runtime runtime = Runtime.getRuntime();Process process = null;try {//判断操作系统if (osName.contains("win")) {process = Runtime.getRuntime().exec(cmd);} else {process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", cmd});}// 取出输出流和错误流的信息PrintStream errorStream = new PrintStream(process.getErrorStream());PrintStream inputStream = new PrintStream(process.getInputStream());errorStream.start();inputStream.start();// 等待ffmpeg命令执行完process.waitFor();// 获取执行结果字符串String result = errorStream.stringBuffer.append(inputStream.stringBuffer + "\n").toString();// 输出执行的命令信息if (showLog) {logger.info("执行命令{}结果{}", cmd, result);}return result;} catch (Exception e) {logger.error("执行命令失败cmd{}失败:{} ", cmd, e.getMessage());throw new BusinessException("视频转换失败");} finally {if (null != process) {ProcessKiller ffmpegKiller = new ProcessKiller(process);runtime.addShutdownHook(ffmpegKiller);}}}/*** 在程序退出前结束已有的FFmpeg进程*/private static class ProcessKiller extends Thread {private Process process;public ProcessKiller(Process process) {this.process = process;}@Overridepublic void run() {this.process.destroy();}}/*** 用于取出ffmpeg线程执行过程中产生的各种输出和错误流的信息*/static class PrintStream extends Thread {InputStream inputStream = null;BufferedReader bufferedReader = null;StringBuffer stringBuffer = new StringBuffer();public PrintStream(InputStream inputStream) {this.inputStream = inputStream;}@Overridepublic void run() {try {if (null == inputStream) {return;}bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String line = null;while ((line = bufferedReader.readLine()) != null) {stringBuffer.append(line);}} catch (Exception e) {logger.error("读取输入流出错了!错误信息:" + e.getMessage());} finally {try {if (null != bufferedReader) {bufferedReader.close();}if (null != inputStream) {inputStream.close();}} catch (IOException e) {logger.error("调用PrintStream读取输出流后,关闭流时出错!");}}}}
}

运行结果

在这里插入图片描述
在这里插入图片描述

获取图片接口

传入图片路径参数。

  1. 判断路径是否为空或者路径格式不正确。
  2. 设置响应类型,设置缓存策略。
  3. 从本地磁盘中读取文件并写入到 response 输出流中。
  4. 关闭文件流和输出流。
@RequestMapping("/getResource")
public void getResource(HttpServletResponse response,@NotNull String sourceName) throws BusinessException, IOException {if(!StringTools.pathIsOk(sourceName)){throw new BusinessException(ResponseCodeEnum.CODE_600);}String suffix = StringTools.getFileSuffix(sourceName);response.setContentType("image/"+suffix.replace(".",""));response.setHeader("Cache-Control","max-age=2592000");readFile(response,sourceName);
}
// filePath = cover/23001/realFileName
protected void readFile(HttpServletResponse response,String filePath) throws IOException {// 根目录/file/cover/23001/realFileNameFile file = new File(appConfig.getProjectFolder() + Constants.FILE_FOLDER + filePath);if(!file.exists()){return;}try(OutputStream out = response.getOutputStream(); FileInputStream in = new FileInputStream(file)){byte[] byteData = new byte[1024];int len = 0;while ((len = in.read(byteData)) != -1) {out.write(byteData, 0, len);}out.flush();}catch (Exception e){log.error("读取文件异常",e);}
}

运行结果

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com