Skip to content

Commit 2f1c463

Browse files
committed
🎨 improve static file handler
1 parent daceb0e commit 2f1c463

File tree

15 files changed

+215
-141
lines changed

15 files changed

+215
-141
lines changed

blade-core/src/main/java/com/hellokaton/blade/Blade.java

+37-46
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,12 @@
3030
import com.hellokaton.blade.mvc.hook.WebHook;
3131
import com.hellokaton.blade.mvc.http.HttpMethod;
3232
import com.hellokaton.blade.mvc.http.session.SessionManager;
33-
import com.hellokaton.blade.mvc.route.DynamicMapping;
3433
import com.hellokaton.blade.mvc.route.RouteMatcher;
35-
import com.hellokaton.blade.mvc.route.mapping.dynamic.RegexMapping;
36-
import com.hellokaton.blade.mvc.route.mapping.dynamic.TrieMapping;
3734
import com.hellokaton.blade.mvc.ui.template.DefaultEngine;
3835
import com.hellokaton.blade.mvc.ui.template.TemplateEngine;
3936
import com.hellokaton.blade.options.CorsOptions;
4037
import com.hellokaton.blade.options.HttpOptions;
38+
import com.hellokaton.blade.options.StaticOptions;
4139
import com.hellokaton.blade.server.NettyServer;
4240
import com.hellokaton.blade.server.Server;
4341
import lombok.AccessLevel;
@@ -54,6 +52,8 @@
5452
import java.util.function.Consumer;
5553
import java.util.stream.Collectors;
5654

55+
import static com.hellokaton.blade.mvc.BladeConst.ENV_KEY_FAVICON_DIR;
56+
5757
/**
5858
* Blade Core
5959
* <p>
@@ -78,13 +78,6 @@ public class Blade {
7878
*/
7979
private final Set<String> packages = new LinkedHashSet<>(BladeConst.PLUGIN_PACKAGE_NAME);
8080

81-
/**
82-
* All static resource URL prefixes,
83-
* defaults to "/favicon.ico", "/robots.txt", "/static/", "/upload/", "/webjars/",
84-
* which are located under classpath
85-
*/
86-
private final Set<String> statics = new HashSet<>(BladeConst.DEFAULT_STATICS);
87-
8881
/**
8982
* The default IOC container implementation
9083
*/
@@ -121,7 +114,8 @@ public class Blade {
121114
private final RouteMatcher routeMatcher = new RouteMatcher();
122115

123116
private CorsOptions corsOptions = null;
124-
private final HttpOptions httpOptions = HttpOptions.create();
117+
private HttpOptions httpOptions = HttpOptions.create();
118+
private StaticOptions staticOptions = StaticOptions.create();
125119

126120
/**
127121
* Blade environment, which stores the parameters of the application.properties configuration file
@@ -280,6 +274,17 @@ public TemplateEngine templateEngine() {
280274
return this.templateEngine;
281275
}
282276

277+
/**
278+
* setting favicon dir, default is /static
279+
*
280+
* @param faviconDir favicon dir
281+
* @return blade instance
282+
*/
283+
public Blade faviconDir(String faviconDir) {
284+
this.setEnv(ENV_KEY_FAVICON_DIR, faviconDir);
285+
return this;
286+
}
287+
283288
/**
284289
* Get RouteMatcher
285290
*
@@ -294,6 +299,21 @@ public Blade http(Consumer<HttpOptions> consumer) {
294299
return this;
295300
}
296301

302+
public Blade http(HttpOptions httpOptions) {
303+
this.httpOptions = httpOptions;
304+
return this;
305+
}
306+
307+
public Blade staticOptions(Consumer<StaticOptions> consumer) {
308+
consumer.accept(this.staticOptions);
309+
return this;
310+
}
311+
312+
public Blade staticOptions(StaticOptions staticOptions) {
313+
this.staticOptions = staticOptions;
314+
return this;
315+
}
316+
297317
public Blade cors(CorsOptions corsOptions) {
298318
this.corsOptions = corsOptions;
299319
return this;
@@ -307,6 +327,10 @@ public HttpOptions httpOptions() {
307327
return this.httpOptions;
308328
}
309329

330+
public StaticOptions staticOptions() {
331+
return this.staticOptions;
332+
}
333+
310334
/**
311335
* Register bean to ioc container
312336
*
@@ -329,29 +353,6 @@ public Blade register(@NonNull Class<?> cls) {
329353
return this;
330354
}
331355

332-
/**
333-
* Add multiple static resource file
334-
* the default provides the static, upload
335-
*
336-
* @param folders static resource directory
337-
* @return blade
338-
*/
339-
public Blade addStatics(@NonNull String... folders) {
340-
this.statics.addAll(Arrays.asList(folders));
341-
return this;
342-
}
343-
344-
/**
345-
* Set whether to show the file directory, default doesn't show
346-
*
347-
* @param fileList show the file directory
348-
* @return blade
349-
*/
350-
public Blade showFileList(boolean fileList) {
351-
this.environment.set(BladeConst.ENV_KEY_STATIC_LIST, fileList);
352-
return this;
353-
}
354-
355356
/**
356357
* Get ioc bean
357358
*
@@ -415,16 +416,6 @@ public Class<?> bootClass() {
415416
return this.bootClass;
416417
}
417418

418-
/**
419-
* Get blade statics list.
420-
* e.g: "/favicon.ico", "/robots.txt", "/static/", "/upload/", "/webjars/"
421-
*
422-
* @return return statics
423-
*/
424-
public Set<String> getStatics() {
425-
return this.statics;
426-
}
427-
428419
/**
429420
* When set to start blade scan packages
430421
*
@@ -686,8 +677,8 @@ public Blade start(Class<?> mainCls, String... args) {
686677
try {
687678
//TODO: add support for Create and Delete
688679
if (event.equals(StandardWatchEventKinds.ENTRY_MODIFY)) {
689-
Path destPath = FileChangeDetector.getDestPath(filePath, environment);
690-
Files.copy(filePath, destPath, StandardCopyOption.REPLACE_EXISTING);
680+
Path destPath = FileChangeDetector.getDestPath(filePath, environment, staticOptions);
681+
Files.copy(filePath, Objects.requireNonNull(destPath), StandardCopyOption.REPLACE_EXISTING);
691682
}
692683
} catch (IOException e) {
693684
log.error("Exception when trying to copy updated file");

blade-core/src/main/java/com/hellokaton/blade/kit/reload/FileChangeDetector.java

+25-26
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
import com.hellokaton.blade.Environment;
44
import com.hellokaton.blade.mvc.BladeConst;
5+
import com.hellokaton.blade.options.StaticOptions;
56
import lombok.extern.slf4j.Slf4j;
67

78
import java.io.IOException;
89
import java.nio.file.*;
910
import java.nio.file.attribute.BasicFileAttributes;
10-
import java.util.*;
11+
import java.util.ArrayList;
12+
import java.util.HashMap;
13+
import java.util.List;
14+
import java.util.Map;
1115
import java.util.function.BiConsumer;
1216
import java.util.stream.Collectors;
1317

@@ -19,18 +23,18 @@ public class FileChangeDetector {
1923
private final WatchService watcher;
2024
private final Map<WatchKey, Path> pathMap = new HashMap<>();
2125

22-
public FileChangeDetector(String dirPath) throws IOException{
26+
public FileChangeDetector(String dirPath) throws IOException {
2327
watcher = FileSystems.getDefault().newWatchService();
2428
registerAll(Paths.get(dirPath));
2529
}
2630

27-
private void register(Path dir) throws IOException{
31+
private void register(Path dir) throws IOException {
2832
WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
29-
pathMap.put(key,dir);
33+
pathMap.put(key, dir);
3034
}
3135

32-
private void registerAll(Path dir) throws IOException{
33-
Files.walkFileTree(dir, new SimpleFileVisitor<Path>(){
36+
private void registerAll(Path dir) throws IOException {
37+
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
3438
@Override
3539
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
3640
register(dir);
@@ -39,46 +43,41 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th
3943
});
4044
}
4145

42-
public void processEvent(BiConsumer<WatchEvent.Kind<Path>, Path> processor){
43-
for(;;){
46+
public void processEvent(BiConsumer<WatchEvent.Kind<Path>, Path> processor) {
47+
for (; ; ) {
4448
WatchKey key;
45-
try{
49+
try {
4650
key = watcher.take();
47-
}catch (InterruptedException e) {
51+
} catch (InterruptedException e) {
4852
return;
4953
}
5054

5155
Path dir = pathMap.get(key);
52-
for (WatchEvent<?> event: key.pollEvents()){
56+
for (WatchEvent<?> event : key.pollEvents()) {
5357
WatchEvent.Kind kind = event.kind();
54-
Path filePath = dir.resolve(((WatchEvent<Path>)event).context());
58+
Path filePath = dir.resolve(((WatchEvent<Path>) event).context());
5559

56-
if(Files.isDirectory(filePath)) continue;
57-
log.info("File {} changes detected!",filePath.toString());
60+
if (Files.isDirectory(filePath)) continue;
61+
log.info("File {} changes detected!", filePath.toString());
5862
//copy updated files to target
5963
processor.accept(kind, filePath);
6064
}
6165
key.reset();
6266
}
6367
}
6468

65-
public static Path getDestPath(Path src, Environment env){
66-
String templateDir = env.get(BladeConst.ENV_KEY_TEMPLATE_PATH,"/templates");
67-
Optional<String> staticDir = env.get(BladeConst.ENV_KEY_STATIC_DIRS);
69+
public static Path getDestPath(Path src, Environment env, StaticOptions staticOptions) {
70+
String templateDir = env.get(BladeConst.ENV_KEY_TEMPLATE_PATH, "/templates");
6871
List<String> templateOrStaticDirKeyword = new ArrayList<>();
6972
templateOrStaticDirKeyword.add(templateDir);
70-
if(staticDir.isPresent()){
71-
templateOrStaticDirKeyword.addAll(Arrays.asList(staticDir.get().split(",")));
72-
}else{
73-
templateOrStaticDirKeyword.addAll(BladeConst.DEFAULT_STATICS);
74-
}
73+
templateOrStaticDirKeyword.addAll(staticOptions.getPaths());
7574

76-
List result = templateOrStaticDirKeyword.stream().filter(dir -> src.toString().indexOf(dir)!=-1).collect(Collectors.toList());
77-
if(result.size()!=1){
75+
List<String> result = templateOrStaticDirKeyword.stream().filter(dir -> src.toString().contains(dir)).collect(Collectors.toList());
76+
if (result.size() != 1) {
7877
log.info("Cannot get dest dir");
79-
return null;
78+
return null;
8079
}
81-
String key = (String)result.get(0);
80+
String key = result.get(0);
8281
log.info(BladeConst.CLASSPATH + src.toString().substring(src.toString().indexOf(key)));
8382
return Paths.get(BladeConst.CLASSPATH + src.toString().substring(src.toString().indexOf(key)));
8483
}

blade-core/src/main/java/com/hellokaton/blade/mvc/BladeConst.java

+4-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import com.hellokaton.blade.kit.StringKit;
1818

1919
import java.util.ArrayList;
20-
import java.util.Arrays;
2120
import java.util.Collections;
2221
import java.util.List;
2322

@@ -38,8 +37,6 @@ public interface BladeConst {
3837
String INTERNAL_SERVER_ERROR_HTML = "<center><h1>500 Internal Server Error</h1><hr/></center>";
3938
String DEFAULT_THREAD_NAME = "_(:3」∠)_";
4039
List<String> PLUGIN_PACKAGE_NAME = new ArrayList<>(Collections.singletonList("com.hellokaton.blade.plugin"));
41-
List<String> DEFAULT_STATICS = new ArrayList<>(
42-
Arrays.asList("/favicon.ico", "/robots.txt", "/static", "/upload", "/webjars/"));
4340

4441
String PROP_NAME = "classpath:application.properties";
4542

@@ -53,17 +50,17 @@ public interface BladeConst {
5350
String ENV_KEY_TASK_THREAD_COUNT = "app.task.thread-count";
5451
String ENV_KEY_CONTEXT_PATH = "app.context-path";
5552
String ENV_KEY_REQUEST_LOG = "app.request-log";
53+
String ENV_KEY_FAVICON_DIR = "app.favicon-dir";
5654
String ENV_KEY_HTTP_MAX_CONTENT = "http.max-content-size";
5755
String ENV_KEY_GZIP_ENABLE = "http.gzip.enabled";
5856
String ENV_KEY_SESSION_ENABLED = "http.session.enabled";
5957
String ENV_KEY_SESSION_KEY = "http.session.key";
6058
String ENV_KEY_SESSION_TIMEOUT = "http.session.timeout";
61-
String ENV_KEY_HTTP_CACHE_TIMEOUT = "http.cache.timeout";
6259
String ENV_KEY_HTTP_REQUEST_COST = "http.request.cost";
6360
String ENV_KEY_PAGE_404 = "mvc.view.404";
6461
String ENV_KEY_PAGE_500 = "mvc.view.500";
65-
String ENV_KEY_STATIC_DIRS = "mvc.statics";
66-
String ENV_KEY_STATIC_LIST = "mvc.statics.show-list";
62+
String ENV_KEY_STATIC_LIST = "static.show-list";
63+
String ENV_KEY_STATIC_CACHE_SECONDS = "static.cache-seconds";
6764
String ENV_KEY_TEMPLATE_PATH = "mvc.template.path";
6865
String ENV_KEY_SERVER_ADDRESS = "server.address";
6966
String ENV_KEY_SERVER_PORT = "server.port";
@@ -88,6 +85,7 @@ public interface BladeConst {
8885

8986
String REQUEST_TO_STATIC_ATTR = "_to_static";
9087

88+
String FAVICON_PATH = "/favicon.ico";
9189
String NEW_LINE = "\r\n";
9290

9391
int BANNER_PADDING = 60;

blade-core/src/main/java/com/hellokaton/blade/mvc/route/RouteMatcher.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public List<Route> getBefore(String path) {
159159
.flatMap(Collection::stream)
160160
.sorted(Comparator.comparingInt(Route::getSort))
161161
.filter(route -> route.getHttpMethod() == HttpMethod.BEFORE)
162-
.filter(route -> matchesPath(route.getPath(), cleanPath))
162+
.filter(route -> matchesPath(route.getRewritePath(), cleanPath))
163163
.collect(Collectors.toList());
164164

165165
this.giveMatch(path, collect);
@@ -178,7 +178,7 @@ public List<Route> getAfter(String path) {
178178
.flatMap(Collection::stream)
179179
.sorted(Comparator.comparingInt(Route::getSort))
180180
.filter(route -> route.getHttpMethod() == HttpMethod.AFTER)
181-
.filter(route -> matchesPath(route.getPath(), cleanPath))
181+
.filter(route -> matchesPath(route.getRewritePath(), cleanPath))
182182
.collect(Collectors.toList());
183183

184184
this.giveMatch(path, afters);

blade-core/src/main/java/com/hellokaton/blade/mvc/ui/ResponseType.java

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public enum ResponseType {
1212
XML(HttpConst.CONTENT_TYPE_XML),
1313
TEXT(HttpConst.CONTENT_TYPE_TEXT),
1414
HTML(HttpConst.CONTENT_TYPE_HTML),
15+
VIEW(HttpConst.CONTENT_TYPE_HTML),
1516
STREAM(HttpConst.CONTENT_TYPE_STREAM),
1617
PREVIEW(""),
1718
;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.hellokaton.blade.options;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
6+
import java.util.Arrays;
7+
import java.util.HashSet;
8+
import java.util.Set;
9+
10+
@Getter
11+
@Setter
12+
public class StaticOptions {
13+
14+
public static final int DEFAULT_CACHE_SECONDS = 86400 * 30;
15+
public static final Set<String> DEFAULT_STATICS = new HashSet<>(
16+
Arrays.asList("/favicon.ico", "/robots.txt", "/static", "/webjars/"));
17+
18+
private boolean showList;
19+
private Set<String> paths = DEFAULT_STATICS;
20+
private int cacheSeconds = DEFAULT_CACHE_SECONDS;
21+
22+
public static StaticOptions create() {
23+
return new StaticOptions();
24+
}
25+
26+
public StaticOptions showList() {
27+
this.showList = true;
28+
return this;
29+
}
30+
31+
public StaticOptions addStatic(String staticPath) {
32+
this.paths.add(staticPath);
33+
return this;
34+
}
35+
36+
public StaticOptions removeStatic(String staticPath) {
37+
this.paths.remove(staticPath);
38+
return this;
39+
}
40+
41+
public StaticOptions cacheSeconds(int cacheSeconds) {
42+
this.cacheSeconds = cacheSeconds;
43+
return this;
44+
}
45+
46+
}

0 commit comments

Comments
 (0)