背景

最近在着手公司框架优化及我的项目理论利用,原先计划是springboot+html前后端拆散独自部署,后端人员兼职前端开发,后续产品线业务进行优化,面向企业应用局部由挪动网站人员负责设计开发,外部配置后盾治理还是由后端负责,随着框架不停迭代与应用的我的项目越来越多,我的项目降级框架变得非常麻烦,后端局部能够通过maven私服进行版本迭代,后盾治理页面降级则须要进行各个我的项目拷贝,所以决定对框架进行整合,将后盾治理页面与框架后端代码进行整合公布。

结构设计

  • 框架打包后盾治理相干规范资源及页面(框架public文件夹)
  • 我的项目应用框架,开发具体业务配置管理页面(我的项目static文件夹)
  • 我的项目须要个性化框架页面时,在我的项目static文件夹建设与框架同目录同名称资源文件进行笼罩,拜访时优先级高于框架目录

SpringBoot动态资源拜访

自定义拜访门路

自定义WebConfig实现WebMvcConfigurer,重写addResourceHandlers办法

@Configurationpublic class WebConfig implements WebMvcConfigurer {    @Value("${system.projectName}")    private String projectName;     /**     * 增加动态资源文件,内部能够间接拜访地址     *     * @param registry     */    @Override    public void addResourceHandlers(ResourceHandlerRegistry registry) {        //第一个办法设置拜访门路前缀,第二个办法设置资源门路        registry.addResourceHandler("/" + projectName + "/**").addResourceLocations("classpath:/static/","classpath:/public/","file:static/");    }}

图标与字体文件夹拜访失败问题

将动态文件拷贝到static/public/resource文件夹下拜访时,图标与字体文件会进行过滤导致损坏,须要在pom文件中进行设置

 <build>        <resources>            <resource>                <filtering>true</filtering>                <directory>src/main/resources</directory>                <excludes>                    <exclude>**/*.woff</exclude>                    <exclude>**/*.ttf</exclude>                    <exclude>**/*.ico</exclude>                </excludes>            </resource>            <resource>                <filtering>false</filtering>                <directory>src/main/resources</directory>                <includes>                    <include>**/*.woff</include>                    <include>**/*.ttf</include>                    <include>**/*.ico</include>                </includes>            </resource>        </resources> </build>

自定义欢送页面

在对动态内目录设置自定义拜访门路替换原有的/**后,无奈找到目录下的index页面,须要建设拦截器手动进行判断,成果为拜访http://localhost:port/project... 会主动跳转到 http://localhost:port/project...

@Componentpublic class PageRedirectInterceptor implements HandlerInterceptor {    @Value("${system.projectName}")    private String projectName;    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        String requestURL = request.getRequestURL().toString();        String scheme = request.getScheme();        String servaerName = request.getServerName();        int port = request.getServerPort();        String rootPageURL = scheme + ":" + "//" + servaerName + ":" + port + "/" + projectName;        if (requestURL.equals(rootPageURL)) {            response.sendRedirect(request.getContextPath() + "/"+projectName + "/index.html");            return false;        }        return true;    }}

自定义页面图标

在对动态内目录设置自定义拜访门路替换原有的/**后,无奈找到目录下的favcion.ico图标,须要在页面援用对立js对立设置,同时须要在配置文件中敞开默认图标,替换spring的小叶子

spring:  mvc:    favicon:      enabled: false
function GetRootPath() {    var loc = window.location,        host = loc.hostname,        protocol = loc.protocol,        port = loc.port ? (':' + loc.port) : '';    var path = location.pathname;    if (path.indexOf('/') === 0) {        path = path.substring(1);    }    var mypath = '/' + path.split('/')[0];    path = (mypath != undefined ? mypath : ('/' + loc.pathname.split('/')[1])) + '/';    var rootPath = protocol + '//' + host + port + path;    return rootPath;}var iconurl = GetRootPath()+"favicon.ico"document.write('<link rel="shortcut icon" href= ' + iconurl + '  rel="external nofollow" rel="external nofollow" ></link>');

我的项目拜访框架动态资源

框架动态资源文件获取

我的项目启动时,因为是援用框架的jar包,咱们须要先找到指定jar包,再将jar包进行解压,找到对应目录将资源拷贝到咱们须要的中央便于拜访

扫描jar包

 public static void copyFrameStaticFile() {        String packageName = "com.haopan.frame";        // 获取包的名字 并进行替换        String packageDirName = packageName.replace('.', '/');        // 定义一个枚举的汇合 并进行循环来解决这个目录下的things        Enumeration<URL> dirs;        try {            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);            // 循环迭代上来            while (dirs.hasMoreElements()) {                // 获取下一个元素                URL url = dirs.nextElement();                // 失去协定的名称                String protocol = url.getProtocol();                if ("jar".equals(protocol)) {                    // 如果是jar包文件                    // 定义一个JarFile                    JarFile jar;                    try {                        // 获取jar                        jar = ((JarURLConnection) url.openConnection()).getJarFile();                        String templateDecompressPath = "tempfiles/decompress/" + CommonUtil.getNewGuid() + "/";                        File targetFile = new File(templateDecompressPath);                        if (!targetFile.exists()) {                            targetFile.mkdirs();                        }                        decompressJarFile(jar, templateDecompressPath);                        String frameStaticPath = templateDecompressPath + "public/";                        File frameStaticFile = new File(frameStaticPath);                        if (frameStaticFile.exists()) {                            String copyTargetPath = "static/";                            File copyTargetFolder = new File(copyTargetPath);                            if (copyTargetFolder.exists()) {                                FileUtil.deleteDirectory(copyTargetPath);                            }                            copyTargetFolder.mkdirs();                            FileUtil.copyFileFolder(frameStaticPath, copyTargetPath);                        }                        FileUtil.deleteDirectory(templateDecompressPath);                        System.out.println("框架动态文件复制结束!");                    } catch (IOException e) {                        e.printStackTrace();                    }                }            }        } catch (IOException e) {            e.printStackTrace();        }    }

解压jar包

对JarFile中的JarEntry对象进行遍历,判断是文件还是目录分类解决

public static synchronized void decompressJarFile(JarFile jf,String outputPath){        if (!outputPath.endsWith(File.separator)) {            outputPath += File.separator;        }        File dir = new File(outputPath);        if (!dir.exists()) {            dir.mkdirs();        }        try{            for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();) {                JarEntry je = (JarEntry) e.nextElement();                String outFileName = outputPath + je.getName();                File f = new File(outFileName);                if(je.isDirectory()){                    if(!f.exists()){                        f.mkdirs();                    }                }else{                    File pf = f.getParentFile();                    if(!pf.exists()){                        pf.mkdirs();                    }                    InputStream in = jf.getInputStream(je);                    OutputStream out = new BufferedOutputStream(                            new FileOutputStream(f));                    byte[] buffer = new byte[2048];                    int nBytes = 0;                    while ((nBytes = in.read(buffer)) > 0) {                        out.write(buffer, 0, nBytes);                    }                    out.flush();                    out.close();                    in.close();                }            }        }catch(Exception e){            System.out.println("解压"+jf.getName()+"出错---"+e.getMessage());        }finally{            if(jf!=null){                try {                    jf.close();                    File jar = new File(jf.getName());                    if(jar.exists()){                        jar.delete();                    }                } catch (IOException e) {                    e.printStackTrace();                }            }        }    }

拷贝目录到指定地位

public class FileUtil {    private static void copy(String f1, String f2) throws IOException {        File file1=new File(f1);        /*     File file2=new File(f2);*/        File[] flist=file1.listFiles();        for (File f : flist) {            if(f.isFile()){                copyFile(f.getPath(),f2+"/"+f.getName()); //调用复制文件的办法                //System.out.println("原门路["+f.getPath()+"] 被复制门路["+f2+"/"+f.getName()+"]");            }else if(f.isDirectory()){                copyFileFolder(f.getPath(),f2+"/"+f.getName()); //调用复制文件夹的办法                //System.out.println("原门路["+f.getPath()+"] 被复制门路["+f2+"/"+f.getName()+"]");            }        }    }    /**     * 复制文件夹     * @throws IOException     */    public static void copyFileFolder(String sourceFolderPath,String targetFolderPath) throws IOException {        //创立文件夹        File file=new File(targetFolderPath);        if(!file.exists()){            file.mkdirs();        }        copy(sourceFolderPath,targetFolderPath);    }    /**     * 复制文件     * @throws IOException     */    public static void copyFile(String sourceFilePath, String tagretFilePath) throws IOException {        try {            InputStream in = new FileInputStream(sourceFilePath);            OutputStream out = new FileOutputStream(tagretFilePath);            byte[] buffer = new byte[2048];            int nBytes = 0;            while ((nBytes = in.read(buffer)) > 0) {                out.write(buffer, 0, nBytes);            }            out.flush();            out.close();            in.close();        } catch (FileNotFoundException e) {            e.printStackTrace();        }    }    public static boolean delete(String fileName) {        File file =new File(fileName);        if (!file.exists()) {            //System.out.println("删除文件失败:" + fileName +"不存在!");            return false;        }else {            if (file.isFile())                return deleteFile(fileName);            else                return deleteDirectory(fileName);        }    }    /**     * 删除单个文件     *     * @param fileName:要删除的文件的文件名     * @return 单个文件删除胜利返回true,否则返回false     */    public static boolean deleteFile(String fileName) {        File file =new File(fileName);        // 如果文件门路所对应的文件存在,并且是一个文件,则间接删除        if (file.exists() && file.isFile()) {            if (file.delete()) {                //System.out.println("删除单个文件" + fileName +"胜利!");                return true;            }else {                //System.out.println("删除单个文件" + fileName +"失败!");                return false;            }        }else {            //System.out.println("删除单个文件失败:" + fileName +"不存在!");            return false;        }    }    /**     * 删除目录及目录下的文件     *     * @param dir:要删除的目录的文件门路     * @return 目录删除胜利返回true,否则返回false     */    public static boolean deleteDirectory(String dir) {        // 如果dir不以文件分隔符结尾,主动增加文件分隔符        if (!dir.endsWith(File.separator))            dir = dir + File.separator;        File dirFile =new File(dir);        // 如果dir对应的文件不存在,或者不是一个目录,则退出        if ((!dirFile.exists()) || (!dirFile.isDirectory())) {            System.out.println("删除目录失败:" + dir +"不存在!");            return false;        }        boolean flag =true;        // 删除文件夹中的所有文件包含子目录        File[] files = dirFile.listFiles();        for (int i =0; i < files.length; i++) {            // 删除子文件            if (files[i].isFile()) {                flag = deleteFile(files[i].getAbsolutePath());                if (!flag)                    break;            }            // 删除子目录            else if (files[i].isDirectory()) {                flag = deleteDirectory(files[i].getAbsolutePath());                if (!flag)                    break;            }        }        if (!flag) {            //System.out.println("删除目录失败!");            return false;        }        // 删除当前目录        if (dirFile.delete()) {            //System.out.println("删除目录" + dir +"胜利!");            return true;        }else {            return false;        }    }}

内部动态资源拜访与优先级设置

设置yml文件中的static-locations配置项,多个应用,隔开,同时指定程序为拜访的优先级

spring:  resources:    static-locations: classpath:static/,classpath:public/,file:static/

最终目录结构图如下,框架局部齐全是我的项目启动时主动解压拷贝的,我的项目局部则是由具体我的项目进行开发,我的项目局部也能够很不便的进行框架局部性能重构,例如登录页,主页面批改等,本形式反对jar包和war包两种打包形式