diff --git a/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/pom.xml b/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/pom.xml
index 3b3e319c..acef7ecc 100644
--- a/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/pom.xml
+++ b/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/pom.xml
@@ -24,5 +24,9 @@
org.nutz
nutzboot-starter-shiro
+
+ org.nutz
+ nutzboot-starter-swagger
+
\ No newline at end of file
diff --git a/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/java/io/nutz/demo/simple/MainLauncher.java b/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/java/io/nutz/demo/simple/MainLauncher.java
index 855db089..22a26905 100644
--- a/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/java/io/nutz/demo/simple/MainLauncher.java
+++ b/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/java/io/nutz/demo/simple/MainLauncher.java
@@ -2,18 +2,10 @@ package io.nutz.demo.simple;
import org.nutz.boot.NbApp;
import org.nutz.ioc.loader.annotation.IocBean;
-import org.nutz.mvc.annotation.At;
-import org.nutz.mvc.annotation.Ok;
@IocBean
public class MainLauncher {
- @Ok("raw")
- @At("/time/now")
- public long now() {
- return System.currentTimeMillis();
- }
-
public static void main(String[] args) throws Exception {
new NbApp().setPrintProcDoc(true).run();
}
diff --git a/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/java/io/nutz/demo/simple/module/TimeModule.java b/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/java/io/nutz/demo/simple/module/TimeModule.java
new file mode 100644
index 00000000..e00dd533
--- /dev/null
+++ b/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/java/io/nutz/demo/simple/module/TimeModule.java
@@ -0,0 +1,28 @@
+package io.nutz.demo.simple.module;
+
+
+import org.nutz.ioc.impl.PropertiesProxy;
+import org.nutz.ioc.loader.annotation.*;
+import org.nutz.mvc.annotation.*;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+@Api("time")
+@At("/time")
+@IocBean(create="init", depose="depose")
+public class TimeModule {
+
+ @Inject
+ protected PropertiesProxy conf;
+
+ @ApiOperation(value = "获取当前毫秒数", notes = "服务器端的时间", httpMethod="GET", response=Long.class)
+ @At
+ @Ok("raw")
+ public long now() {
+ return System.currentTimeMillis();
+ }
+
+ public void init() {}
+ public void depose() {}
+
+}
diff --git a/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/resources/log4j.properties b/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/resources/log4j.properties
index 50a16139..874668bb 100644
--- a/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/resources/log4j.properties
+++ b/nutzboot-demo/nutzboot-demo-simple/nutzboot-demo-simple-tomcat/src/main/resources/log4j.properties
@@ -1,8 +1,7 @@
log4j.rootLogger=debug,Console
log4j.logger.org.eclipse.jetty=info
-log4j.logger.org.apache.tomcat=info
-log4j.logger.org.apache.catalina=info
+log4j.logger.org.apache=info
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
diff --git a/nutzboot-starter/nutzboot-starter-tomcat/src/main/java/org/nutz/boot/starter/tomcat/TomcatStarter.java b/nutzboot-starter/nutzboot-starter-tomcat/src/main/java/org/nutz/boot/starter/tomcat/TomcatStarter.java
index 8851a978..3a3cea91 100644
--- a/nutzboot-starter/nutzboot-starter-tomcat/src/main/java/org/nutz/boot/starter/tomcat/TomcatStarter.java
+++ b/nutzboot-starter/nutzboot-starter-tomcat/src/main/java/org/nutz/boot/starter/tomcat/TomcatStarter.java
@@ -4,10 +4,15 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.net.JarURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
+import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
import javax.servlet.ServletContext;
@@ -23,8 +28,12 @@ import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardThreadExecutor;
import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.webresources.AbstractResource;
+import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.EmptyResourceSet;
+import org.apache.catalina.webresources.FileResource;
import org.apache.catalina.webresources.StandardRoot;
+import org.apache.juli.logging.LogFactory;
import org.nutz.boot.annotation.PropDoc;
import org.nutz.boot.starter.ServerFace;
import org.nutz.boot.starter.servlet3.AbstractServletContainerStarter;
@@ -33,6 +42,8 @@ import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Encoding;
import org.nutz.lang.Files;
import org.nutz.lang.Lang;
+import org.nutz.lang.Streams;
+import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
@@ -52,21 +63,24 @@ public class TomcatStarter extends AbstractServletContainerStarter implements Se
protected static final String PRE = "tomcat.";
- @PropDoc(group = "tomcat", value = "监听的ip地址", defaultValue = "0.0.0.0")
+ @PropDoc(value = "监听的ip地址", defaultValue = "0.0.0.0")
public static final String PROP_HOST = PRE + "host";
- @PropDoc(group = "tomcat", value = "监听的端口", defaultValue = "8080", type = "int")
+ @PropDoc(value = "监听的端口", defaultValue = "8080", type = "int")
public static final String PROP_PORT = PRE + "port";
- @PropDoc(group = "tomcat", value = "上下文路径")
+ @PropDoc(value = "上下文路径")
public static final String PROP_CONTEXT_PATH = PRE + "contextPath";
@PropDoc(value = "Session空闲时间,单位分钟", defaultValue = "30", type = "int")
public static final String PROP_SESSION_TIMEOUT = "web.session.timeout";
- @PropDoc(group = "tomcat", value = "静态文件路径", defaultValue = "static")
+ @PropDoc(value = "静态文件路径", defaultValue = "static")
public static final String PROP_STATIC_PATH = PRE + "staticPath";
+ @PropDoc(value = "本地静态文件路径")
+ public static final String PROP_STATIC_PATH_LOCAL = PRE + "staticPathLocal";
+
@PropDoc(value = "POST表单最大尺寸", defaultValue = "64 * 1024 * 1024")
public static final String PROP_MAX_POST_SIZE = PRE + "maxPostSize";
@@ -170,7 +184,27 @@ public class TomcatStarter extends AbstractServletContainerStarter implements Se
this.tomcatContext.setSessionTimeout(getSessionTimeout() / 60);
this.tomcatContext.addLifecycleListener(new StoreMergedWebXmlListener());
StandardRoot sr = new StandardRoot(this.tomcatContext);
- sr.addPreResources(new ClasspathResourceSet(sr, "static/"));
+ if (!Strings.isBlank(conf.get(PROP_STATIC_PATH_LOCAL))) {
+ File local = new File(conf.get(PROP_STATIC_PATH_LOCAL));
+ if (local.exists()) {
+ log.debug("add local path=" + local.getAbsolutePath());
+ sr.addPreResources(new DirResourceSet(sr, "/", local.getAbsolutePath(), "/"));
+ }
+ else {
+ log.debug("local path=" + local + " not exists, skip.");
+ }
+ }
+ for (String resourcePath : getResourcePaths()) {
+ if ("static".equals(resourcePath) || "static/".equals(resourcePath)) {
+ if (new File(resourcePath).exists()) {
+ sr.addPreResources(new DirResourceSet(sr, "/", new File(resourcePath).getAbsolutePath(), "/"));
+ }
+ sr.addPreResources(new ClasspathResourceSet(sr, "static"));
+ }
+ else if ("webapp".equals(resourcePath) || "webapp/".equals(resourcePath)) {
+ sr.addPreResources(new ClasspathResourceSet(sr, "webapp"));
+ }
+ }
this.tomcatContext.setResources(sr);
try {
@@ -278,11 +312,16 @@ public class TomcatStarter extends AbstractServletContainerStarter implements Se
public class ClasspathResourceSet extends EmptyResourceSet {
+ protected org.apache.juli.logging.Log LOG = LogFactory.getLog(ClasspathResourceSet.class);
+
protected String prefix;
+ private WebResourceRoot root;
+
public ClasspathResourceSet(WebResourceRoot root, String prefix) {
super(root);
this.prefix = prefix;
+ this.root = root;
}
public boolean isReadOnly() {
@@ -294,12 +333,122 @@ public class TomcatStarter extends AbstractServletContainerStarter implements Se
}
public WebResource getResource(String path) {
+ if (path.endsWith("/"))
+ return super.getResource(path);
+ URL url = appContext.getClassLoader().getResource(prefix + path);
+ if (url == null) {
+ return super.getResource(path);
+ }
+ String ext = url.toExternalForm();
+ log.debug("Resource " + ext);
+ if (ext.startsWith("file:")) {
+ return new FileResource(root, path, new File(url.getFile()), true, null);
+ }
+ if (ext.startsWith("jar:")) {
+ try {
+ JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
+ JarEntry en = jarConnection.getJarEntry();
+ JarFile jar = jarConnection.getJarFile();
+ return new AbstractResource(root, prefix) {
+ public boolean isVirtual() {
+ return false;
+ }
+
+ public boolean isFile() {
+ return !en.isDirectory();
+ }
+
+ public boolean isDirectory() {
+ return en.isDirectory();
+ }
+
+ public URL getURL() {
+ return url;
+ }
+
+ public String getName() {
+ return en.getName();
+ }
+
+ public Manifest getManifest() {
+ try {
+ return jar.getManifest();
+ }
+ catch (IOException e) {
+ return null;
+ }
+ }
+
+ public long getLastModified() {
+ return en.getTime();
+ }
+
+ public long getCreation() {
+ return en.getCreationTime().toMillis();
+ }
+
+ public long getContentLength() {
+ return en.getSize();
+ }
+
+ public byte[] getContent() {
+ try {
+ return Streams.readBytes(getInputStream());
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public URL getCodeBase() {
+ return getBaseUrl();
+ }
+
+ public Certificate[] getCertificates() {
+ return null;
+ }
+
+ public String getCanonicalPath() {
+ return null;
+ }
+
+ public boolean exists() {
+ return true;
+ }
+
+ public boolean delete() {
+ return false;
+ }
+
+ public boolean canRead() {
+ return isFile();
+ }
+
+ protected org.apache.juli.logging.Log getLog() {
+ return LOG;
+
+ }
+
+ protected InputStream doGetInputStream() {
+ try {
+ return url.openStream();
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ };
+ }
+ catch (IOException e) {
+ log.debug("error when reading jar file?", e);
+ }
+ }
return super.getResource(path);
}
@Override
public boolean getStaticOnly() {
- return true;
+ return "static".equals(prefix);
}
}