静态资源相关问题-springboot

通过web访问项目中(resources文件夹下)的静态资源!

问题1-禁用默认规则

问题描述

配置了全局异常处理,禁用了默认的静态资源规则,将无法通过web访问项目中的静态资源。

#当没有对应处理器时,允许抛出异常(让自定义的异常处理类捕获404)
spring.mvc.throw-exception-if-no-handler-found=true
#禁用默认静态资源规则(不为工程中的资源文件建立映射)
spring.web.resources.add-mappings=false

#上述配置:所有访问不到的路径,均会抛出404异常,捕获之后返回自定义的DataVo实例-json对象。
#将不能访问static下的静态资源(若部署前端项目将不能访问),得前后端分开部署。

解决方法

要(通过web)访问项目中的静态资源(部署网站、图片等资源),**解决方法:**在自定义配置类中添加相关的ResourceHandler。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author: 轻率的保罗
 * @since: 2023-01-16
 * @Description: 静态资源规则配置。配置 全局异常处理-404异常捕获 之后(所有访问不到的路径,均会抛出404异常,捕获之后返回自定义的DataVo实例-json对象),导致静态资源无法正常访问,添加如下配置。
 * 注意:若访问路径(静态资源),从以下addResourceHandler配置的目录中找不到,则会返回“Whitelabel Error Page”页面,而不是经过全局异常处理捕获后返回的404错误信息(DataVo对象)
 */
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
    
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
    
        //静态资源:
        //    前端网站,访问 路径/web/** ,会在 项目resources/static/web/ 目录下查找
        //    文件,访问 路径/public/file/** ,会在 项目resources/static/public/file/ 目录下查找
        //    放图片,访问 路径/public/** 下的静态资源,会在 项目resources/static/public/image/ 目录下查找
        registry.addResourceHandler("/web/**").addResourceLocations("classpath:/static/web/");
        registry.addResourceHandler("/public/file/**").addResourceLocations("classpath:/static/public/file/");
        registry.addResourceHandler("/public/image/**").addResourceLocations("classpath:/static/public/image/");
        //swaggerUI:
        //    swagger第三方UI - Knife4j,访问地址为:http://localhost:8181/malldemo/doc.html
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");//以jar包方式访问js、css、html等静态资源(Knife4j的相关依赖已打包成jar包)
    }
}

需要注意的是文件放在resource文件夹下,会与项目一起打包成jar包。不想打包成jar包,见下边问题2



问题2-jar包

问题描述

文件放在resources文件夹下,会与项目一起打包成jar包。若部署了前端项目,要更新只能重新打包jar包,略显麻烦。若有文件上传功能,也不方便对上传的文件进行管理。

解决方法

解决方案:项目初始化时用到的静态资源放在resources文件夹下;后期提交/更新的静态资源(文件上传等),通过 自定义路径+配置静态资源规则 实现web访问功能。

配置文件

在springboot配置文件中添加几个自定义配置项。

  • 1、文件默认的保存位置为项目部署地址下的data文件夹(项目名_data),若要自定义文件保存位置,在springboot配置文件中添加自定义配置path.custom.enable、path.filepath.xxx设置文件保存位置。

  • 2、是否启用自定义静态资源映射,使用自定义配置web.resources.add-mappings.enable设置是否启用,使用自定义配置web.resources.path-pattern设置web访问匹配路径。

# 文件上传位置:
#   文件默认保存在项目部署地址下的data文件夹中(项目名_data),详情见AppConfig类init()方法。自定义文件保存位置,则同时添加下边三个配置:
#path.custom.enable=true
#path.filepath.linux=/usr/local/java/@artifactId@/
#path.filepath.windows=C:\\javafile\\@artifactId@\\

#   是否启用静态资源映射(上边文件保存地址,是否可以通过 http://xxx/xxx/xxx 访问到。默认不启用,详情见AppConfig类init()方法)
#   add-mappings.enable,用于设置是否启用。path-pattern,用于设置web访问匹配路径(默认为/web/**)。映射的服务器路径为文件保存地址。
web.resources.add-mappings.enable=true
#web.resources.path-pattern=/web/**

获取项目部署地址

文件默认保存在项目部署地址下的data文件夹中(项目名_data),就需要先获取项目部署地址。

直接通过java -jar xxx.jar命令运行springboot项目,获取jar包的位置(即项目部署地址)。

/**
 * 获取运行Jar包的目录,即项目部署地址。并检查是否有读写权限。
 * MacOs 13.1、Linux-Centos7、Win10环境中可获取到。
 * @return 路径
 */
private String getJarFilePathAndCheck() throws Exception {
    
    
    //方案一:可能Linux-Ubuntu中jarFile为null,无法获取到项目部署地址。无测试环境,未测试。
    ApplicationHome home = new ApplicationHome(getClass());
    File jarFile = home.getSource();
    String path = null;
    if(jarFile != null){
    
    
        path = jarFile.getParentFile().toString();
    }else{
    
    
        //方案二:获取classpath,从中截取(未在win系统中测试该方案。方案一大部分情况可正常获取)
        String classpath = ResourceUtils.getURL("classpath:").getPath();
        if(classpath.contains("file:")){
    
    
            //win系统,file:/F:/xxx,所以len为6
            int len = SysUtil.isWin()?6:5;
            classpath = classpath.substring(len);
            log.info("处理1 = "+classpath);
        }
        if(classpath.contains(".jar!")){
    
    
            classpath = classpath.substring(0,classpath.indexOf(".jar!"));
        }
        // 再把最后一个分隔符后边的去掉
        classpath = classpath.substring(0,classpath.lastIndexOf(File.separator)+1);
        path = classpath;
    }
    if(path == null || path == ""){
    
    
        String errMsg = "无法获取项目部署地址!!!";
        log.error(errMsg);
        throw new Exception(errMsg);
    }
    //目录最后须带有分隔符
    path = File.separator.equals(path.substring(path.length()-1))?path:path+File.separator;
    //检查读写权限
    SysUtil.checkAndCreatePath(path);
    return path;
}

SysUtil.checkAndCreatePath()如下:(类SysUtil,见附件3

/**
 * 检查路径是否存在,不存在则创建,同时检查路径是否是目录、检查是否有读写权限。
 * @param path 绝对地址
 */
public static void checkAndCreatePath(String path) throws Exception {
    
    
    File file = new File(path);
    if(file.exists()){
    
    
        //存在,则:1、检查是否是目录。2、检查是否有读写权限。
        if(!file.isDirectory()){
    
    
            String errMsg = "警告!路径【"+path+"】不是目录!";
            log.error(errMsg);
            throw new IllegalArgumentException(errMsg);
        }
        if(!file.canRead() || !file.canWrite()){
    
    
            String errMsg = "警告!路径【"+path+"】无读写权限!";
            log.error(errMsg);
            throw new AccessDeniedException(errMsg);
        }
    }else{
    
    
        //不存在,则创建目录。
        if(!file.mkdirs()){
    
    
            if(!file.canRead() || !file.canWrite()){
    
    
                String errMsg = "警告!路径【"+path+"】无读写权限!";
                log.error(errMsg);
                throw new AccessDeniedException(errMsg);
            }else {
    
    
                String errMsg = "路径【"+path+"】不存在,尝试创建目录,目录创建失败!";
                log.error(errMsg);
                throw new IOException(errMsg);
            }
        }
    }
}

初始化文件保存地址

定义一个类AppConfig,用于保存和初始化一些配置项,例如:

  • 文件保存地址filepath(根地址)
    • 其他文件保存地址(filepath下的子目录)
    • 检查目录是否已存在,存在则检查是否有读写权限,不存在则创建。
  • 静态资源映射匹配路径PATH_PATTERN
    • 如果配置文件中有配置则更新,否则使用默认配置“/web/**”

在类AppConfig中添加一个init()方法用于初始化这些配置。为了让init()方法在项目启动的时候执行,需要添加注解@PostConstruct。init()方法如下:

/**
 * 初始化变量jarFilePath、filepath
 * 检查是否有权限访问(读写)filepath,不存在则创建。无访问权限或创建失败会抛出异常,阻止项目启动
 */
@PostConstruct
public void init() throws Exception {
    
    
    log.info("---- 初始化AppConfig start ----");
    //初始化变量jarFilePath
    jarFilePath = getJarFilePathAndCheck();
    //初始化变量filepath
    Boolean isEnable = Boolean.valueOf(env.getProperty("path.custom.enable"));
    //是否自定义文件保存位置。默认保存在项目部署地址下(data文件夹)
    if(isEnable){
    
    
        log.info("自定义文件保存位置!");
        String filepathLinux = env.getProperty("path.filepath.linux");
        String filepathWin = env.getProperty("path.filepath.windows");
        if(filepathLinux == null || filepathWin == null){
    
    
            String errMsg = "自定义文件保存位置,但是未提供【path.filepath.linux】、【path.filepath.windows】!";
            log.error(errMsg);
            throw new IllegalArgumentException(errMsg);
        }
        if (SysUtil.isUnix()) {
    
    
            //Mac、Linux、Unix 系统
            filepath = filepathLinux;
        }else{
    
    
            if(SysUtil.isWin()){
    
    
                //Windows 系统
                filepath = filepathWin;
            }else{
    
    
                String errMsg = "未知系统类型【"+SysUtil.getOsName()+"】,无法初始化文件保存位置!!!";
                log.error(errMsg);
                throw new Exception(errMsg);
            }
        }
    }else{
    
    
        log.info("文件默认保存在项目部署地址下(data文件夹)!");
        //获取项目部署地址
        filepath = jarFilePath + env.getProperty("spring.application.name")+"_data" + File.separator;
    }
    //目录最后须带有分隔符
    filepath = File.separator.equals(filepath.substring(filepath.length()-1))?filepath:filepath+File.separator;
    //创建相关路径(无权限会抛出异常,阻止程序启动)
    String[] paths = {
    
    filepath,filepath+WEB_FOLDER,filepath+FILE_FOLDER,filepath+IMG_FOLDER,filepath+IMG_FOLDER+File.separator+CONTENT_IMG_FOLDER,filepath+IMG_FOLDER+File.separator+TAG_IMG_FOLDER,filepath+IMG_FOLDER+File.separator+AVATAR_IMG_FOLDER,filepath+IMG_FOLDER+File.separator+COMMON_IMG_FOLDER};
    for (String path : paths) {
    
    
        SysUtil.checkAndCreatePath(path);
    }
    log.info("文件保存根路径为: "+paths[0]);
    log.info("  -前端项目部署路径为: "+paths[1]);
    log.info("  -文件保存路径为: "+paths[2]);
    log.info("  -图片文件保存路径为: "+paths[3]);
    log.info("    +图片-动态配图 保存路径为: "+paths[4]);
    log.info("    +图片-标签图片 保存路径为: "+paths[5]);
    log.info("    +图片-头像图片 保存路径为: "+paths[6]);
    log.info("    +图片-其他类型图片 保存路径为: "+paths[7]);
    //是否启用静态资源映射
    if(isEnabelWebMapping()){
    
    
        String pathPattern = env.getProperty("web.resources.path-pattern");
        if(pathPattern != null){
    
    
            this.PATH_PATTERN = pathPattern;
        }
        log.info("是否启用静态资源映射: yes");
        log.info("  文件保存根路径为: "+filepath);
        log.info("  web路径为: "+getWebUrl());
        log.info("  前端项目访问url为: "+getWebUrl()+WEB_FOLDER+"/index.html");
        log.info("  静态资源访问示例:️");
        log.info("    访问动态配图,服务器保存路径为【"+paths[4]+"/图片文件名】️");
        log.info("    web路径为【"+getWebUrl()+IMG_FOLDER+"/"+CONTENT_IMG_FOLDER+"/图片文件名】");
        // 示例: http://localhost:8181/malldemo/web/image/contentimg/assii.jpg
    }else{
    
    
        log.info("是否启用静态资源映射: no");
    }
    log.info("---- 初始化AppConfig end ----");
}

类AppConfig代码见最后的附件1

设置静态资源映射规则

问题1-解决方法中类MyWebMvcConfigurer,在重写的addResourceHandlers方法中添加如下内容:

根据springboot配置文件中的配置,判断是否要配置 自定义静态资源映射规则。

//配置 静态资源映射(详情见AppConfig类中的init()方法),同时映射jar包内的resources文件夹下的static文件夹
if(appConfig.isEnabelWebMapping()){
    
    
    registry.addResourceHandler(appConfig.getPATH_PATTERN()).addResourceLocations("file:" + appConfig.getFilePath(),"classpath:/static/");
}
//url路径 “/web/**” 映射到 服务器地址“filePath”(文件保存地址)和项目的resources/static/文件夹。变量PATH_PATTERN配置在类AppConfig中。

类MyWebMvcConfigurer代码见最后的附件2

测试1

不配置文件保存地址,即默认保存在项目部署地址下的data文件夹中(项目名_data)。

启用静态资源映射。

# 文件上传位置:
# 自定义文件保存位置,则同时添加下边三个配置:
#path.custom.enable=true
#path.filepath.linux=/usr/local/java/@artifactId@/
#path.filepath.windows=C:\\javafile\\@artifactId@\\
# 是否启用静态资源映射
web.resources.add-mappings.enable=true

运行结果:IDEA中启动项目

 ---- 初始化AppConfig start ----
文件默认保存在项目部署地址下(data文件夹)!
文件保存根路径为: /Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/
  -前端项目部署路径为: /Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/project
  -文件保存路径为: /Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/file
  -图片文件保存路径为: /Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/image
    +图片-动态配图 保存路径为: /Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/image/contentimg
    +图片-标签图片 保存路径为: /Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/image/tagimg
    +图片-头像图片 保存路径为: /Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/image/avatarimg
    +图片-其他类型图片 保存路径为: /Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/image/common
是否启用静态资源映射: yes
  文件保存根路径为: /Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/
  web路径为: http://127.0.0.1:8181/malldemo/web/
  前端项目访问url为: http://127.0.0.1:8181/malldemo/web/project/index.html
  静态资源访问示例:️
    访问动态配图,服务器保存路径为【/Users/qsdbl/Documents/workspace/java/mall-demo/target/mall-demo_data/image/contentimg/图片文件名】️
    web路径为【http://127.0.0.1:8181/malldemo/web/image/contentimg/图片文件名】
---- 初始化AppConfig end ----

测试2

配置自定义文件保存地址。

启用静态资源映射。

# 文件上传位置:
# 自定义文件保存位置,则同时添加下边三个配置:
path.custom.enable=true
path.filepath.linux=/usr/local/java/@artifactId@/
path.filepath.windows=C:\\javafile\\@artifactId@\\
# 是否启用静态资源映射
web.resources.add-mappings.enable=true

运行结果:IDEA中启动项目

---- 初始化AppConfig start ----
自定义文件保存位置!
文件保存根路径为: /usr/local/java/mall-demo/
  -前端项目部署路径为: /usr/local/java/mall-demo/project
  -文件保存路径为: /usr/local/java/mall-demo/file
  -图片文件保存路径为: /usr/local/java/mall-demo/image
    +图片-动态配图 保存路径为: /usr/local/java/mall-demo/image/contentimg
    +图片-标签图片 保存路径为: /usr/local/java/mall-demo/image/tagimg
    +图片-头像图片 保存路径为: /usr/local/java/mall-demo/image/avatarimg
    +图片-其他类型图片 保存路径为: /usr/local/java/mall-demo/image/common
是否启用静态资源映射: yes
  文件保存根路径为: /usr/local/java/mall-demo/
  web路径为: http://127.0.0.1:8181/malldemo/web/
  前端项目访问url为: http://127.0.0.1:8181/malldemo/web/project/index.html
  静态资源访问示例:️
    访问动态配图,服务器保存路径为【/usr/local/java/mall-demo/image/contentimg/图片文件名】️
    web路径为【http://127.0.0.1:8181/malldemo/web/image/contentimg/图片文件名】
---- 初始化AppConfig end ----

将图片assii.jpg放到目录“/usr/local/java/mall-demo/image/contentimg”下,访问地址“http://localhost:8181/malldemo/web/image/contentimg/assii.jpg”,结果如下:



附件

附件1

package com.qsdbl.malldemo.configuration;

import com.qsdbl.malldemo.common.utils.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;
import javax.annotation.PostConstruct;
import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author: 轻率的保罗
 * @since: 2023-01-30
 * @Description: 程序配置信息
 */
@Slf4j
@Component(value = "appconfig")
public class AppConfig {
    
    
    /**
     * 静态资源映射 匹配路径(web访问路径前缀)
     */
    private String PATH_PATTERN = "/web/**";

    /**
     * 项目部署地址。
     */
    private String jarFilePath;

    /**
     * 文件保存地址。包含jarFilePath
     */
    private String filepath;

    /**
     * 保存文件 文件夹。filepath下的一级文件夹,即 filepath + FILE_FOLDER
     */
    private String FILE_FOLDER = "file";

    /**
     * 存放前端项目 文件夹。filepath下的一级文件夹。
     * 将前端项目部署在 filepath + WEB_FOLDER 下,即可通过 getWebUrl() + WEB_FOLDER 访问前端项目。
     */
    private String WEB_FOLDER = "project";

    /**
     * 图片文件 文件夹。filepath下的一级文件夹。
     */
    private String IMG_FOLDER = "image";

    /**
     * 动态配图 文件夹。
     * IMG_FOLDER下的一级文件夹,即 filepath + IMG_FOLDER + CONTENT_IMG_FOLDER。下同。
     */
    private String CONTENT_IMG_FOLDER = "contentimg";

    /**
     * 标签图片 文件夹。
     */
    private String TAG_IMG_FOLDER = "tagimg";

    /**
     * 头像图片 文件夹。
     */
    private String AVATAR_IMG_FOLDER = "avatarimg";

    /**
     * 其他类型图片 文件夹。
     */
    private String COMMON_IMG_FOLDER = "common";

    /**
     * 获取配置文件中的配置信息
     */
    @Autowired
    private Environment env;

    /**
     * 初始化变量jarFilePath、filepath
     * 检查是否有权限访问(读写)filepath,不存在则创建。无访问权限或创建失败会抛出异常,阻止项目启动
     */
    @PostConstruct
    public void init() throws Exception {
    
    
        log.info("---- 初始化AppConfig start ----");
        //初始化变量jarFilePath
        jarFilePath = getJarFilePathAndCheck();
        //初始化变量filepath
        Boolean isEnable = Boolean.valueOf(env.getProperty("path.custom.enable"));
        //是否自定义文件保存位置。默认保存在项目部署地址下(data文件夹)
        if(isEnable){
    
    
            log.info("自定义文件保存位置!");
            String filepathLinux = env.getProperty("path.filepath.linux");
            String filepathWin = env.getProperty("path.filepath.windows");
            if(filepathLinux == null || filepathWin == null){
    
    
                String errMsg = "自定义文件保存位置,但是未提供【path.filepath.linux】、【path.filepath.windows】!";
                log.error(errMsg);
                throw new IllegalArgumentException(errMsg);
            }
            if (SysUtil.isUnix()) {
    
    
                //Mac、Linux、Unix 系统
                filepath = filepathLinux;
            }else{
    
    
                if(SysUtil.isWin()){
    
    
                    //Windows 系统
                    filepath = filepathWin;
                }else{
    
    
                    String errMsg = "未知系统类型【"+SysUtil.getOsName()+"】,无法初始化文件保存位置!!!";
                    log.error(errMsg);
                    throw new Exception(errMsg);
                }
            }
        }else{
    
    
            log.info("文件默认保存在项目部署地址下(data文件夹)!");
            //获取项目部署地址
            filepath = jarFilePath + env.getProperty("spring.application.name")+"_data" + File.separator;
        }
        //目录最后须带有分隔符
        filepath = File.separator.equals(filepath.substring(filepath.length()-1))?filepath:filepath+File.separator;
        //创建相关路径(无权限会抛出异常,阻止程序启动)
        String[] paths = {
    
    filepath,filepath+WEB_FOLDER,filepath+FILE_FOLDER,filepath+IMG_FOLDER,filepath+IMG_FOLDER+File.separator+CONTENT_IMG_FOLDER,filepath+IMG_FOLDER+File.separator+TAG_IMG_FOLDER,filepath+IMG_FOLDER+File.separator+AVATAR_IMG_FOLDER,filepath+IMG_FOLDER+File.separator+COMMON_IMG_FOLDER};
        for (String path : paths) {
    
    
            SysUtil.checkAndCreatePath(path);
        }
        log.info("文件保存根路径为: "+paths[0]);
        log.info("  -前端项目部署路径为: "+paths[1]);
        log.info("  -文件保存路径为: "+paths[2]);
        log.info("  -图片文件保存路径为: "+paths[3]);
        log.info("    +图片-动态配图 保存路径为: "+paths[4]);
        log.info("    +图片-标签图片 保存路径为: "+paths[5]);
        log.info("    +图片-头像图片 保存路径为: "+paths[6]);
        log.info("    +图片-其他类型图片 保存路径为: "+paths[7]);
        //是否启用静态资源映射
        if(isEnabelWebMapping()){
    
    
            String pathPattern = env.getProperty("web.resources.path-pattern");
            if(pathPattern != null){
    
    
                this.PATH_PATTERN = pathPattern;
            }
            log.info("是否启用静态资源映射: yes");
            log.info("  文件保存根路径为: "+filepath);
            log.info("  web路径为: "+getWebUrl());
            log.info("  前端项目访问url为: "+getWebUrl()+WEB_FOLDER+"/index.html");
            log.info("  静态资源访问示例:️");
            log.info("    访问动态配图,服务器保存路径为【"+paths[4]+"/图片文件名】️");
            log.info("    web路径为【"+getWebUrl()+IMG_FOLDER+"/"+CONTENT_IMG_FOLDER+"/图片文件名】");
            // 示例: http://localhost:8181/malldemo/web/image/contentimg/assii.jpg
        }else{
    
    
            log.info("是否启用静态资源映射: no");
        }
        log.info("---- 初始化AppConfig end ----");
    }

    /**
     * 获取ip地址
     */
    public String getIpAddress() throws UnknownHostException {
    
    
        return InetAddress.getLocalHost().getHostAddress();
    }

    /**
     * 获取web url(即静态资源访问路径,要加上静态资源保存位置相对于filepath的 相对地址 才能访问到具体的资源)。
     * 前提是启用静态资源映射,通过isEnabelWebMapping()来判断。
     * 最后带有分隔符。
     * @return url 或者 空字符串(说明未启用静态资源映射)
     */
    public String getWebUrl() throws UnknownHostException {
    
    
        //   /malldemo/   处理成 /malldemo
        String contextPath = env.getProperty("server.servlet.context-path");
        if(contextPath != null && contextPath.endsWith("/")){
    
    
            contextPath = contextPath.substring(0,contextPath.length()-1);
        }
        String url = "http://"+ getIpAddress()+":"+env.getProperty("server.port")+contextPath+ PATH_PATTERN.substring(0, PATH_PATTERN.lastIndexOf("/**")+1);
        return isEnabelWebMapping()?url:"";
    }

    /**
     * 是否启用静态资源映射
     */
    public boolean isEnabelWebMapping(){
    
    
        return Boolean.valueOf(env.getProperty("web.resources.add-mappings.enable"));
    }

    /**
     * 获取项目部署地址(最后有分隔符)
     */
    public String getJarFilePath(){
    
    
        return jarFilePath;
    }

    /**
     * 获取文件保存地址(最后有分隔符)
     */
    public String getFilePath(){
    
    
        return filepath;
    }

    /**
     * 获取运行Jar包的目录,即项目部署地址。并检查是否有读写权限。
     * MacOs 13.1、Linux-Centos7、Win10环境中可获取到。
     * @return 路径
     */
    private String getJarFilePathAndCheck() throws Exception {
    
    
        //方案一:可能Linux-Ubuntu中jarFile为null,无法获取到项目部署地址。无测试环境,未测试。
        ApplicationHome home = new ApplicationHome(getClass());
        File jarFile = home.getSource();
        String path = null;
        if(jarFile != null){
    
    
            path = jarFile.getParentFile().toString();
        }else{
    
    
            //方案二:获取classpath,从中截取(未在win系统中测试该方案。方案一大部分情况可正常获取)
            String classpath = ResourceUtils.getURL("classpath:").getPath();
            if(classpath.contains("file:")){
    
    
                //win系统,file:/F:/xxx,所以len为6
                int len = SysUtil.isWin()?6:5;
                classpath = classpath.substring(len);
                log.info("处理1 = "+classpath);
            }
            if(classpath.contains(".jar!")){
    
    
                classpath = classpath.substring(0,classpath.indexOf(".jar!"));
            }
            // 再把最后一个分隔符后边的去掉
            classpath = classpath.substring(0,classpath.lastIndexOf(File.separator)+1);
            path = classpath;
        }
        if(path == null || path == ""){
    
    
            String errMsg = "无法获取项目部署地址!!!";
            log.error(errMsg);
            throw new Exception(errMsg);
        }
        //目录最后须带有分隔符
        path = File.separator.equals(path.substring(path.length()-1))?path:path+File.separator;
        //检查读写权限
        SysUtil.checkAndCreatePath(path);
        return path;
    }

    public String getFILE_FOLDER() {
    
    
        return FILE_FOLDER;
    }

    public String getIMG_FOLDER() {
    
    
        return IMG_FOLDER;
    }

    public String getCONTENT_IMG_FOLDER() {
    
    
        return CONTENT_IMG_FOLDER;
    }

    public String getTAG_IMG_FOLDER() {
    
    
        return TAG_IMG_FOLDER;
    }

    public String getAVATAR_IMG_FOLDER() {
    
    
        return AVATAR_IMG_FOLDER;
    }

    public String getCOMMON_IMG_FOLDER() {
    
    
        return COMMON_IMG_FOLDER;
    }

    /**
     * 获取保存 文件 根文件夹 完整路径(服务器绝对路径)
     * @return 路径最后带有分隔符
     */
    public String getFILE_FOLDER_FULL() {
    
    
        return filepath+FILE_FOLDER+File.separator;
    }
//
//    /**
//     * 获取保存 图片文件 根文件夹 完整路径(服务器绝对路径)
//     * @return 路径最后带有分隔符
//     */
//    public String getIMG_FOLDER_FULL() {
    
    
//        return filepath+IMG_FOLDER+File.separator;
//    }

    /**
     * 获取保存 动态配图 文件夹 完整路径(服务器绝对路径)
     * @return 路径最后带有分隔符
     */
    public String getCONTENT_IMG_FOLDER_FULL() {
    
    
        return filepath+IMG_FOLDER+File.separator+CONTENT_IMG_FOLDER+File.separator;
    }

    /**
     * 获取保存 标签图片 文件夹 完整路径(服务器绝对路径)
     * @return 路径最后带有分隔符
     */
    public String getTAG_IMG_FOLDER_FULL() {
    
    
        return filepath+IMG_FOLDER+File.separator+TAG_IMG_FOLDER+File.separator;
    }

    /**
     * 获取保存 头像图片 文件夹 完整路径(服务器绝对路径)
     * @return 路径最后带有分隔符
     */
    public String getAVATAR_IMG_FOLDER_FULL() {
    
    
        return filepath+IMG_FOLDER+File.separator+AVATAR_IMG_FOLDER+File.separator;
    }

    /**
     * 获取保存 其他类型图片 文件夹 完整路径(服务器绝对路径)
     * @return 路径最后带有分隔符
     */
    public String getCOMMON_IMG_FOLDER_FULL() {
    
    
        return filepath+IMG_FOLDER+File.separator+COMMON_IMG_FOLDER+File.separator;
    }

    /**
     * 获取静态资源映射路径
     */
    public String getPATH_PATTERN() {
    
    
        return PATH_PATTERN;
    }
}

附件2

package com.qsdbl.malldemo.configuration;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author: 轻率的保罗
 * @since: 2023-01-16
 * @Description: 静态资源规则配置。配置 全局异常处理-404异常捕获 之后(所有访问不到的路径,均会抛出404异常,捕获之后返回自定义的DataVo实例-json对象),导致静态资源无法正常访问,添加如下配置。
 * 注意:若访问路径(静态资源),从以下addResourceHandler配置的目录中找不到,则会返回“Whitelabel Error Page”页面,而不是经过全局异常处理捕获后返回的404错误信息(DataVo对象)
 * 注意:addResourceLocations中地址最后带有分隔符
 */
@Slf4j
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
    
    

    /**
     * 获取配置文件中的配置信息
     */
    @Autowired
    private Environment env;

    /**
     * 程序配置信息
     */
    @Autowired
    private AppConfig appConfig;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
    
        //配置 静态资源映射(详情见AppConfig类中的init()方法)
        if(appConfig.isEnabelWebMapping()){
    
    
            registry.addResourceHandler(appConfig.getWEBPATH()).addResourceLocations("file:" + appConfig.getFilePath());
        }
        //swaggerUI:
        //    swagger第三方UI - Knife4j,访问地址为:http://localhost:8181/malldemo/doc.html
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");//以jar包方式访问js、css、html等静态资源(Knife4j的相关依赖已打包成jar包)
    }
}

附件3

package com.qsdbl.malldemo.common.utils;

import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException;
import java.nio.file.AccessDeniedException;

/**
 * @author: 轻率的保罗
 * @since: 2023-01-30
 * @Description: 通用工具类
 */
@Slf4j
public class SysUtil {
    
    

    /**
     * 检查路径是否存在,不存在则创建,同时检查路径是否是目录、检查是否有读写权限。
     * @param path 绝对地址
     */
    public static void checkAndCreatePath(String path) throws Exception {
    
    
        File file = new File(path);
        if(file.exists()){
    
    
            //存在,则:1、检查是否是目录。2、检查是否有读写权限。
            if(!file.isDirectory()){
    
    
                String errMsg = "警告!路径【"+path+"】不是目录!";
                log.error(errMsg);
                throw new IllegalArgumentException(errMsg);
            }
            if(!file.canRead() || !file.canWrite()){
    
    
                String errMsg = "警告!路径【"+path+"】无读写权限!";
                log.error(errMsg);
                throw new AccessDeniedException(errMsg);
            }
        }else{
    
    
            //不存在,则创建目录。
            if(!file.mkdirs()){
    
    
                if(!file.canRead() || !file.canWrite()){
    
    
                    String errMsg = "警告!路径【"+path+"】无读写权限!";
                    log.error(errMsg);
                    throw new AccessDeniedException(errMsg);
                }else {
    
    
                    String errMsg = "路径【"+path+"】不存在,尝试创建目录,目录创建失败!";
                    log.error(errMsg);
                    throw new IOException(errMsg);
                }
            }
        }
    }

    /**
     * 是否是 Unix 系统,包括Mac、Linux、Unix 系统
     * @return true - 是;false - 不是;
     */
    public static boolean isUnix(){
    
    
        String osName = getOsName();
        return osName.contains("mac") || osName.contains("linux") || osName.contains("unix");
    }

    /**
     * 是否是 Windows 系统
     * @return true - 是;false - 不是;
     */
    public static boolean isWin(){
    
    
        String osName = getOsName();
        return osName.contains("win");
    }

    /**
     * 获取系统名称(转换为小写)
     * @return 例如:mac os x
     */
    public static String getOsName(){
    
    
        return System.getProperty("os.name").toLowerCase();
    }

}


说明

本博客中的案例,使用的maven依赖如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.2</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<!--        启用web支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--        启用lombok(lombok 与 日志@Slf4j)-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

<!--        启用单元测试-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

<!-- mybatis-plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.2</version>
</dependency>

猜你喜欢

转载自blog.csdn.net/weixin_44773109/article/details/128940262