SpringBoot 文件、视频、音频、图片公用接口

本文介绍了一种在Spring Boot项目中读取配置文件并实现文件上传的方法。包括配置文件监听器的设计,配置文件读取工具类的实现,以及如何在启动类中加载配置文件。同时,详细阐述了文件上传工具类的使用,以及如何在Controller中调用文件上传方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注意:该项目中涉及到读取配置文件

  • 一、读取配置文件
    • 1、配置文件监听器
package com.**.productcenter.config;

import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;

/**
 * 配置文件加载监听器
 * @author Zyred
 */
public class PropertiesListener implements  ApplicationListener<ApplicationStartedEvent> {

    /**
     * 配置项名称  key
     */
    private String propertyFileName;

    /**
     * 构造器
     * @param name
     */
    public PropertiesListener(String name) {
        this.propertyFileName = name;
    }

    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
        PropertiesListenerConfig.loadAllProperties(propertyFileName);
    }
}
  •  2、配置文件读取
package com.**.productcenter.config;

import org.springframework.beans.BeansException;
import org.springframework.core.io.support.PropertiesLoaderUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 读取配置文件
 * @author Zyred
 */
public class PropertiesListenerConfig {

    /**
     * 定义属性集合
     */
    public static Map propertiesMap = new HashMap();

    /**
     * 加载配置文件
     * @param props
     * @throws BeansException
     */
    private static void processProperties(Properties props) throws BeansException {
        propertiesMap = new HashMap<String, String>();
        for (Object key : props.keySet()) {
            String keyStr = key.toString();
            try {
                // PropertiesLoaderUtils的默认编码是ISO-8859-1,在这里转码一下
                propertiesMap.put(keyStr, new String(
                        props.getProperty(keyStr).getBytes("ISO-8859-1"), "utf-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (java.lang.Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 加载配置文件
     * @param propertyFileName
     */
    public static void loadAllProperties(String propertyFileName) {
        try {
            Properties properties = PropertiesLoaderUtils.loadAllProperties(propertyFileName);
            processProperties(properties);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据属性获取配置项
     * @param name
     * @return
     */
    public static String getProperty(String name) {
        return propertiesMap.get(name) + "";
    }

    /**
     * 获取所有配置项
     * @return
     */
    public static Map<String, String> getAllProperty() {
        return propertiesMap;
    }

}
  •  3、修改启动类
package com.**.productcenter;

import com.kedi.productcenter.config.PropertiesListener;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;


/**
* 方法实现说明   商品中心 启动类
* @author      ytw
* @param
* @return      
* @exception
* @update Zyred  修改启动项,加载读取配置文件的方法
* @date        2019/7/22 16:17
*/
@ComponentScan("com.kedi")
@EnableEurekaClient
@SpringBootApplication
public class ProductCenter {
    public static void main( String[] args ) {
        SpringApplication application = new SpringApplication(ProductCenter.class);
        application.addListeners(new PropertiesListener("file.properties"));
        application.run(args);
    }
}
  • 二、文件上传
    • 书写工具类
package com.**.productcenter.utils;


import com.kedi.productcenter.config.PropertiesListenerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.UUID;

/**
 * 文件上传方法, 该类可以传 视频, 文件, 音频, 图片
 * @author Zyred
 */
public class FileUploadUtil {

    Logger logger = LoggerFactory.getLogger(FileUploadUtil.class);

    private String type;

    private MultipartFile file;

    private String savePath;

    /**
     * 文件访问地址
     */
    private String resultPath;

    /**
     * 根据类型读取配置文件构造器
     * @param type  properties文件key
     * @param file  文件
     */
    public FileUploadUtil(String type, MultipartFile file){
        this.file = file;
        this.type = type;
    }

    /**
     * 根据保存路径构造器
     * @param file   文件
     * @param savePath  保存路径如: C:\\upload
     */
    public FileUploadUtil(MultipartFile file, String savePath){
        this.file = file;
        this.savePath = savePath;
    }

    /**
     * 上传文件方法
     * @return
     */
    public String uploadFile(){

        logger.info("上传文件类型:" + type);

        String save_path = null;
        InputStream is = null;
        FileOutputStream os = null;

        //判断文件不为空
        if (file == null && file.isEmpty()) {
            return "上传的文件为空";
        }

        if(type != null && !type.isEmpty()){
            //通过key获取到存储的路径
            save_path = PropertiesListenerConfig.getProperty(type);
        }

        if(save_path == null){
            save_path = savePath;
        }

        //获取到文件的名字
        String oldFileName = file.getOriginalFilename();
        logger.info("上传文件名称:" + oldFileName);
        String oldFileNameSufix = oldFileName.substring(oldFileName.lastIndexOf("."), oldFileName.length());

        //得到文件的新名字
        String newFileName = UUID.randomUUID().toString() + oldFileNameSufix;
        logger.info("上传文件新名称:" + newFileName);

        //保存后的文件路径
        String affterPath = save_path + newFileName;
        logger.info("文件保存位置:" + affterPath);

        //创建文件对象
        File dest = new File(affterPath);
        //文件或目录是否存在
        if (dest.exists()) {
            dest.mkdir();
        }

        //判断文件父目录是否存在
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdir();
        }
        //保存文件
        try {
            //获取输入流
            is = file.getInputStream();
            //创建输出流
            os = new FileOutputStream(dest);
            int len = 0;
            byte[] buffer = new byte[2048*512];
            //往输出流中写入字节流
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }

            InetAddress localHost = InetAddress.getLocalHost();
            //请求前缀  http://  https://
            String prefix = PropertiesListenerConfig.getProperty("file.download.path.prefix");
            //java项目请求路径 如:/image/download/file
            String middle = PropertiesListenerConfig.getProperty("file.download.path.middle");
            resultPath = prefix + localHost.getHostAddress() + middle + newFileName;
            logger.info("文件下载地址:" + resultPath);
        } catch (IOException e) {
            e.printStackTrace();
            return "服务器异常,请稍后重试";
        }finally {
            try{
                if(os != null || os != null){
                    os.close();
                    os.flush();
                    is.close();
                }
            }catch (IOException e){
                e.printStackTrace();
                return "流关闭异常";
            }
        }
        return resultPath;
    }
}
  • 2、controller方法
package com.**.productcenter.controller;

import com.kedi.productcenter.config.PropertiesListenerConfig;
import com.kedi.productcenter.utils.FileUploadUtil;
import com.kedi.productcenter.utils.ResultVoUtil;
import com.kedi.productcenter.vo.ResultVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.util.UUID;

/**
 * 图片, 文件, 视频, 音频上传共用接口
 * @author Zyred
 */
@Controller
@RequestMapping("/file")
public class FileUploadUtilController {


    @RequestMapping("/index")
    public String file(){
        return "index";
    }

    /**
     * 文件上传
     * @param type
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/fileUpload/ds", produces="application/json;charset=UTF-8", method = RequestMethod.POST)
    public String fileUpload(@RequestParam("type") String type, @RequestParam("file") MultipartFile file){
        FileUploadUtil upload = new FileUploadUtil(type, file);
        String result = upload.uploadFile();
        return result;
    }

}
  • 3、修改配置文件
    spring:  
      servlet:
        multipart:
          max-file-size: 1024MB         # 允许上传最大文件大小
          file-size-threshold: 1MB
          max-request-size: 1024MB      # 设置最大的请求文件的大小

    最后,如果项目中使用了zuul作为网关,在配置文件中也要加上该配置

<think>我们正在讨论“公用接口”与“调用接口”的概念和实现方式。根据提供的引用,我们可以提炼以下信息:引用[1]:说明了接口在Java中的用途,主要是为了在类之间建立契约(即使没有is-a关系),并突破单继承限制。引用[2]:展示了一个WebService接口的定义,它作为公用接口的示例,用于统一暴露方法并管理命名空间。引用[3]:演示了Spring框架中异步调用接口方法的实现方式。下面我们将分别解释这两个概念:1.**公用接口(PublicInterface)**:通常指设计给外部系统或模块使用的接口,它定义了服务提供者对外公开的契约。例如在WebService中,我们定义一个公用接口(如引用[2]中的ApiService),然后由不同的类去实现它,这样外部调用者只需要遵循接口定义即可调用服务,无需关心内部实现。公用接口强调稳定性和规范性。2.**调用接口(InvocationInterface)**:通常指实际调用接口方法的过程和方式。例如引用[3]中,我们通过Spring的`@Async`注解来实现异步调用接口方法。调用接口关注的是如何执行接口定义的方法,如同步/异步、本地/远程等。**主要区别**:-**公用接口**:关注接口的设计和定义,如方法签名、参数、返回类型等,是静态的契约。-**调用接口**:关注接口方法的执行机制,是动态的调用过程。**实现方式**:**公用接口的实现**(以Java为例):-定义接口(如引用[2]):```java@WebService(targetNamespace="http://service.spi.bjca.cn/")publicinterfaceApiService{//声明公用方法publicStringsomeMethod(Stringparam);}```-实现接口:```java@ServicepublicclassApiServiceImplimplementsApiService{@OverridepublicStringsomeMethod(Stringparam){//具体实现return"Result:"+param;}}```**调用接口的实现**(以Spring异步调用为例,引用[3]):-配置Spring支持异步(在applicationContext.xml中):```xml<task:annotation-driven/>```-在需要异步调用的方法上添加注解:```java@ServicepublicclassSomeService{@AsyncpublicvoidasyncMethod(){//异步执行的方法体}}```-调用异步方法(Spring会自动创建代理,使调用变为异步):```java@AutowiredSomeServicesomeService;//注意:直接通过Spring注入的代理对象调用publicvoidcallAsyncMethod(){someService.asyncMethod();//异步调用,立即返回}```需要注意的是,调用接口的方式还可以有:-同步调用:直接调用接口方法,等待返回结果。-远程调用(如RPC):通过远程代理调用接口方法。-事件驱动:通过消息队列等方式触发接口方法。**总结**:公用接口是契约,调用接口是执行契约的方式。在软件设计中,定义清晰稳定的公用接口至关重要,而调用接口的实现则可以根据性能、可用性等需求灵活选择。§§相关问题§§1.如何设计一个稳定且可扩展的公用接口?2.除了异步调用,调用接口还有哪些常见调用方式?3.在分布式系统中公用接口的设计有何特殊要求?</think> ### 公用接口 vs 调用接口 概念解析与实现方法 #### 1. 公用接口(Public Interface) **定义**:公用接口是对外公开的标准化契约,定义系统或模块对外暴露的功能规范(如引用[2]所示)。它强调**统一标准**和**解耦**。 - **核心特征**: - 限定命名空间和访问规则(如引用[2]中的`@WebService`注解) - 仅声明方法签名(无具体实现) - 强制实现类遵守统一规范 - **实现方式**: ```java // 定义公用接口(引用[2]) @WebService(targetNamespace = "http://service.example/") public interface ApiService { String processRequest(String param); // 统一方法签名 } // 实现接口 @Service public class ApiServiceImpl implements ApiService { @Override public String processRequest(String param) { return "Processed: " + param; // 具体实现 } } ``` - **使用场景**: - 跨系统集成(如WebService、RESTful API) - 模块解耦(如Spring中的服务接口) #### 2. 调用接口(Invocation Interface) **定义**:调用接口关注**如何执行接口方法**,包括调用机制、执行策略(如同步/异步)和生命周期管理(如引用[3]所示)。 - **核心特征**: - 控制方法执行方式(如同步、异步) - 管理调用线程和资源 - 处理异常和超时 - **实现方式**: ```java // Spring异步调用(引用[3]) @Service public class PaymentService { // 同步调用 public void syncProcess() { /* 直接执行 */ } // 异步调用(添加@Async注解) @Async public void asyncProcess() { Thread.sleep(5000); // 后台线程执行 } } // 配置异步支持(applicationContext.xml) <task:annotation-driven executor="myExecutor"/> <task:executor id="myExecutor" pool-size="5"/> ``` - **调用示例**: ```java @Autowired PaymentService paymentService; public void executePayment() { paymentService.syncProcess(); // 阻塞式调用 paymentService.asyncProcess(); // 非阻塞式异步调用 } ``` #### 3. 关键区别 | **维度** | 公用接口 | 调用接口 | |-------------------|-------------------------------|------------------------------| | **定位** | 定义**功能规范** | 定义**执行机制** | | **核心目标** | 统一标准、解耦实现 | 控制执行方式、资源管理 | | **典型技术** | Java Interface, WebService | @Async, 线程池, 远程调用 | | **修改影响范围** | 所有实现类需同步修改 | 调用方适配新执行策略 | | **使用场景** | 系统间集成、架构分层 | 性能优化、复杂调用链管理 | #### 4. 典型应用场景 1. **公用接口使用场景**(如引用[1][2]): - 突破Java单继承限制(`implements`多个接口) - 定义跨系统通信协议(如SOAP/WSDL) - 组件化开发中规范模块边界 2. **调用接口使用场景**(如引用[3]): - 耗时操作异步化(避免阻塞主线程) - 批量任务并发执行(线程池控制) - 微服务熔断降级(Hystrix调用隔离) > **设计建议**:公用接口应保持稳定(避免频繁变更签名),而调用接口可根据性能需求动态调整(如切换线程池大小或异步策略)[^1][^2][^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值