扩展webx资源装载器之HttpResourceLoader(一):简单实现

webx是一个开源的web框架,主页地址:http://www.openwebx.org/。这里我们主要说下使用http协议对网络中任意资源进行装载,来增强webx资源装载的功能。

用webx官网的mvn命令,生成tutorial1项目,里面webx的pom如下:

        ...
       <webx-version>3.2.4</webx-version>
        ...
        <dependency>
            <groupId>com.alibaba.citrus</groupId>
            <artifactId>citrus-webx-all</artifactId>
        </dependency>
        ...

这个版本里,webx的resourceLoader有2种扩展:

[res-loaders:webapp-loader /]:通过servletContext.getResource(resourceName)来获取资源。
[res-loaders:classpath-loader /]:通过classLoader.getResource(resourceName)来获取资源。
[res-loaders:super-loader/]:通过resource.xml里配置的资源别名,结合配置的资源加载器,来进行资源加载。这种是在前面2种的基础之上。

基于springExt,这里扩展点是res-loaders,捐献是webapp-loader,classpath-loader和super-loader。

新增一个http-loader,即[res-loaders:http-loader/],具体的捐献实现和配置在后面会再进行介绍,。

HttpResourceLoader简单类实现:

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;
import javax.servlet.ServletContext;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.runtime.RuntimeConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.context.WebApplicationContext;

import com.alibaba.citrus.service.resource.Resource;
import com.alibaba.citrus.service.resource.ResourceLoader;
import com.alibaba.citrus.service.resource.ResourceLoaderContext;
import com.alibaba.citrus.service.resource.ResourceLoadingOption;
import com.alibaba.citrus.service.resource.ResourceLoadingService;
import com.alibaba.citrus.service.resource.support.InputStreamResource;
import com.alibaba.citrus.service.template.TemplateService;
import com.alibaba.citrus.service.velocity.impl.VelocityEngineImpl;
import com.alibaba.citrus.service.velocity.impl.VelocityRuntimeInstance;

import static org.springframework.web.context.WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;


/**
 * 
 * @author yankai913@gmail.com
 * @date 2016年4月11日
 */
public class HttpResourceLoader implements ResourceLoader, ServletContextAware,
        ApplicationListener<ContextRefreshedEvent> {

    private static final Logger logger = LoggerFactory.getLogger(HttpResourceLoader.class);

    String resourceRemoteHost = "http://localhost:6666";

    String vmEncoding = "UTF-8";

    String[] additionalPathArr = new String[] { "", "/common" };

    ApplicationContext applicationContext;

    ServletContext servletContext;


    @Override
    public void init(ResourceLoadingService resourceLoadingService) {

    }


    @Override
    public Resource getResource(ResourceLoaderContext context, Set<ResourceLoadingOption> options) {
        String resourceName = context.getResourceName();

        try {

            for (String additionalPath : additionalPathArr) {

                String remoteFileURL = this.resourceRemoteHost + additionalPath + resourceName;

                HttpUtils.HttpResult httpRequest =
                        HttpUtils.httpGet(remoteFileURL, null, null, vmEncoding, 3000);

                if (httpRequest.code == HttpURLConnection.HTTP_OK) {
                    String htmlText = httpRequest.content;
                    wrapHtmlContent(resourceName, htmlText);
                    ByteArrayInputStream bais = new ByteArrayInputStream(htmlText.getBytes(vmEncoding));
                    InputStreamResource resource = new PrototypeInputStreamResource(bais);
                    return resource;
                } else {
                    continue;
                }
            }

            throw new IOException("http get template failed! resourceName=" + resourceName);
        } catch (Exception e) {
            logger.error("http get template failed! resourceName=" + resourceName + e.getMessage(), e);
        }
        return null;
    }


    void wrapHtmlContent(String resourceName, String htmlText) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timestamp = sdf.format(new Date());

        String content = "<!-- http get " + resourceName + "\t" + timestamp + " start -->\n";
        content = content + htmlText;
        content = "\n<!-- http get " + resourceName + "\t" + timestamp + " end -->\n";
    }


    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }


    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        if (event.getApplicationContext().getParent() == null) {
            WebApplicationContext wac =
                    (WebApplicationContext) servletContext
                        .getAttribute(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

            TemplateService ts = (TemplateService) wac.getBean("templateService");
            VelocityEngineImpl ve = (VelocityEngineImpl) ts.getTemplateEngine("vm");
            VelocityRuntimeInstance vri = (VelocityRuntimeInstance) ve.getRuntimeServices();
            vmEncoding = StringUtils.trimToNull((String) vri.getProperty(RuntimeConstants.INPUT_ENCODING));
        }
    }

    // 保证实时数据,不缓存。
    static class PrototypeInputStreamResource extends InputStreamResource {

        public PrototypeInputStreamResource(InputStream stream) {
            super(stream);
        }


        public long lastModified() {
            return System.currentTimeMillis();
        }
    }
}

remoteResourceHost:资源所在的地方,例如,vm目录放在本地,nginx指向vm目录,nginx作为文件服务器提供文件资源服务。
httpUtils是一个http工具类。

这样一个扩展好处就是,服务器部署某个应用后,配置vm目录指向本地,如果需要修改vm看效果,不用重启应用,不用登录服务器修改vm文件,不用本地文件改了再传到服务器,只用在本地修改即可。用于开发阶段。

此条目发表在编程语言分类目录,贴了, 标签。将固定链接加入收藏夹。