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 {
@Override
public 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";
@Resource
private 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<>();
@Resource
private 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 common
docker 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直接返回本地缓存的静态文件