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文件,不用本地文件改了再传到服务器,只用在本地修改即可。用于开发阶段。