SpringBoot 2.x 图片上传本地 静态资源配置 Docker 部署差异

SpringBoot 2.x 图片上传本地 静态资源配置 Docker 部署差异

概述

  1. 项目基于 SpringBoot 2.X
  2. 实现图片上传到本地并通过 ip + 端口访问
  3. 部署方式为 docker,同时兼容 windows 环境
  4. 上传的图片实现持久化保存
  5. 已应用到实际开发环境中

本文目的

网上有很多类似的介绍,但都是基于 window 环境的配置方式,配置的方式有好多种,这里我整合了一下,并且结合自身开发需求进行了相应的调整。

图片上传功能

  • Controller
@ApiOperation("图片上传")
    @ApiResponses({
            @ApiResponse(code = 0, message = "图片上传成功", response = ImageDTO.class),
            @ApiResponse(code = 0002, message = "图片上传异常"),
            @ApiResponse(code = 0004, message = "图片过大,最大不能超过10M")
    })
    @PostMapping("/uploadImage")
    public ResultResponse<ImageDTO> uploadImage(@RequestBody MultipartFile file) {
        try {

            // 1. 图片上传
            String fileName = file.getOriginalFilename();
            String newFileName = UuidUtils.uuid() + fileName.substring(fileName.lastIndexOf("."));
            String imgFilePath = FileUtils.getSystemImagePath() + newFileName;
            log.info("uploadImage path = {}", imgFilePath);
            file.transferTo(new File(imgFilePath));

            //2. 将图片地址返回
            ImageDTO uploadDTO = new ImageDTO();

            // 相对路径
            String imageRelativelyUrl = AresConst.imagePath + newFileName;
            // 项目地址+文件路径
            String imageFullPath = serverConfig.getLocalServerUrl() + imageRelativelyUrl;

            uploadDTO.setImageUrl(imageFullPath);
            uploadDTO.setImageName(newFileName);
            uploadDTO.setImageRelativelyUrl(imageRelativelyUrl);

            return ResultResponse.success(uploadDTO);
        } catch (IOException e) {
            log.error(SystemEnum.IMAGE_UPLOAD_ERROR.getMsg(), e);
            throw new CustomException(SystemEnum.IMAGE_UPLOAD_ERROR.getCode(), SystemEnum.IMAGE_UPLOAD_ERROR.getMsg());
        }
    }
  • 获取系统路径方法
  1. ResourceUtils.getURL(“classpath:”).getPath(); 这个方法是获取 classpath 路径,也就是 resource 目录下, window 和Linux 环境下都能拿到当前项目的根路径,如果是部署在 docker 环境下,使用 jar 包启动,这个目录就为 jar 包的同级目录

Resource resource = new ClassPathResource(“classpath”); 这个方法,我当时在本地使用没有任何问题,但是部署到 docker 环境下,就获取不到路径了。

  1. images 在根目录下创建一个 images 文件夹,这个是为了统一管理,而且部署到 docker 后做目录挂载使用,所有图片上传到这个文件夹下
  2. 还有一种获取项目根目录的方法:System.getProperty(“user.dir”); 这个在 Linux 环境下同样适用,包括部署到 docker 中
    /** *
     * 获取图片存放路径
     * @param
     * @return java.lang.String
     * @date 2020/06/12 11:48
     */
    public static String getSystemImagePath() {
        String imagePath = "";
        try {
            //获取根目录
            File path = new File(ResourceUtils.getURL("classpath:").getPath());
            if (!path.exists()) {
                path = new File("");
            }
            //如果上传目录为/images/,则可以如下获取
            File upload = new File(path.getAbsolutePath(), "images/");
            if (!upload.exists()) {
                upload.mkdirs();
            }
            // 需要拼接一个 / 上面方法生成的路径缺少/ 
            imagePath = upload.getAbsolutePath()+"/";
        } catch (FileNotFoundException e) {
            log.error("getSystemImagePath 异常", e);
        }
        log.info("getSystemImagePath generate path = {}", imagePath);
        return imagePath;
    }

静态资源配置

  1. 主要是为了将上传后的图片提供给前端访问

  2. 有 2 种配置方式:

    2.1 SpringMvc 的配置方式,在 application.yml 文件中配置,我下面会给出链接,可以参考

    2.2 继承 WebMvcConfigurationSupport 使用代码来配置,这种方式在 SpringBoot 中比较推荐

    本文采用的就是第二种方式

  3. 核心方法:addResourceHandlers

    3.1 addResourceHandler: 这个方法里面就是配置静态资源的,addResourceHandler:匹配规则,主要是访问图片的路径,可以写正则

    3.2 addResourceLocations: 静态资源路径,这个我个人认为不能写正则,其实我还是很想写正则,但是发现写了正则,然而并没有作用,或者写的方式有问题,写正则的目的是想解决一个文件夹下多级路径下的图片

    window环境下:本地自定义路径(看注释),docker 或 Linux 下:linux jar 同目录下路径(看注释)

    支持配置多个路径,classpath 开头的是配置到项目 resource 目录下,file 开头的是配置到自定义目录下,这个目录需要自己创建出来,如果 docker 中是以 jar 包方式启动,建议用 file 方式,如果重新部署图片也不会丢失

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    @Override
    protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
                SerializerFeature.WriteEnumUsingToString,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.DisableCircularReferenceDetect);
        fastJsonConfig.setSerializeFilters((ValueFilter) (o, s, source) -> {
            boolean bool = source != null && (source instanceof Long || source instanceof BigInteger) && source.toString().length() > 15;
            if (bool) {
                return source.toString();
            } else {
                return null == source ? "" : source;
            }
        });

        //处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        fastConverter.setSupportedMediaTypes(fastMediaTypes);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        converters.add(fastConverter);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 静态资源映射路径:文件必传放在resource/images/ eg:http://ip:port/images/4f48204eb5bd4711ad62d1a8fb42952c.jpg
//        registry.addResourceHandler("/images/**").addResourceLocations("classpath:/images/");
        // 本地自定义路径
//        registry.addResourceHandler("/images/**").addResourceLocations("file:/F:/images");
         // linux jar 同目录下路径
        registry.addResourceHandler("/images/**").addResourceLocations("file:/usr/src/app/images/");

        registry.addResourceHandler("/**").addResourceLocations(
                "classpath:/static/");
        registry.addResourceHandler("swagger-ui.html").addResourceLocations(
                "classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations(
                "classpath:/META-INF/resources/webjars/");
        super.addResourceHandlers(registry);
    }

    /**
     * 注册自定义拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(new AresInterceptor())
                .addPathPatterns("/*/v1/**")
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/favicon.ico");

    }

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {

        configurer.favorPathExtension(false);

    }

    /**
     * 解决跨域问题
     *
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedHeaders("*")
                .allowCredentials(true)
                .allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE")
                .maxAge(3600);
    }


}

docker 部署注意事项

  1. 需要挂载文件夹目录,避免重新部署时丢失文件,这个是因为 docker 每次部署会重新启动,所有的东西都是新的,所以你需要挂载到 Linux 下,启动后文件夹就是互通的
  2. 关于 docker 下目录,我上面给出的目录是我们的真实目录,可能不同部署方式目录会有所不一样,需要自己进入 docker 查看 jar 包所在目录地址
  3. docker 启动目录挂载命令: -v /data/appdatas/project/images:/usr/src/app/images
  4. 进入 docker 命令:docker exec -it [dockerID] /bin/sh

本文参考以下链接

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值