springboot 页面静态化
页面静态化:将动态渲染的页面保存为静态页面(一般存储在nginx),提高访问速度
说明:页面静态化适用于数据不常变更的场景,如果数据频繁变更,宜使用其他方案提高访问性能
相关类与接口
IContext:存储上下文变量
public interface IContext {Locale getLocale();boolean containsVariable(String var1);Set<String> getVariableNames();Object getVariable(String var1);
}
AbstractContext
public abstract class AbstractContext implements IContext {private final Map<String, Object> variables;private Locale locale;protected AbstractContext() {protected AbstractContext(Locale locale) {protected AbstractContext(Locale locale, Map<String, Object> variables) {public void setLocale(Locale locale) {public final Locale getLocale() {public final boolean containsVariable(String name) {public final Set<String> getVariableNames() {public final Object getVariable(String name) {public void setVariable(String name, Object value) {public void setVariables(Map<String, Object> variables) {public void removeVariable(String name) {public void clearVariables() {
Context
public final class Context extends AbstractContext {public Context() {}public Context(Locale locale) {super(locale);}public Context(Locale locale, Map<String, Object> variables) {super(locale, variables);}
}
ITemplateEngine
public interface ITemplateEngine {IEngineConfiguration getConfiguration();String process(String var1, IContext var2);String process(String var1, Set<String> var2, IContext var3);String process(TemplateSpec var1, IContext var2);void process(String var1, IContext var2, Writer var3);void process(String var1, Set<String> var2, IContext var3, Writer var4);void process(TemplateSpec var1, IContext var2, Writer var3);IThrottledTemplateProcessor processThrottled(String var1, IContext var2);IThrottledTemplateProcessor processThrottled(String var1, Set<String> var2, IContext var3);IThrottledTemplateProcessor processThrottled(TemplateSpec var1, IContext var2);
}
ISpringTemplateEngine
public interface ISpringTemplateEngine extends ITemplateEngine {void setTemplateEngineMessageSource(MessageSource var1);
}
TemplateEngine
public class TemplateEngine implements ITemplateEngine {public static final String TIMER_LOGGER_NAME = TemplateEngine.class.getName() + ".TIMER";private static final Logger logger = LoggerFactory.getLogger(TemplateEngine.class);private static final Logger timerLogger;private static final int NANOS_IN_SECOND = 1000000;private volatile boolean initialized = false;private final Set<DialectConfiguration> dialectConfigurations = new LinkedHashSet(3);private final Set<ITemplateResolver> templateResolvers = new LinkedHashSet(3);private final Set<IMessageResolver> messageResolvers = new LinkedHashSet(3);private final Set<ILinkBuilder> linkBuilders = new LinkedHashSet(3);private ICacheManager cacheManager = null;private IEngineContextFactory engineContextFactory = null;private IDecoupledTemplateLogicResolver decoupledTemplateLogicResolver = null;private IEngineConfiguration configuration = null;public TemplateEngine() {this.setCacheManager(new StandardCacheManager());this.setEngineContextFactory(new StandardEngineContextFactory());this.setMessageResolver(new StandardMessageResolver());this.setLinkBuilder(new StandardLinkBuilder());this.setDecoupledTemplateLogicResolver(new StandardDecoupledTemplateLogicResolver());this.setDialect(new StandardDialect());}***********
dialect 操作public void setDialect(IDialect dialect) {public void setDialects(Set<IDialect> dialects) {public void setAdditionalDialects(Set<IDialect> additionalDialects) {public final Set<IDialect> getDialects() {public void addDialect(String prefix, IDialect dialect) {public void addDialect(IDialect dialect) {public void setDialectsByPrefix(Map<String, IDialect> dialects) {public final Map<String, Set<IDialect>> getDialectsByPrefix() {public void clearDialects() {***********
templateResolver 操作public void setTemplateResolver(ITemplateResolver templateResolver) {public void setTemplateResolvers(Set<ITemplateResolver> templateResolvers) {public void addTemplateResolver(ITemplateResolver templateResolver) {public final Set<ITemplateResolver> getTemplateResolvers() {***********
process 操作public final String process(String template, IContext context) {public final String process(String template, Set<String> templateSelectors, IContext context) {public final String process(TemplateSpec templateSpec, IContext context) {public final void process(String template, IContext context, Writer writer) {public final void process(String template, Set<String> templateSelectors, IContext context, Writer writer) {public final void process(TemplateSpec templateSpec, IContext context, Writer writer) {public final IThrottledTemplateProcessor processThrottled(String template, IContext context) {public final IThrottledTemplateProcessor processThrottled(String template, Set<String> templateSelectors, IContext context) {public final IThrottledTemplateProcessor processThrottled(TemplateSpec templateSpec, IContext context) {***********
其余操作public final ICacheManager getCacheManager() {public void setCacheManager(ICacheManager cacheManager) {public final IEngineContextFactory getEngineContextFactory() {public void setEngineContextFactory(IEngineContextFactory engineContextFactory) {public final IDecoupledTemplateLogicResolver getDecoupledTemplateLogicResolver() {public void setDecoupledTemplateLogicResolver(IDecoupledTemplateLogicResolver decoupledTemplateLogicResolver) {public final Set<IMessageResolver> getMessageResolvers() {public void setMessageResolvers(Set<IMessageResolver> messageResolvers) {public void addMessageResolver(IMessageResolver messageResolver) {public void setMessageResolver(IMessageResolver messageResolver) {public final Set<ILinkBuilder> getLinkBuilders() {public void setLinkBuilders(Set<ILinkBuilder> linkBuilders) {public void addLinkBuilder(ILinkBuilder linkBuilder) {public void setLinkBuilder(ILinkBuilder linkBuilder) {public void clearTemplateCache() {public void clearTemplateCacheFor(String templateName) {public static String threadIndex() {public final boolean isInitialized() {public IEngineConfiguration getConfiguration() {private void checkNotInitialized() {final void initialize() {protected void initializeSpecific() {static {timerLogger = LoggerFactory.getLogger(TIMER_LOGGER_NAME);}
}
SpringTemplateEngine:springboot启动时自动创建实例bean(mvc)
public class SpringTemplateEngine extends TemplateEngine implements ISpringTemplateEngine, MessageSourceAware {private static final SpringStandardDialect SPRINGSTANDARD_DIALECT = new SpringStandardDialect();private MessageSource messageSource = null;private MessageSource templateEngineMessageSource = null;public SpringTemplateEngine() {super.setDialect(SPRINGSTANDARD_DIALECT);}public void setMessageSource(MessageSource messageSource) {public void setTemplateEngineMessageSource(MessageSource templateEngineMessageSource) {public void setEnableSpringELCompiler(boolean enableSpringELCompiler) {public void setRenderHiddenMarkersBeforeCheckboxes(boolean renderHiddenMarkersBeforeCheckboxes) {public boolean getEnableSpringELCompiler() {public boolean getRenderHiddenMarkersBeforeCheckboxes() {protected final void initializeSpecific() {protected void initializeSpringSpecific() {
使用示例
*************
config 层
WebConfig
@EnableAsync
@Configuration
public class WebConfig implements AsyncConfigurer {@Overridepublic Executor getAsyncExecutor() {ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setMaxPoolSize(10);executor.setQueueCapacity(10);executor.setKeepAliveSeconds(60);executor.initialize();return executor;}
}
*************
service 层
StaticPageService
@Service
public class StaticPageService {private final String path="/usr/nginx/html";@Resourceprivate TemplateEngine templateEngine;@Async@SuppressWarnings("all")public void createOrUpdatePage(Map<String,Object> map, String templateName, String dir, Integer id){System.out.println("createOrUpdatePage: "+dir);Context context=new Context();context.setVariables(map);File root=new File(path+File.separator+dir);if (!root.exists()){root.mkdir();}File file=new File(path,dir+File.separator+id+".html");if (file.exists()){file.delete();}try {PrintWriter writer=new PrintWriter(file, StandardCharsets.UTF_8);templateEngine.process(templateName,context,writer);}catch (Exception e){e.printStackTrace();}}@Async@SuppressWarnings("all")public void deletePage(String dir, Integer id){File file = new File(path, dir+File.separator+id+".html");if (file.exists()){file.delete();}}
}
*************
controller 层
HelloController
@Controller
public class HelloController {private Map<String,Object> map=new HashMap<>();@Resourceprivate StaticPageService pageService;@RequestMapping("/person/{id}.html")public ModelAndView get(@PathVariable("id") Integer id, ModelAndView mv){map.put("id",id);map.put("name","瓜田李下");map.put("age",20);pageService.createOrUpdatePage(map,"template","person", id);mv.setViewName("template");mv.addAllObjects(map);return mv;}
}
*************
前端页面
template.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head><meta charset="UTF-8"><title>static page</title>
</head>
<body>
<div th:align="center" style="color: coral"><span th:text="'id: '+${id}"></span><br><span th:text="'name: '+${name}"></span><br><span th:text="'age: '+${age}"></span>
</div>
</body>
</html>
创建应用
nginx 配置:default.conf
server {listen 80;server_name localhost;#charset koi8-r;#access_log /var/log/nginx/host.access.log main;location /person {root /usr/share/nginx/html;index index.html index.htm;if ( !-e $request_filename ){proxy_pass http://192.168.57.2:8080;break;}}error_page 500 502 503 504 /50x.html;location = /50x.html {root /usr/share/nginx/html;}}
创建应用:docker 启动springboot应用,nginx代理应用
docker run -it -d --net fixed3 --ip 192.168.57.2 \
-v /usr/nginx/static-page/demo.jar:/usr/local/app.jar \
-v /usr/nginx/html:/usr/nginx/html \
--name static-page commondocker run -it -d --net fixed3 --ip 192.168.57.3 \
-v /usr/nginx/static-page/conf/default.conf:/etc/nginx/conf.d/default.conf \
-v /usr/nginx/html:/usr/share/nginx/html \
--name nginx nginx
使用测试
192.168.57.3:8000/person/1.html

控制台输出
2021-08-24 12:25:21.123 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-08-24 12:25:21.180 INFO 1 --- [ main] com.example.demo.SpringbootApplication : Started SpringbootApplication in 10.528 seconds (JVM running for 13.335)
2021-08-24 12:25:29.686 INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-08-24 12:25:29.687 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-08-24 12:25:29.690 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms
createOrUpdatePage: person
查看本地目录:/usr/nginx/html
[root@centos html]# pwd
/usr/nginx/html[root@centos html]# ls
person
[root@centos html]# ls person
1.html[root@centos html]# cat person/1.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head><meta charset="UTF-8"><title>static page</title>
</head>
<body>
<div align="center" style="color: coral"><span>id: 1</span><br><span>name: 瓜田李下</span><br><span>age: 20</span>
</div>
</body>
再次访问192.168.57.3:8000/person/1.html,nginx直接返回本地缓存的静态文件

















