diff --git a/blade-core/src/main/java/com/hellokaton/blade/Blade.java b/blade-core/src/main/java/com/hellokaton/blade/Blade.java index b7dafc70..7a45d4d3 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/Blade.java +++ b/blade-core/src/main/java/com/hellokaton/blade/Blade.java @@ -30,14 +30,12 @@ import com.hellokaton.blade.mvc.hook.WebHook; import com.hellokaton.blade.mvc.http.HttpMethod; import com.hellokaton.blade.mvc.http.session.SessionManager; -import com.hellokaton.blade.mvc.route.DynamicMapping; import com.hellokaton.blade.mvc.route.RouteMatcher; -import com.hellokaton.blade.mvc.route.mapping.dynamic.RegexMapping; -import com.hellokaton.blade.mvc.route.mapping.dynamic.TrieMapping; import com.hellokaton.blade.mvc.ui.template.DefaultEngine; import com.hellokaton.blade.mvc.ui.template.TemplateEngine; import com.hellokaton.blade.options.CorsOptions; import com.hellokaton.blade.options.HttpOptions; +import com.hellokaton.blade.options.StaticOptions; import com.hellokaton.blade.server.NettyServer; import com.hellokaton.blade.server.Server; import lombok.AccessLevel; @@ -54,6 +52,8 @@ import java.util.function.Consumer; import java.util.stream.Collectors; +import static com.hellokaton.blade.mvc.BladeConst.ENV_KEY_FAVICON_DIR; + /** * Blade Core *

@@ -78,13 +78,6 @@ public class Blade { */ private final Set packages = new LinkedHashSet<>(BladeConst.PLUGIN_PACKAGE_NAME); - /** - * All static resource URL prefixes, - * defaults to "/favicon.ico", "/robots.txt", "/static/", "/upload/", "/webjars/", - * which are located under classpath - */ - private final Set statics = new HashSet<>(BladeConst.DEFAULT_STATICS); - /** * The default IOC container implementation */ @@ -121,7 +114,8 @@ public class Blade { private final RouteMatcher routeMatcher = new RouteMatcher(); private CorsOptions corsOptions = null; - private final HttpOptions httpOptions = HttpOptions.create(); + private HttpOptions httpOptions = HttpOptions.create(); + private StaticOptions staticOptions = StaticOptions.create(); /** * Blade environment, which stores the parameters of the application.properties configuration file @@ -280,6 +274,17 @@ public TemplateEngine templateEngine() { return this.templateEngine; } + /** + * setting favicon dir, default is /static + * + * @param faviconDir favicon dir + * @return blade instance + */ + public Blade faviconDir(String faviconDir) { + this.setEnv(ENV_KEY_FAVICON_DIR, faviconDir); + return this; + } + /** * Get RouteMatcher * @@ -294,6 +299,21 @@ public Blade http(Consumer consumer) { return this; } + public Blade http(HttpOptions httpOptions) { + this.httpOptions = httpOptions; + return this; + } + + public Blade staticOptions(Consumer consumer) { + consumer.accept(this.staticOptions); + return this; + } + + public Blade staticOptions(StaticOptions staticOptions) { + this.staticOptions = staticOptions; + return this; + } + public Blade cors(CorsOptions corsOptions) { this.corsOptions = corsOptions; return this; @@ -307,6 +327,10 @@ public HttpOptions httpOptions() { return this.httpOptions; } + public StaticOptions staticOptions() { + return this.staticOptions; + } + /** * Register bean to ioc container * @@ -329,29 +353,6 @@ public Blade register(@NonNull Class cls) { return this; } - /** - * Add multiple static resource file - * the default provides the static, upload - * - * @param folders static resource directory - * @return blade - */ - public Blade addStatics(@NonNull String... folders) { - this.statics.addAll(Arrays.asList(folders)); - return this; - } - - /** - * Set whether to show the file directory, default doesn't show - * - * @param fileList show the file directory - * @return blade - */ - public Blade showFileList(boolean fileList) { - this.environment.set(BladeConst.ENV_KEY_STATIC_LIST, fileList); - return this; - } - /** * Get ioc bean * @@ -415,16 +416,6 @@ public Class bootClass() { return this.bootClass; } - /** - * Get blade statics list. - * e.g: "/favicon.ico", "/robots.txt", "/static/", "/upload/", "/webjars/" - * - * @return return statics - */ - public Set getStatics() { - return this.statics; - } - /** * When set to start blade scan packages * @@ -686,8 +677,8 @@ public Blade start(Class mainCls, String... args) { try { //TODO: add support for Create and Delete if (event.equals(StandardWatchEventKinds.ENTRY_MODIFY)) { - Path destPath = FileChangeDetector.getDestPath(filePath, environment); - Files.copy(filePath, destPath, StandardCopyOption.REPLACE_EXISTING); + Path destPath = FileChangeDetector.getDestPath(filePath, environment, staticOptions); + Files.copy(filePath, Objects.requireNonNull(destPath), StandardCopyOption.REPLACE_EXISTING); } } catch (IOException e) { log.error("Exception when trying to copy updated file"); diff --git a/blade-core/src/main/java/com/hellokaton/blade/kit/reload/FileChangeDetector.java b/blade-core/src/main/java/com/hellokaton/blade/kit/reload/FileChangeDetector.java index 4f018c1e..45e0c9f9 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/kit/reload/FileChangeDetector.java +++ b/blade-core/src/main/java/com/hellokaton/blade/kit/reload/FileChangeDetector.java @@ -2,12 +2,16 @@ import com.hellokaton.blade.Environment; import com.hellokaton.blade.mvc.BladeConst; +import com.hellokaton.blade.options.StaticOptions; import lombok.extern.slf4j.Slf4j; import java.io.IOException; import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.function.BiConsumer; import java.util.stream.Collectors; @@ -19,18 +23,18 @@ public class FileChangeDetector { private final WatchService watcher; private final Map pathMap = new HashMap<>(); - public FileChangeDetector(String dirPath) throws IOException{ + public FileChangeDetector(String dirPath) throws IOException { watcher = FileSystems.getDefault().newWatchService(); registerAll(Paths.get(dirPath)); } - private void register(Path dir) throws IOException{ + private void register(Path dir) throws IOException { WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY); - pathMap.put(key,dir); + pathMap.put(key, dir); } - private void registerAll(Path dir) throws IOException{ - Files.walkFileTree(dir, new SimpleFileVisitor(){ + private void registerAll(Path dir) throws IOException { + Files.walkFileTree(dir, new SimpleFileVisitor() { @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { register(dir); @@ -39,22 +43,22 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th }); } - public void processEvent(BiConsumer, Path> processor){ - for(;;){ + public void processEvent(BiConsumer, Path> processor) { + for (; ; ) { WatchKey key; - try{ + try { key = watcher.take(); - }catch (InterruptedException e) { + } catch (InterruptedException e) { return; } Path dir = pathMap.get(key); - for (WatchEvent event: key.pollEvents()){ + for (WatchEvent event : key.pollEvents()) { WatchEvent.Kind kind = event.kind(); - Path filePath = dir.resolve(((WatchEvent)event).context()); + Path filePath = dir.resolve(((WatchEvent) event).context()); - if(Files.isDirectory(filePath)) continue; - log.info("File {} changes detected!",filePath.toString()); + if (Files.isDirectory(filePath)) continue; + log.info("File {} changes detected!", filePath.toString()); //copy updated files to target processor.accept(kind, filePath); } @@ -62,23 +66,18 @@ public void processEvent(BiConsumer, Path> processor){ } } - public static Path getDestPath(Path src, Environment env){ - String templateDir = env.get(BladeConst.ENV_KEY_TEMPLATE_PATH,"/templates"); - Optional staticDir = env.get(BladeConst.ENV_KEY_STATIC_DIRS); + public static Path getDestPath(Path src, Environment env, StaticOptions staticOptions) { + String templateDir = env.get(BladeConst.ENV_KEY_TEMPLATE_PATH, "/templates"); List templateOrStaticDirKeyword = new ArrayList<>(); templateOrStaticDirKeyword.add(templateDir); - if(staticDir.isPresent()){ - templateOrStaticDirKeyword.addAll(Arrays.asList(staticDir.get().split(","))); - }else{ - templateOrStaticDirKeyword.addAll(BladeConst.DEFAULT_STATICS); - } + templateOrStaticDirKeyword.addAll(staticOptions.getPaths()); - List result = templateOrStaticDirKeyword.stream().filter(dir -> src.toString().indexOf(dir)!=-1).collect(Collectors.toList()); - if(result.size()!=1){ + List result = templateOrStaticDirKeyword.stream().filter(dir -> src.toString().contains(dir)).collect(Collectors.toList()); + if (result.size() != 1) { log.info("Cannot get dest dir"); - return null; + return null; } - String key = (String)result.get(0); + String key = result.get(0); log.info(BladeConst.CLASSPATH + src.toString().substring(src.toString().indexOf(key))); return Paths.get(BladeConst.CLASSPATH + src.toString().substring(src.toString().indexOf(key))); } diff --git a/blade-core/src/main/java/com/hellokaton/blade/mvc/BladeConst.java b/blade-core/src/main/java/com/hellokaton/blade/mvc/BladeConst.java index a72b7b79..5919b71f 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/mvc/BladeConst.java +++ b/blade-core/src/main/java/com/hellokaton/blade/mvc/BladeConst.java @@ -17,7 +17,6 @@ import com.hellokaton.blade.kit.StringKit; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -38,8 +37,6 @@ public interface BladeConst { String INTERNAL_SERVER_ERROR_HTML = "

500 Internal Server Error


"; String DEFAULT_THREAD_NAME = "_(:3」∠)_"; List PLUGIN_PACKAGE_NAME = new ArrayList<>(Collections.singletonList("com.hellokaton.blade.plugin")); - List DEFAULT_STATICS = new ArrayList<>( - Arrays.asList("/favicon.ico", "/robots.txt", "/static", "/upload", "/webjars/")); String PROP_NAME = "classpath:application.properties"; @@ -53,17 +50,17 @@ public interface BladeConst { String ENV_KEY_TASK_THREAD_COUNT = "app.task.thread-count"; String ENV_KEY_CONTEXT_PATH = "app.context-path"; String ENV_KEY_REQUEST_LOG = "app.request-log"; + String ENV_KEY_FAVICON_DIR = "app.favicon-dir"; String ENV_KEY_HTTP_MAX_CONTENT = "http.max-content-size"; String ENV_KEY_GZIP_ENABLE = "http.gzip.enabled"; String ENV_KEY_SESSION_ENABLED = "http.session.enabled"; String ENV_KEY_SESSION_KEY = "http.session.key"; String ENV_KEY_SESSION_TIMEOUT = "http.session.timeout"; - String ENV_KEY_HTTP_CACHE_TIMEOUT = "http.cache.timeout"; String ENV_KEY_HTTP_REQUEST_COST = "http.request.cost"; String ENV_KEY_PAGE_404 = "mvc.view.404"; String ENV_KEY_PAGE_500 = "mvc.view.500"; - String ENV_KEY_STATIC_DIRS = "mvc.statics"; - String ENV_KEY_STATIC_LIST = "mvc.statics.show-list"; + String ENV_KEY_STATIC_LIST = "static.show-list"; + String ENV_KEY_STATIC_CACHE_SECONDS = "static.cache-seconds"; String ENV_KEY_TEMPLATE_PATH = "mvc.template.path"; String ENV_KEY_SERVER_ADDRESS = "server.address"; String ENV_KEY_SERVER_PORT = "server.port"; @@ -88,6 +85,7 @@ public interface BladeConst { String REQUEST_TO_STATIC_ATTR = "_to_static"; + String FAVICON_PATH = "/favicon.ico"; String NEW_LINE = "\r\n"; int BANNER_PADDING = 60; diff --git a/blade-core/src/main/java/com/hellokaton/blade/mvc/route/RouteMatcher.java b/blade-core/src/main/java/com/hellokaton/blade/mvc/route/RouteMatcher.java index 8863f81c..dd09b35b 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/mvc/route/RouteMatcher.java +++ b/blade-core/src/main/java/com/hellokaton/blade/mvc/route/RouteMatcher.java @@ -159,7 +159,7 @@ public List getBefore(String path) { .flatMap(Collection::stream) .sorted(Comparator.comparingInt(Route::getSort)) .filter(route -> route.getHttpMethod() == HttpMethod.BEFORE) - .filter(route -> matchesPath(route.getPath(), cleanPath)) + .filter(route -> matchesPath(route.getRewritePath(), cleanPath)) .collect(Collectors.toList()); this.giveMatch(path, collect); @@ -178,7 +178,7 @@ public List getAfter(String path) { .flatMap(Collection::stream) .sorted(Comparator.comparingInt(Route::getSort)) .filter(route -> route.getHttpMethod() == HttpMethod.AFTER) - .filter(route -> matchesPath(route.getPath(), cleanPath)) + .filter(route -> matchesPath(route.getRewritePath(), cleanPath)) .collect(Collectors.toList()); this.giveMatch(path, afters); diff --git a/blade-core/src/main/java/com/hellokaton/blade/mvc/ui/ResponseType.java b/blade-core/src/main/java/com/hellokaton/blade/mvc/ui/ResponseType.java index d8b0a7ae..68aaadd8 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/mvc/ui/ResponseType.java +++ b/blade-core/src/main/java/com/hellokaton/blade/mvc/ui/ResponseType.java @@ -12,6 +12,7 @@ public enum ResponseType { XML(HttpConst.CONTENT_TYPE_XML), TEXT(HttpConst.CONTENT_TYPE_TEXT), HTML(HttpConst.CONTENT_TYPE_HTML), + VIEW(HttpConst.CONTENT_TYPE_HTML), STREAM(HttpConst.CONTENT_TYPE_STREAM), PREVIEW(""), ; diff --git a/blade-core/src/main/java/com/hellokaton/blade/options/StaticOptions.java b/blade-core/src/main/java/com/hellokaton/blade/options/StaticOptions.java new file mode 100644 index 00000000..4f3044df --- /dev/null +++ b/blade-core/src/main/java/com/hellokaton/blade/options/StaticOptions.java @@ -0,0 +1,46 @@ +package com.hellokaton.blade.options; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +@Getter +@Setter +public class StaticOptions { + + public static final int DEFAULT_CACHE_SECONDS = 86400 * 30; + public static final Set DEFAULT_STATICS = new HashSet<>( + Arrays.asList("/favicon.ico", "/robots.txt", "/static", "/webjars/")); + + private boolean showList; + private Set paths = DEFAULT_STATICS; + private int cacheSeconds = DEFAULT_CACHE_SECONDS; + + public static StaticOptions create() { + return new StaticOptions(); + } + + public StaticOptions showList() { + this.showList = true; + return this; + } + + public StaticOptions addStatic(String staticPath) { + this.paths.add(staticPath); + return this; + } + + public StaticOptions removeStatic(String staticPath) { + this.paths.remove(staticPath); + return this; + } + + public StaticOptions cacheSeconds(int cacheSeconds) { + this.cacheSeconds = cacheSeconds; + return this; + } + +} diff --git a/blade-core/src/main/java/com/hellokaton/blade/server/HttpServerHandler.java b/blade-core/src/main/java/com/hellokaton/blade/server/HttpServerHandler.java index f584b472..b1435e42 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/server/HttpServerHandler.java +++ b/blade-core/src/main/java/com/hellokaton/blade/server/HttpServerHandler.java @@ -59,10 +59,12 @@ public class HttpServerHandler extends SimpleChannelInboundHandler public static final FastThreadLocal WEB_CONTEXT_THREAD_LOCAL = new FastThreadLocal<>(); - private final StaticFileHandler staticFileHandler = new StaticFileHandler(WebContext.blade()); + static final StaticFileHandler staticFileHandler = new StaticFileHandler(WebContext.blade()); + + static final RouteMatcher routeMatcher = WebContext.blade().routeMatcher(); + private final RouteMethodHandler routeHandler = new RouteMethodHandler(); private final Set notStaticUri = new LRUSet<>(128); - private final RouteMatcher routeMatcher = WebContext.blade().routeMatcher(); private boolean recordRequestLog() { return WebContext.blade().environment() @@ -174,10 +176,16 @@ private boolean isStaticFile(HttpMethod method, String uri) { return false; } - if (WebContext.blade().getStatics().stream().noneMatch(s -> s.equals(uri) || uri.startsWith(s))) { + if (FAVICON_PATH.equals(uri)) { + return true; + } + + Set paths = WebContext.blade().staticOptions().getPaths(); + if (paths.stream().noneMatch(s -> s.equals(uri) || uri.startsWith(s))) { notStaticUri.add(uri); return false; } + return true; } diff --git a/blade-core/src/main/java/com/hellokaton/blade/server/HttpServerInitializer.java b/blade-core/src/main/java/com/hellokaton/blade/server/HttpServerInitializer.java index be8c6f0e..42ebda4e 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/server/HttpServerInitializer.java +++ b/blade-core/src/main/java/com/hellokaton/blade/server/HttpServerInitializer.java @@ -5,6 +5,7 @@ import com.hellokaton.blade.kit.DateKit; import com.hellokaton.blade.options.CorsOptions; import com.hellokaton.blade.options.HttpOptions; +import com.hellokaton.blade.options.StaticOptions; import com.hellokaton.blade.server.decode.FullHttpRequestDecode; import com.hellokaton.blade.server.decode.HttpObjectAggregatorDecode; import io.netty.channel.ChannelInitializer; @@ -34,11 +35,11 @@ public class HttpServerInitializer extends ChannelInitializer { private final HttpServerHandler httpServerHandler; - private final SslContext sslCtx; private CorsConfig corsConfig; private int maxContentSize; private boolean enableGzip; + public static volatile String date = DateKit.gmtDate(LocalDateTime.now()); @@ -46,10 +47,12 @@ public HttpServerInitializer(SslContext sslCtx, Blade blade, ScheduledExecutorSe this.sslCtx = sslCtx; this.httpServerHandler = new HttpServerHandler(); this.mergeCorsConfig(blade.corsOptions()); + this.mergeStaticOptions(blade.staticOptions(), blade.environment()); this.mergeHttpOptions(blade.httpOptions(), blade.environment()); service.scheduleWithFixedDelay(() -> date = DateKit.gmtDate(LocalDateTime.now()), 1000, 1000, TimeUnit.MILLISECONDS); } + @Override protected void initChannel(SocketChannel ch) { ChannelPipeline pipeline = ch.pipeline(); @@ -114,6 +117,24 @@ private void mergeCorsConfig(CorsOptions corsOptions) { this.corsConfig = corsConfigBuilder.build(); } + private void mergeStaticOptions(StaticOptions staticOptions, Environment environment) { + int cacheSeconds = staticOptions.getCacheSeconds(); + if (cacheSeconds > 0 && StaticOptions.DEFAULT_CACHE_SECONDS != cacheSeconds) { + environment.set(ENV_KEY_STATIC_CACHE_SECONDS, cacheSeconds); + } else { + cacheSeconds = environment.getInt(ENV_KEY_STATIC_CACHE_SECONDS, StaticOptions.DEFAULT_CACHE_SECONDS); + staticOptions.setCacheSeconds(cacheSeconds); + } + + boolean showList = staticOptions.isShowList(); + if (showList) { + environment.set(ENV_KEY_STATIC_LIST, true); + } else { + showList = environment.getBoolean(ENV_KEY_STATIC_LIST, Boolean.FALSE); + staticOptions.setShowList(showList); + } + } + private void mergeHttpOptions(HttpOptions httpOptions, Environment environment) { this.maxContentSize = httpOptions.getMaxContentSize(); this.enableGzip = httpOptions.isEnableGzip(); diff --git a/blade-core/src/main/java/com/hellokaton/blade/server/NettyServer.java b/blade-core/src/main/java/com/hellokaton/blade/server/NettyServer.java index 9d09748c..4f131fec 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/server/NettyServer.java +++ b/blade-core/src/main/java/com/hellokaton/blade/server/NettyServer.java @@ -361,11 +361,6 @@ private void initConfig() { // print banner text this.printBanner(); - String statics = environment.get(ENV_KEY_STATIC_DIRS, ""); - if (StringKit.isNotBlank(statics)) { - blade.addStatics(statics.split(",")); - } - String templatePath = environment.get(ENV_KEY_TEMPLATE_PATH, "templates"); if (templatePath.charAt(0) == NettyHttpConst.CHAR_SLASH) { templatePath = templatePath.substring(1); diff --git a/blade-core/src/main/java/com/hellokaton/blade/server/RouteMethodHandler.java b/blade-core/src/main/java/com/hellokaton/blade/server/RouteMethodHandler.java index 25d6b8ab..968ae680 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/server/RouteMethodHandler.java +++ b/blade-core/src/main/java/com/hellokaton/blade/server/RouteMethodHandler.java @@ -44,15 +44,13 @@ /** * Http Server Handler * - * @author biezhi - * 2017/5/31 + * @author hellokaton + * 2022/5/9 */ @Slf4j public class RouteMethodHandler implements RequestHandler { private final RouteMatcher routeMatcher = WebContext.blade().routeMatcher(); - private final StaticFileHandler staticFileHandler = new StaticFileHandler(WebContext.blade()); - private final boolean hasBeforeHook = routeMatcher.hasBeforeHook(); private final boolean hasAfterHook = routeMatcher.hasAfterHook(); @@ -130,7 +128,7 @@ public HttpResponse onView(ViewBody body) { public HttpResponse onStatic(StaticFileBody body) { request.attribute(REQUEST_TO_STATIC_ATTR, body.path()); try { - staticFileHandler.handle(webContext); + HttpServerHandler.staticFileHandler.handle(webContext); } catch (Exception e) { throw new RuntimeException(e); } @@ -231,16 +229,34 @@ private void routeHandle(RouteContext context) { Path path = target.getClass().getAnnotation(Path.class); - boolean responseJson = this.setResponseType(context, path); + ResponseType responseType = ResponseType.EMPTY; + if (null != path && !ResponseType.EMPTY.equals(path.responseType())) { + responseType = path.responseType(); + } + ResponseType routeResponseType = context.route().getResponseType(); + if (null != routeResponseType && !ResponseType.EMPTY.equals(routeResponseType)) { + responseType = routeResponseType; + } + + boolean responseJson = ResponseType.JSON.equals(responseType); + if (responseJson) { + if (!context.isIE()) { + context.contentType(HttpConst.CONTENT_TYPE_JSON); + } else { + context.contentType(HttpConst.CONTENT_TYPE_HTML); + } + } else if (null != responseType && !ResponseType.EMPTY.equals(responseType) + && !ResponseType.PREVIEW.equals(responseType)) { + context.contentType(responseType.contentType()); + } int len = actionMethod.getParameterTypes().length; MethodAccess methodAccess = BladeCache.getMethodAccess(target.getClass()); - Object returnParam = methodAccess.invoke( - target, actionMethod.getName(), len > 0 ? - context.routeParameters() : null); + Object[] args = len > 0 ? context.routeParameters() : null; + Object returnParam = methodAccess.invoke(target, actionMethod.getName(), args); if (null == returnParam) { return; } @@ -250,9 +266,15 @@ private void routeHandle(RouteContext context) { return; } if (returnType == String.class) { - context.body( - ViewBody.of(new ModelAndView(returnParam.toString())) - ); + if (ResponseType.VIEW.equals(responseType)) { + context.body( + ViewBody.of(new ModelAndView(returnParam.toString())) + ); + } else if (ResponseType.HTML.equals(responseType)) { + context.html(returnParam.toString()); + } else if (ResponseType.TEXT.equals(responseType)) { + context.text(returnParam.toString()); + } return; } if (returnType == ModelAndView.class) { @@ -266,29 +288,6 @@ private void routeHandle(RouteContext context) { } } - private boolean setResponseType(RouteContext context, Path path) { - ResponseType responseType = ResponseType.EMPTY; - if (null != path && !ResponseType.EMPTY.equals(path.responseType())) { - responseType = path.responseType(); - } - ResponseType routeResponseType = context.route().getResponseType(); - if (null != routeResponseType && !ResponseType.EMPTY.equals(routeResponseType)) { - responseType = routeResponseType; - } - boolean responseJson = ResponseType.JSON.equals(responseType); - if (responseJson) { - if (!context.isIE()) { - context.contentType(HttpConst.CONTENT_TYPE_JSON); - } else { - context.contentType(HttpConst.CONTENT_TYPE_HTML); - } - } else if (null != routeResponseType && !ResponseType.EMPTY.equals(routeResponseType) - && !ResponseType.PREVIEW.equals(routeResponseType)) { - context.contentType(routeResponseType.contentType()); - } - return responseJson; - } - /** * Invoke WebHook * diff --git a/blade-core/src/main/java/com/hellokaton/blade/server/StaticFileHandler.java b/blade-core/src/main/java/com/hellokaton/blade/server/StaticFileHandler.java index 68e347c6..3d11fcf9 100644 --- a/blade-core/src/main/java/com/hellokaton/blade/server/StaticFileHandler.java +++ b/blade-core/src/main/java/com/hellokaton/blade/server/StaticFileHandler.java @@ -54,8 +54,7 @@ import java.util.regex.Pattern; import static com.hellokaton.blade.kit.BladeKit.*; -import static com.hellokaton.blade.mvc.BladeConst.HTTP_DATE_FORMAT; -import static com.hellokaton.blade.mvc.BladeConst.REQUEST_TO_STATIC_ATTR; +import static com.hellokaton.blade.mvc.BladeConst.*; import static io.netty.handler.codec.http.HttpResponseStatus.*; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_0; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; @@ -81,11 +80,11 @@ public class StaticFileHandler implements RequestHandler { /** * default cache 30 days. */ - private final int httpCacheSeconds; + private final int staticFileCacheSeconds; public StaticFileHandler(Blade blade) { this.showFileList = blade.environment().getBoolean(BladeConst.ENV_KEY_STATIC_LIST, false); - this.httpCacheSeconds = blade.environment().getInt(BladeConst.ENV_KEY_HTTP_CACHE_TIMEOUT, 86400 * 30); + this.staticFileCacheSeconds = blade.environment().getInt(BladeConst.ENV_KEY_STATIC_CACHE_SECONDS, 86400 * 30); } /** @@ -98,7 +97,7 @@ public void handle(WebContext webContext) throws Exception { Request request = webContext.getRequest(); ChannelHandlerContext ctx = webContext.getChannelHandlerContext(); - if (!com.hellokaton.blade.mvc.http.HttpMethod.GET.name().equals(request.method())) { + if (!HttpMethod.GET.name().equals(request.method())) { sendError(ctx, METHOD_NOT_ALLOWED); return; } @@ -114,6 +113,12 @@ public void handle(WebContext webContext) throws Exception { } else { uri = URLDecoder.decode(request.uri(), "UTF-8"); } + + if (FAVICON_PATH.equals(uri)) { + String dir = WebContext.blade().getEnv(ENV_KEY_FAVICON_DIR, "/static"); + uri = dir + uri; + } + String method = StringKit.padRight(request.method(), 6); String cleanURL = getCleanURL(request, uri); @@ -386,7 +391,7 @@ private boolean writeJarResource(ChannelHandlerContext ctx, Request request, private boolean executeHttp304(ChannelHandlerContext ctx, Request request, long size, long lastModified) { String ifModifiedSince = request.header(HttpConst.HEADER_IF_MODIFIED_SINCE); - if (StringKit.isNotEmpty(ifModifiedSince) && httpCacheSeconds > 0) { + if (StringKit.isNotEmpty(ifModifiedSince) && staticFileCacheSeconds > 0) { Date ifModifiedSinceDate = format(ifModifiedSince, HTTP_DATE_FORMAT); @@ -436,11 +441,11 @@ private void setDateAndCacheHeaders(HttpResponse response, File fileToCache) { response.headers().set(HttpHeaderNames.DATE, dateFormatter.format(time.getTime())); // Add cache headers - if (httpCacheSeconds > 0) { - time.add(Calendar.SECOND, httpCacheSeconds); + if (staticFileCacheSeconds > 0) { + time.add(Calendar.SECOND, staticFileCacheSeconds); response.headers().set(HttpHeaderNames.EXPIRES, dateFormatter.format(time.getTime())); - response.headers().set(HttpHeaderNames.CACHE_CONTROL, "private, max-age=" + httpCacheSeconds); + response.headers().set(HttpHeaderNames.CACHE_CONTROL, "private, max-age=" + staticFileCacheSeconds); response.headers().set( HttpHeaderNames.LAST_MODIFIED, dateFormatter.format(new Date(fileToCache.lastModified()))); } diff --git a/blade-core/src/test/java/com/hellokaton/blade/BladeTest.java b/blade-core/src/test/java/com/hellokaton/blade/BladeTest.java index f9a20848..6e99b7d0 100644 --- a/blade-core/src/test/java/com/hellokaton/blade/BladeTest.java +++ b/blade-core/src/test/java/com/hellokaton/blade/BladeTest.java @@ -8,6 +8,7 @@ import com.hellokaton.blade.mvc.http.HttpSession; import com.hellokaton.blade.mvc.ui.template.TemplateEngine; import com.hellokaton.blade.options.HttpOptions; +import com.hellokaton.blade.options.StaticOptions; import com.hellokaton.blade.types.BladeClassDefineType; import com.mashape.unirest.http.Unirest; import netty_hello.Hello; @@ -120,11 +121,14 @@ public void testRegister() { @Test public void testAddStatics() { Blade blade = Blade.create(); - blade.addStatics("/assets/", "/public"); + blade.staticOptions(options -> { + options.addStatic("/assets/"); + options.addStatic("/assets/"); + }); - assertEquals(7, blade.getStatics().size()); - assertEquals(Boolean.TRUE, blade.getStatics().contains("/assets/")); - assertEquals(Boolean.FALSE, blade.getStatics().contains("/hello/")); + assertEquals(7, blade.staticOptions().getPaths().size()); + assertEquals(Boolean.TRUE, blade.staticOptions().getPaths().contains("/assets/")); + assertEquals(Boolean.FALSE, blade.staticOptions().getPaths().contains("/hello/")); } @Test @@ -194,8 +198,8 @@ public void testThreadName() { @Test public void testShowFileList() { Blade blade = Blade.create(); - blade.showFileList(false); - assertEquals(Boolean.FALSE, blade.environment().getBooleanOrNull(ENV_KEY_STATIC_LIST)); + blade.staticOptions(StaticOptions::showList); + assertEquals(Boolean.FALSE, blade.staticOptions().isShowList()); } @Test diff --git a/blade-examples/src/main/java/com/example/Application.java b/blade-examples/src/main/java/com/example/Application.java index 54af0d7f..e4e5ee0f 100644 --- a/blade-examples/src/main/java/com/example/Application.java +++ b/blade-examples/src/main/java/com/example/Application.java @@ -17,6 +17,7 @@ import com.hellokaton.blade.mvc.ui.ResponseType; import com.hellokaton.blade.mvc.ui.RestResponse; import com.hellokaton.blade.options.CorsOptions; +import com.hellokaton.blade.options.HttpOptions; import com.hellokaton.blade.security.limit.LimitOptions; import lombok.extern.slf4j.Slf4j; @@ -71,6 +72,11 @@ public String index(Request req) { return token; } + @GET(value = "home", responseType = ResponseType.VIEW) + public String home() { + return "home.html"; + } + @POST public String verifyToken(Request req) { System.out.println("token = " + req.header("X-CSRF-TOKEN")); @@ -110,7 +116,7 @@ public static void main(String[] args) { Blade.create() .cors(corsOptions) -// .http(HttpOptions::enableSession) + .http(HttpOptions::enableSession) .get("/base/:uid", ctx -> { ctx.text(ctx.pathString("uid")); }) diff --git a/blade-examples/src/main/resources/static/favicon.ico b/blade-examples/src/main/resources/static/favicon.ico new file mode 100644 index 00000000..259de9cb Binary files /dev/null and b/blade-examples/src/main/resources/static/favicon.ico differ diff --git a/blade-examples/src/main/resources/templates/home.html b/blade-examples/src/main/resources/templates/home.html index e4f405c3..dab65bc1 100644 --- a/blade-examples/src/main/resources/templates/home.html +++ b/blade-examples/src/main/resources/templates/home.html @@ -3,9 +3,10 @@ + Title - +

This is home page.

\ No newline at end of file