前言

在单页面应用(SPA,Single Page Application)开发中,点击不同的菜单,通常需要动态获取其对应的Html页面代码,返回给前端,再将这一整块append到主框架页面的某个指定div中。所以,Java如何获取Html代码呢?

开发环境中

如在Eclipse中开发一个基于SpringBootSPA,每次右键-Run As/Debug As主类来运行项目,那如何找到某指定页面的html文件呢?如下(字节流):

/**
 * 获取对应pageName的html内容(本地eclipse里直接run)<br>
 * 字节流方式读取文件,可能读断一个中文字符,导致乱码
 */
@Deprecated
private String getHtmlByPageName(String pageName) {
    URL url = this.getClass().getClassLoader().getResource("templates/" + pageName + ".html");
    LOGGER.info("pageName : {} - {}", pageName, url);
    // File f = new
    // File("E:\\code_svn\\srp_trunk\\target\\classes\\templates\\404.html");
    StringBuffer sb = new StringBuffer();
    BufferedInputStream bis = null;
    try {
        File f = new File(url.toURI());
        FileInputStream fis = new FileInputStream(f);
        bis = new BufferedInputStream(fis);
        int len = 0;
        byte[] temp = new byte[1024];
        while ((len = bis.read(temp)) != -1) {
            sb.append(new String(temp, 0, len));
        }
        LOGGER.debug("page content:\n{}...", sb.toString().substring(0, 200));
    } catch (Exception e) {
        LOGGER.error("Error occurred, cause by: ", e);
    } finally {
        if (bis != null) {
            try {
                bis.close();
            } catch (IOException e) {
                LOGGER.error("Error occurred, cause by: ", e);
            }
        }
    }
    return sb.toString();
}

注意事项

采用字节流读取文本,容易读断一个完整的汉字,从而造成页面部分汉字乱码,如��。

所以,以字符流方式读取更佳,如下(字符流):

/**
 * 获取对应pageName的html内容(本地eclipse里直接run)<br>
 * 字符流方式读取文件
 */
private String getHtmlByPageName1(String pageName) {
    URL url = this.getClass().getClassLoader().getResource("templates/" + pageName + ".html");
    LOGGER.info("pageName : {} - {}", pageName, url);
    // File f = new
    // File("E:\\code_svn\\srp_trunk\\target\\classes\\templates\\404.html");
    StringBuffer sb = new StringBuffer();
    BufferedInputStream bis = null;
    try {
        File f = new File(url.toURI());
        FileInputStream fis = new FileInputStream(f);
        bis = new BufferedInputStream(fis);
        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
        String s = "";
        while ((s = br.readLine()) != null) {
            sb.append(s).append("\n");
        }
        LOGGER.debug("page content:\n{}...", sb.toString().substring(0, 200));
    } catch (Exception e) {
        LOGGER.error("Error occurred, cause by: ", e);
    } finally {
        if (bis != null) {
            try {
                bis.close();
            } catch (IOException e) {
                LOGGER.error("Error occurred, cause by: ", e);
            }
        }
    }
    return sb.toString();
}

 

生产环境中

在生产环境中,不同于开发环境,我们经常需要java -jar来运行目标jar包,那在SpringBoot打出来的jar包中,如何找到某指定页面的html文件呢?如下(字符流):

/**
 * 获取对应pageName的html内容(生产环境java -jar直接run)
 */
private String getHtmlByPageName2(String pageName) throws IOException {
    // /BOOT-INF/classes/templates/dashboard.html
    String path = "/BOOT-INF/classes/templates/" + pageName + ".html";
    // 返回读取指定资源的输入流
    InputStream is = this.getClass().getResourceAsStream(path);
    BufferedReader br = new BufferedReader(new InputStreamReader(is));
    String s = "";
    StringBuffer sb = new StringBuffer();
    while ((s = br.readLine()) != null) {
        sb.append(s).append("\n");
    }
    return sb.toString();
}

注意每次readLine后都别忘了append换行符,否则会导致html中的<script>元素里的JavaScript,将从第一处双斜杠注释的地方往后,都作为注释内容的一部分(因为整个html都是长长一整行),最终很神奇地发现为何某些JavaScript代码没运行。

所以,我们需要在代码中,判断当前程序所处的环境是开发环境还是生产环境,以进入不同的获取页面代码的逻辑。

SpringBoot多环境配置

一般可放置多个application-{profile}.properties文件,并在application.properties中设置一默认环境,如下:

spring.profiles.active=test

要想改变运行环境,可修改上述配置为dev或其他,亦可通过命令行参数的方式设置,如下:

java -jar xxx.jar --spring.profiles.active=dev

判断SpringBoot运行环境

Java如何判断SpringBoot的运行环境呢?如下:

import java.util.Locale;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextUtil implements ApplicationContextAware {

    private static ApplicationContext context = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

    // 传入线程中
    public static <T> T getBean(String beanName) {
        return (T) context.getBean(beanName);
    }

    // 国际化使用
    public static String getMessage(String key) {
        return context.getMessage(key, null, Locale.getDefault());
    }

    /// 获取当前环境
    public static String getActiveProfile() {
        return context.getEnvironment().getActiveProfiles()[0];
    }
}

因此, 对于Java根据SpringBoot运行环境的不同,而走不同的getHtmlByPageName逻辑,如下:

String profile = SpringContextUtil.getActiveProfile();
if ("dev".equals(profile)) {
    return getHtmlByPageName1(pageName);
} else {
    return getHtmlByPageName2(pageName);
}

以上。