整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

如何应用Web页面静态化技术以提高Web应用系统的响应性能

件项目实训及课程设计指导——如何应用Web页面静态化技术提高Web应用系统的响应性能

1、什么是Web页面静态化技术

(1)Web页面静态化技术

将JSP动态页面按照某种模板格式生成对应的*.html纯静态Web页面的过程,称之为Web页面静态化技术。

(2)何种场合需要应用Web页面静态化技术

当有些企业应用系统中的页面信息在一段时间内不发生变化时(比如内容管理系统、网上商城中的商品信息等),可以应用Web页面静态化技术,这样可以提高整个系统的响应效率——因为无须再访问后台数据库系统、也不需要再次编译处理JSP动态页面文件,因此能够减少对Web应用系统的消耗和性能影响。

2、为什么要应用Web页面静态化技术

目前基于B/S(Browser/Server,浏览器/服务器模式)体系架构的企业应用系统基本上都是由动态Web页面所构成的(比如由*.jsp、*.aspx、*.php等类型),正因为是动态化的Web页面才能满足不同的Web浏览者的个性化的访问需要、并且能够与访问者产生相互交互。

但为了能够产生出动态的应用效果,用户每一次对目标页面的HTTP请求都会在Web服务器端对这些动态Web页面进行编译或者动态处理,而这些操作都是很消耗Web服务器系统资源的。

如果目标页面文件(比如*.jsp)在一定的时间内,其动态显示的内容不会发生改变(比如新闻系统中的新闻信息显示、网点中的商品分类和某一商品信息的详情页等),那么就没有必要为每一次对它的HTTP请求访问,都进行一次"新"的编译或执行。此时可以在用户第一次对它访问后,就把它在这段没有发生改变的时间内的页面处理结果保存到一个纯静态的页面文件(*.html格式)或者有静态效果的其它格式页面文件(*.vm、*.ftl等形式)中,然后用户以后每次再访问这个动态Web页面时,后台Web服务器系统程序就直接采用转换后的静态页面内容进行响应。

因此,经过静态化技术转换处理后的结果Web页面能够快速地响应用户的HTTP请求,而且还能够大大地减少对Web服务器系统资源的消耗。当然,为了能够达到静态化的功能实现目标,软件应用系统的开发人员可以在Web应用系统的开发中应用各种模板技术——比如Velocity模板、FreeMarker模板技术等。当然,读者如果熟悉Web页面静态化技术的实现原理后,也可以自己编程实现。

在Web应用系统的表示层开发中如何通过应用Velocity模板技术以提高Web应用系统的响应性能,作者在以前的文章中的做了详细的介绍,有兴趣的读者可以翻看文章《软件项目实训及课程设计指导——如何在Web应用系统表示层开发实现中应用Velocity模板技术》。

作者在下文将为读者介绍如何在Web应用系统的表示层开发中应用FreeMarker模板技术以提高Web应用系统的响应性能。

3、在Web应用系统的表示层开发中应用FreeMarker模板技术

(1)FreeMarker模板是什么、怎么理解"模板引擎"的概念

FreeMarker 和Velocity都属于"模板引擎"(作者注:"模板引擎"在J2EE平台中一般为框架形式的系统程序和相关的系统库),开发人员应用这些模板引擎所提供的模板语言处理相关的数据,模板引擎系统会按照开发人员的要求输出文本,这些文本的格式可以是HTML网页、电子邮件、配置文件以及源代码等形式。

如下代码示例为在标准的HTML页面中内嵌FreeMarker模板语言的语句(参看其中的黑体标识的语句)的示例。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html> <head> <title>showInfoTemplate.ftl</title>
<meta http-equiv="content-type" content="text/html; charset=gb2312">
</head> <body>
    <h2>采用标准的方式获得参数值: ${showResultInfo}</h2 > <br>
    <h2>采用FreeMarker模板的内建变量的方式获得参数值: ${Request.showResultInfo }</h2 > <br>
</body></html>

(2)为什么要应用FreeMarker等类型的模板技术

谈到"模板"的概念,相信读者应该不会感觉到陌生感,在生活中大量地应用各种各样的"模板",应用的目的读者也应该都会理解。同样,在计算机软件应用系统中也大量地提高各种模板和应用各种模板来简化和加速某项"工作",比如Word中的文档格式模板、编程语言中的print("%各种格式符")语句中的替换模板等等。而在J2EE系统平台的应用系统开发中之所以应用FreeMarker模板技术:

首先,FreeMarker模板技术同样也能够实现Web应用系统中的表示逻辑和数据处理逻辑相互分离——这是通过在模板文件中包装HTML标签实现的。

FreeMarker模板采用标准的Web Servlet程序中所提供的模型数据动态地生成目标HTML页面文件。在Web应用系统开发中如果应用FreeMarker模板技术,界面开发人员只需要关注于界面(也就是FreeMarker的模板文件)的开发,而系统中的业务逻辑的开发人员也只需要负责将需要显示的数据填入到FreeMarker的模板文件的数据模型中。最终由FreeMarker模板引擎负责合并数据模型和模板文件,然后产生出完整的Web页面文件并输出到Web浏览器中。

其次,实现将基于动态化技术的各种Web页面(如*.jsp、*.aspx、*.php等)转换为静态的HTML格式或其它文本格式的Web页面,达到"动态页面静态化"的高效响应的应用效果。

因此,模板引擎不只是可以让开发人员实现代码级别的分离(如系统中的业务逻辑代码和用户界面展示控制代码的分离),也可以实现软件应用系统中的数据分离(如动态可变数据与静态固定数据相互分离),甚至还可以实现应用系统中的代码单元共享(代码重用)等效果。

4、Struts及Struts2应用框架都全面地支持FreeMarker模板技术

(1)FreeMarker模板特别适应于基于MVC体系架构模式的Web应用系统

Struts2应用框架默认采用FreeMarker作为其模板文件,并且Struts2应用框架中所有的主题模板文件都是采用FreeMarker模板技术编写的。

(2)Struts2应用框架全面提供对FreeMarker模板技术的支持

在基于Struts2应用框架的Web应用系统中,开发人员只需要将项目中的Action类的配置定义中的结果<result>标签中的type属行设置为:type="freemarker",就可以自动地由Struts2应用框架中内带的FreeMarker引擎完成模型数据和模板文件的总装配和输出(参看如下示例图所示)。

(3)Struts应用框架也同样提供对FreeMarker模板技术的支持

而在Struts应用框架中应用FreeMarker模板技术,开发人员只需要在Web应用系统的部署描述文件web.xml中配置出与FreeMarker模板相关的FreemarkerServlet组件(参看如下示例图所示),然后由该FreemarkerServlet组件将项目中的相关Action类中所保存的模型数据和模板文件相互集成组装成最终的HTML页面文件、并向Web浏览器输出。

作者将在下文及后续文章中为读者介绍在J2EE Web应用系统、J2EE Struts应用框架的应用系统及J2EE Struts2应用框架的应用系统等环境中如何应用FreeMarker模板技术实现Web页面静态化的应用效果。作者首先在下文为读者介绍在J2EE Web应用系统环境中如何应用FreeMarker模板技术。

5、在J2EE Web应用项目中添加一个JSP页面文件

(1)在Web项目的userManage目录下添加一个文件名称为fmtWebUserLogin.jsp的JSP页面文件,该页面主要功能是模拟用户系统登录,其中包含有一个标准的HTML表单,创建的过程参看如下示例图所示。

(2)fmtWebUserLogin.jsp页面文件的代码示例

<%@ page language="java" pageEncoding="GB18030"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><title>My JSP 'fmtUserLogin.jsp' starting page</title>
</head><body>
    <form action="/Struts2Web/fmtServletAction" method="post" >
        您的名称:<input type="text" name="userName" /> <br />
        您的密码:<input type="password" name="userPassWord" /> <br />
        <input type="submit" value="提交" name="submitButton" onclick="this.value='正在提交请求,请稍候'"/>
        <input type="reset" value="取消" />
    </form>
</body></html>

(3)fmtWebUserLogin.jsp页面静态预览的效果图如下图所示

6、在J2EE Web应用项目中添加一个Servlet组件

在J2EE Web应用系统中使用FreeMarker模板时,应该让J2EE Servlet组件来合并模板和数据。因此J2EE Servlet组件负责创建Configuration类型的对象实例,并负责合并模板和数据。

(1)程序包名称为com.px1987.struts2.servlet,类名称为FMTServletAction,创建的过程参看如下示例图所示。

(2)将J2EE Servlet组件的URL-Pattern设置为/fmtServletAction,创建的过程参看如下示例图所示。

(3)FMTServletAction程序类的代码示例

package com.px1987.struts2.servlet;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
public class FMTServletAction extends HttpServlet {
      private Configuration oneConfiguration=null;
      public FMTServletAction() {
      			super();
      }
      public void init() throws ServletException {
            /** 初始化FreeMarker配置,并创建出一个Configuration的实例 */
            oneConfiguration = new Configuration(); //设置FreeMarker的模版文件位置
            oneConfiguration.setServletContextForTemplateLoading(getServletContext(),"userManage");
            } //第一个参数是本web应用的 ServletContext,第二个参数是模板文件的路径
            public void destroy() {
            super.destroy();
      }
      public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
            String resultMessage=null;
            String userName=request.getParameter("userName");
            String userPassWord=request.getParameter("userPassWord");
            boolean returnResult=userName.equals("yang") &&userPassWord.equals("1234");
            if(returnResult){
            			resultMessage =userName+"您登录成功!";
            }
            else{
            			resultMessage =userName+"您的身份信息无效!";
            }
            Map oneHashMap = new HashMap();
            oneHashMap.put("showResultInfo", resultMessage); //取得模版文件
            Template oneTemplate= oneConfiguration.getTemplate("showInfoFMTTemplate.ftl");
            response.setContentType("text/html; charset=gb2312");
            Writer out = response.getWriter();
            try{ //结果必须输出到HttpServletResponse中,才能被浏览器加载
            			oneTemplate.process(oneHashMap, out);
            }
            catch (TemplateException e){
            			throw new ServletException("加载FreeMarker的模板文件时出现了错误", e);
            }
      }
}

7、在J2EE Web应用项目中添加一个FreeMarker模板文件

(1)模板文件的名称为showInfoFMTTemplate.ftl,创建的过程参看如下示例图所示。

(2)模板文件showInfoFMTTemplate.ftl的代码示例如下,注意其中黑体标识的代码

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html> <head> <title>showInfoTemplate.ftl</title>
<meta http-equiv="content-type" content="text/html; charset=gb2312">
</head> <body>
			<h2>采用标准的方式获得参数值: ${showResultInfo}</h2 > <br>
</body></html>

8、部署本Web项目并启动测试页面以验证本示例的功能

(1)正确地部署完毕本Web项目后,在浏览器的URL地址栏中输入如下示图中的访问地址,启动测试页面 ,执行的结果参看如下示例图所示。

(2)在测试页面的表单中模拟用户登录系统的状态,输入相关的登录参数后的执行结果参看如下示例图所示。

从本示例的执行结果来看,在showInfoFMTTemplate.ftl页面中同样也可以获得在传统的J2EE Web应用环境中一般由动态JSP类型的Web页面才能获得的动态结果数据,但本示例中的*.ftl页面是静态效果的Web页面。因此,最终实现和达到了"动态页面静态化"的高效响应的应用效果。

作者为了能够让读者进一步地理解"动态页面静态化"的应用效果,可以通过浏览结果页面相关的源程序从而确认最终是否为一个HTML格式的纯静态页面。读者可以在Web浏览器中右键单击,然后在弹出的快捷菜单项目中选择"查看源文件"的功能子菜单项目(参看如下示例图所示)。

将在Web浏览器中显示出用户当前正在浏览的Web页面的源代码,熟悉HTML语言的读者应该能够看懂其中的代码含义——全部为HTML格式的纯静态页面标签。

如何应用XML+XSLT+AJAX组合技术实现无刷新数据查询

应用XML+XSLT技术分离Web应用表示层数据和样式的实例

如何应用“XML+XSLT”技术分离Web表示层数据和样式

课程设计指导——应用AJAX技术提高Web应用的整体响应性能

如何在Web应用系统表示层开发中应用Velocity模板技术


WEB系列】静态资源配置与读取

SpringWeb项目除了我们常见的返回json串之外,还可以直接返回静态资源(当然在现如今前后端分离比较普遍的情况下,不太常见了),一些简单的web项目中,前后端可能就一个人包圆了,前端页面,js/css文件也都直接放在Spring项目中,那么你知道这些静态资源文件放哪里么

I. 默认配置

1. 配置

静态资源路径,SpringBoot默认从属性spring.resources.static-locations中获取

默认值可以从org.springframework.boot.autoconfigure.web.ResourceProperties#CLASSPATH_RESOURCE_LOCATIONS获取

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
			"classpath:/resources/", "classpath:/static/", "classpath:/public/" };

/**
 * Locations of static resources. Defaults to classpath:[/META-INF/resources/,
 * /resources/, /static/, /public/].
 */
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
复制代码

注意上面的默认值,默认有四个,优先级从高到低

  • /META-INF/resources/
  • /resources/
  • /static/
  • /public/

2. 实例演示

默认静态资源路径有四个,所以我们设计case需要依次访问这四个路径中的静态资源,看是否正常访问到;其次就是需要判定优先级的问题,是否和上面说的一致

首先创建一个SpringBoot web项目,工程创建流程不额外多说,pom中主要确保有下面依赖即可(本文使用版本为: 2.2.1.RELEASE)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
复制代码

在资源文件夹resources下,新建四个目录,并添加html文件,用于测试是否可以访问到对应的资源文件(主要关注下图中标红的几个文件)



a. META-INF/resources

静态文件 m.html

<html>
<title>META-INF/resource/m.html</title>
<body>
jar包内,META-INF/resources目录下 m.html
</body>
</html>
复制代码

完成对应的Rest接口

@GetMapping(path = "m")
public String m() {
    return "m.html";
}
复制代码



b. resources

静态文件 r.html

<html>
<title>resources/r.html</title>
<body>
jar包内,resouces目录下 r.html
</body>
</html>
复制代码

对应的Rest接口

@GetMapping(path = "r")
public String r() {
    return "r.html";
}
复制代码



c. static

静态文件 s.html

<html>
<title>static/s.html</title>
<body>
jar包内,static目录下 s.html
</body>
</html>
复制代码

对应的Rest接口

@GetMapping(path = "s")
public String s() {
    return "s.html";
}
复制代码



d. public

静态文件 p.html

<html>
<title>public/p.html</title>
<body>
jar包内,public目录下 p.html
</body>
</html>
复制代码

对应的Rest接口

@GetMapping(path = "p")
public String p() {
    return "p.html";
}
复制代码



e. 优先级测试

关于优先级的测试用例,主要思路就是在上面四个不同的文件夹下面放相同文件名的静态资源,然后根据访问时具体的返回来确定相应的优先级。相关代码可以在文末的源码中获取,这里就不赘述了

II. 自定义资源路径

一般来讲,我们的静态资源放在上面的四个默认文件夹下面已经足够,但总会有特殊情况,如果资源文件放在其他的目录下,应该怎么办?

1. 修改配置文件

第一种方式比较简单和实用,修改上面的spring.resources.static-locations配置,添加上自定义的资源目录,如在 application.yml 中,指定配置

spring:
  resources:
    static-locations: classpath:/out/,classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
复制代码

上面指定了可以扫描/out目录下的静态资源文件,且它的优先级是最高的(上面的配置顺序中,优先级的高低从左到右)

实例演示

在资源目录下,新建文件/out/index.html



请注意在其他的四个资源目录下,也都存在 index.html这个文件(根据上面优先级的描述,返回的应该是/out/index.html)

@GetMapping(path = "index")
public String index() {
    return "index.html";
}
复制代码



2. WebMvcConfigurer 添加资源映射

除了上述的配置指定之外,还有一种常见的使用姿势就是利用配置类WebMvcConfigurer来手动添加资源映射关系,为了简单起见,我们直接让启动类实现WebMvcConfigure接口

@SpringBootApplication
public class Application implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        // 请注意下面这个映射,将资源路径 /ts 下的资源,映射到根目录为 /ts的访问路径下
        // 如 ts下的ts.html, 对应的访问路径 /ts/ts
        registry.addResourceHandler("/ts/**").addResourceLocations("classpath:/ts/");
    }


    public static void main(String[] args) {
        SpringApplication.run(Application.class);
    }
}
复制代码

根据上面的配置表示将/ts目录下的资源ts.html,映射到/ts/ts,而直接访问/ts会报404(这个逻辑可能有点绕,需要仔细想一想)

@GetMapping(path = "ts")
public String ts() {
    return "ts.html";
}

@GetMapping(path = "ts/ts")
public String ts2() {
    return "ts.html";
}
复制代码



III. Jar包资源访问

前面描述的静态资源访问主要都是当前包内的资源访问,如果我们的静态资源是由第三方的jar包提供(比如大名鼎鼎的Swagger UI),这种时候使用姿势是否有不一样的呢?

1. classpath 与 classpath*

在之前使用SpringMVC3+/4的时候,classpath:/META-INF/resources/表示只扫描当前包内的/META-INF/resources/路径,而classpath*:/META-INF/resources/则会扫描当前+第三方jar包中的/META-INF/resources/路径

那么在SpringBoot2.2.1-RELEASE版本中是否也需要这样做呢?(答案是不需要,且看后面的实例)

2. 实例

新建一个工程,只提供基本的html静态资源,项目基本结构如下(具体的html内容就不粘贴了,墙裂建议有兴趣的小伙伴直接看源码,阅读效果更优雅)



接着在我们上面常见的工程中,添加依赖

<dependency>
    <groupId>com.git.hui.boot</groupId>
    <artifactId>204-web-static-resources-ui</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
复制代码

添加对应资源的访问端点

@GetMapping(path = "ui")
public String ui() {
    return "ui.html";
}

@GetMapping(path = "out")
public String out() {
    return "out.html";
}

// 第三方jar包的 META-INF/resources 优先级也高于当前包的 /static

@GetMapping(path = "s2")
public String s2() {
    return "s2.html";
}
复制代码

请注意,这个时候我们是没有修改前面的spring.resources.static-locations配置的



上面的访问结果,除了说明访问第三方jar包中的静态资源与当前包的静态资源配置没有什么区别之外,还可以得出一点

  • 相同资源路径下,当前包的资源优先级高于jar包中的静态资源
  • 默认配置下,第三方jar包中META-INF/resources下的静态资源,优先级高于当前包的/resources, /static, /public

IV. 其他

0. 项目

  • 工程:github.com/liuyueyi/sp…
  • 源码:github.com/liuyueyi/sp…
  • github.com/liuyueyi/sp…

1. 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

学习记录的代码,部分参考自gitee码云的如下两个工程。这两个个工程有详尽的Spingboot1.x和2.x教程。鸣谢!

https://gitee.com/didispace/SpringBoot-Learning.git

https://gitee.com/jeff1993/springboot-learning-example.git

本学习记录的示例代码克隆地址,分支为develop

https://gitee.com/kutilion/MyArtifactForEffectiveJava.git

静态资源

通常实际的项目中会引入大量的静态资源。比如图片,样式表css,脚本js,静态html页面等。这章主要学习引入模板来实现访问静态资源。

一般Springboot提供的默认静态资源存放位置是/resources之下。html的文件一般存放在/resources/templates中。

渲染静态页面通常会用到模板。模板种类很多,这里介绍两种:

  • Thymeleaf
  • FreeMarker

另外比较常用的模板还有velocity,但是velocity在Springboot1.5开始就不被支持了。

示例相关代码如下:

Thymeleaf

  • studySpringboot.n06.webframework.web.WebController.java
  • templates/06_webframework/thymeleaf.html

FreeMarker

  • studySpringboot.n06.webframework.web.WebController.java
  • templates/06_webframework/freemarker.ftl

Thymeleaf

build.gradle

为了使用Thymeleaf模板,需要在build.gradle脚本中引入模板引擎的依赖

implementation 'org.springframework.boot:spring-boot-starter-thymeleaf

WebController.java

控制器类中声明访问路径,并且为模板添加一个变量

 @RequestMapping("/thymeleaf")
 public String ThymeleafTest(ModelMap map) {
 map.addAttribute("host", "http://blog.kutilionThymeleaf.com");
 return "06_webframework/thymeleaf"; 
 }

注意这个方法的返回值,因为静态页面没有直接放在templates文件夹下,而是放在templates文件夹的子文件夹06_webframework中,所以返回值中要把路径带上

thymeleaf.html

静态页面中使用了el表达式,可以将java变量反映到页面上

<!DOCTYPE html>
<html>
<head lang="en">
 <meta charset="UTF-8" />
 <title></title>
</head>
<body>
<h1 th:text="${host}">This Thymeleaf framework test page.</h1>
</body>
</html>

执行结果:

FreeMarker

原理和Thymeleaf基本是一样的

build.gradle

implementation 'org.springframework.boot:spring-boot-starter-freemarker'

WebController.java

 @RequestMapping("/freemarker")
 public String FreeMarkerTest(ModelMap map) {
 map.addAttribute("host", "http://blog.kutilionFreemarker.com");
 return "06_webframework/thymeleaf";
 }

freemarker.ftl

<!DOCTYPE html>
<html>
<head lang="en">
 <meta charset="UTF-8" />
 <title></title>
</head>
<body>
<h1 th:text="${host}">This Freemarker framework test page.</h1>
</body>
</html>

执行结果:

总结

  • 引入并且使用了Thymeleaf和FreeMarker模板
  • Springboot默认已经配置好这两种模板了,如果需要手动配置需要参考两种模板的文档