`
紫_色
  • 浏览: 144422 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Spring mvc系列八之 页面静态化(二)

阅读更多

前一章讲到页面静态化当中freeMarker标签的使用,这一章我们使用spring mvc结合freeMarker处理大型网站页面静态化.

第一步:引入除spring mvc 所需的jar包(之前系列的文章讲过,大家可以看之前的文章),还需要引入freemarker-xxx.jar commons-logging-xxx.jar  

 

第二步:扩展FreeMarkerView,使我们可以控制是否生成静态页面以及生成的静态页面存放的位置.

package gd.hz;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerView;

import freemarker.template.SimpleHash;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class ExFreeMarkerView extends FreeMarkerView {
	 @Override
	    protected void doRender(Map<String, Object> model,
	            HttpServletRequest request, HttpServletResponse response)
	            throws Exception {
		 
	        exposeModelAsRequestAttributes(model, request);
	        
	        SimpleHash fmModel = buildTemplateModel(model, request, response);
	 
	        if (logger.isDebugEnabled()) {
	            logger.debug("Rendering FreeMarker template [" + getUrl() + "] in FreeMarkerView '" + getBeanName() + "'");
	        }
	        
	        Locale locale = RequestContextUtils.getLocale(request);
	         
	        /*
	         * 在这里我们默认生成静态文件,当ModelAndView有指定STATIC_HTML = false时,就不会输出HTML文件
	         * 例如:ModelAndView modelAndView = new ModelAndView("htmlTest");
	         *       modelAndView.addObject("STATICHTML", false); 
	         */
	        if(Boolean.FALSE.equals(model.get("STATIC_HTML"))){
	            processTemplate(getTemplate(locale), fmModel, response);
	        }else{
	            createHTML(getTemplate(locale), fmModel, request, response);
	        }
	    }
	 
	    public void createHTML(Template template, SimpleHash model,HttpServletRequest request,
	            HttpServletResponse response) throws IOException, TemplateException, ServletException {
	            //站点根目录的绝对路径
	            String basePath = request.getSession().getServletContext().getRealPath("/");
	            String requestHTML = this.getRequestHTML(request);
	            
	            //静态页面绝对路径
	            String htmlPath = basePath + requestHTML;
	             
	            File htmlFile = new File(htmlPath);
	            
	            if(!htmlFile.getParentFile().exists()){
	                htmlFile.getParentFile().mkdirs();
	            }
	            
	            /**
	             * 如果静态页面已经存在,就不再创建静态页面.
	             */
	            if(!htmlFile.exists()){
	                htmlFile.createNewFile();
	                Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(htmlFile), "UTF-8"));
		            //处理模版  
		            template.process(model, out);
		            out.flush();
		            out.close();
	            }
	            /*将请求转发到生成的htm文件*/
	            request.getRequestDispatcher(requestHTML).forward(request, response);
	    }
	     
	    /**
	     * 计算要生成的静态文件相对路径.
	     */
	    private String getRequestHTML(HttpServletRequest request){
	        
	    	//web应用名称,部署在ROOT目录时为空
	        String contextPath = request.getContextPath();
	        
	        //web应用/目录/文件.do
	        String requestURI = request.getRequestURI();
	        
	        //basePath里面已经有了web应用名称,所以直接把它replace掉,以免重复
	        requestURI = requestURI.replaceFirst(contextPath, "");
	       
	        //将.do改为.htm,稍后将请求转发到此htm文件
	        requestURI = requestURI.substring(0, requestURI.indexOf(".")) + ".htm";
	         
	        return requestURI;
	    }
}

 这里我们取出STATIC_HTML的值,当为false是就不生成静态页面.

而getRequestHTML()方法是生成静态页面的相对路径,这里我们可以灵活处理,可以决定静态页面的存放路径.

 

第三步:配置spring mvc配置文件,这里我的文件名为springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="      
           http://www.springframework.org/schema/beans      
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd      
           http://www.springframework.org/schema/context      
           http://www.springframework.org/schema/context/spring-context-3.0.xsd     
           http://www.springframework.org/schema/mvc      
           http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
	<!-- 开启注解扫描功能 -->
	<context:component-scan base-package="gd.hz.controller"></context:component-scan>

	<!-- 将上面两个注解和并 -->
	<mvc:annotation-driven />

	
    <!--freemarker页面解析器 -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
        <property name="suffix" value=".ftl"></property>
        <property name="contentType" value="text/html;charset=UTF-8" />
<!--         <property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" /> -->
        <!-- 将Spring的FreeMarkerView改成我们扩展的View -->
        <property name="viewClass" value="gd.hz.ExFreeMarkerView" />
        <property name="exposeRequestAttributes" value="true" />
        <property name="exposeSessionAttributes" value="true" />
        <property name="exposeSpringMacroHelpers" value="true" />
    </bean>
 
    <bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />
 
    <!--配置Freemarker -->
    <bean id="freemarkerConfigurer"
        class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
        <!-- 模版页面存放的位置 -->
         <property name="templateLoaderPath" value="/ftl/"></property>
        <property name="freemarkerVariables">
            <map>
                <entry key="xml_escape" value-ref="fmXmlEscape" />
            </map>
        </property>
        <property name="freemarkerSettings">
            <props>
                <prop key="template_update_delay">10</prop>
                <prop key="defaultEncoding">UTF-8</prop>
            </props>
        </property>
    </bean>
    
    <!-- 下面要声明在模版后面 -->
    <bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- JSP页面存放的位置 -->
		<property name="prefix" value="/jsp/" />
		<property name="suffix" value=".jsp" />
	</bean> 
</beans>

 这里页面额外说明的是,如果我们想一个网站有使用freeMarker和jsp时,也可以在配置文件中声明如:

<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<!-- JSP页面存放的位置 -->
		<property name="prefix" value="/jsp/" />
		<property name="suffix" value=".jsp" />
	</bean> 

 这句话要声明在使用freeMarker配置下面,这样当处sping 找不到相关页面模板时就会找相关名称的jsp页面.另外还需要声明使用我们扩展的ExFreeMarkerView.

 

第四步:创建测试页:

模板页:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
</head>
<body>
	${content}
</body>
</html>

JSP页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
</head>
<body>
我是从jsp过来的.${content }
</body>
</html

  

 

 

 

第五步:Controller

package gd.hz.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller("indexController")
public class IndexController {

    @RequestMapping("index")
    public ModelAndView index(){
        ModelAndView modelAndView = new ModelAndView("index");
        modelAndView.addObject("content", "网站标题");
        
        //当设置false时不生成静态页面
        modelAndView.addObject("STATIC_HTML", false);
        
        return modelAndView;
    }
    
    @RequestMapping("html/index")
    public ModelAndView htmlIndex(){
        ModelAndView modelAndView = new ModelAndView("index");
        //默认是生成静态页面的
        modelAndView.addObject("content", "网站标题");
        return modelAndView;
    }
    
    //jsp测试
    @RequestMapping("jsp/index")
    public ModelAndView jspindex(){
        ModelAndView modelAndView = new ModelAndView("test");
        modelAndView.addObject("content", "网站标题");
        return modelAndView;
    }
}

 首先看一下第一个请求,这里我们声明STATIC_HTML=false,不生成静态页面.第二个请求,我们生成的静态页面,根据ExFreeMarkerView中的定义,会跳转到静态页面.

第三个请求,因为没有test.ftl,这样spring 会去找test.jsp页面,所发请求会到test.jsp.

 

经过上面的三种方法,我们使用在进行大型网站开发时,可以灵活运用,可以在页面的某些数据变化少的地方进行部分页面静态化.也可以根据需求,只请求JSP页面.

 

分享到:
评论
4 楼 游其是你 2014-04-01  
紫_色 写道
扩展的ExFreeMarkerView类是用于页面静态化的.是没有问题的.
游其是你 写道
liuxinga001 写道
请教下:使用html/index测试时总是报错误:
javax.servlet.ServletException: Cannot expose request attribute 'content' because of an existing model object of the same name
是什么问题?

这个问题是扩展的ExFreeMarkerView类有问题,你用最原始的类替换掉这个类就可以了。

扩展的ExFreeMarkerView类是用于页面静态化的.是没有问题的.



嗯,谢谢。但是我用楼主扩展的这个类跟1楼出现了相同的问题,然后我用Spring 的freemark类替换掉楼主的这个方法就不报错了,不知道楼主是怎么使用的,能否提供一个完整的例子呢?就是这篇文章的例子,谢谢!我的企鹅是996475895,如果不方便也可以发送到我的QQ邮箱,不胜感激。

楼主的这系列文章写的很不错,真心赞一个。
3 楼 紫_色 2014-03-28  
扩展的ExFreeMarkerView类是用于页面静态化的.是没有问题的.
游其是你 写道
liuxinga001 写道
请教下:使用html/index测试时总是报错误:
javax.servlet.ServletException: Cannot expose request attribute 'content' because of an existing model object of the same name
是什么问题?

这个问题是扩展的ExFreeMarkerView类有问题,你用最原始的类替换掉这个类就可以了。

扩展的ExFreeMarkerView类是用于页面静态化的.是没有问题的.
2 楼 游其是你 2014-03-28  
liuxinga001 写道
请教下:使用html/index测试时总是报错误:
javax.servlet.ServletException: Cannot expose request attribute 'content' because of an existing model object of the same name
是什么问题?

这个问题是扩展的ExFreeMarkerView类有问题,你用最原始的类替换掉这个类就可以了。
1 楼 liuxinga001 2013-07-03  
请教下:使用html/index测试时总是报错误:
javax.servlet.ServletException: Cannot expose request attribute 'content' because of an existing model object of the same name
是什么问题?

相关推荐

    Spring MVC 教程快速入门 深入分析

    八、Spring MVC请求如何映射到具体的Action中的方法:说明了如何配置映射器(HandlerMapping)将用户请求映射到具体的控制器方法。 九、Spring MVC中的拦截器:拦截器是Spring MVC提供的一个可插入的组件,可以用来...

    Spring mvc 教程

    ### Spring MVC 教程知识点详解 #### Spring Web MVC 框架简介 Spring Web MVC 是 Spring Framework 的一个重要组成部分,主要用于构建基于 Java 的 Web 应用程序。它提供了一个灵活且强大的 MVC 实现,使得开发者...

    Spring MVC入门教程

    七、spring mvc 如何访问到静态的文件,如jpg,js,css? 八、spring mvc 请求如何映射到具体的Action中的方法? 九、spring mvc 中的拦截器: 十、spring mvc 如何使用拦截器? 十一、spring mvc 如何实现全局的异常...

    spring mvc restful service

    5. **项目结构**:一个典型的Spring MVC Maven项目结构包括`src/main/java`(存放源代码)、`src/main/resources`(存放配置文件和静态资源)、`src/main/webapp/WEB-INF`(存放`web.xml`配置文件)等。 6. **配置...

    Spring MVC框架简介和使用

    DispatcherServlet 是 Spring MVC 的核心组件之一,负责接收请求并分发给合适的控制器进行处理。其启动流程大致如下: 1. **类的继承关系**:`DispatcherServlet` 继承自 `FrameworkServlet`,而 `FrameworkServlet...

    基本的spring mvc + spring security实现的登录(无数据库)

    - 通常包含src/main/java目录下的Controller、Service、DAO层以及配置类,src/main/resources下可能有Spring MVC和Spring Security的配置文件,webapp下是静态资源和视图文件。 7. **学习重点**: - 理解Spring ...

    spring mvc

    DispatcherServlet 是 Spring MVC 中的核心组件之一,它作为前端控制器的角色,主要负责以下任务: - **初始化**:读取配置文件并初始化 Spring 容器。 - **请求处理**:处理所有进入系统的 HTTP 请求。 - **响应...

    Spring MVC 教程 快速入门 深入分析

    二、spring mvc 核心类与接口 三、spring mvc 核心流程图 四、spring mvc DispatcherServlet说明 五、spring mvc 双亲上下文的说明 六、springMVC-mvc.xml 配置文件片段讲解 七、spring mvc 如何访问到静态的文件,...

    spring mvc mybatis velocity 示范

    总结起来,Spring MVC提供了MVC模式的实现,MyBatis简化了数据库操作,Velocity则负责页面渲染。这三者结合,构建出了一套高效、模块化的Java Web开发解决方案。开发者可以根据需求灵活配置,实现快速开发和维护。

    spring mvc项目创建

    Spring MVC 是一个基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的一部分,主要用于构建 MVC(Model-View-Controller)模式的 Web 应用程序。在本项目创建过程中,我们将深入探讨如何配置一个基本的 Spring ...

    Spring+Spring MVC+Spring JDBC+MySql实现简单登录注册

    在本项目中,我们主要利用Spring框架,包括其核心模块Spring、MVC模块Spring MVC以及数据访问/集成模块Spring JDBC,结合MySQL数据库来构建一个基础的登录注册系统。以下是这个项目涉及的关键技术点: 1. **Spring...

    jQuery Spring MVC

    3. **视图解析**:Spring MVC 通过`ViewResolver`处理视图解析,jQuery 则负责客户端的页面动态更新,两者协同工作,可以实现局部刷新。 ### jqGrid 示例 `jqGrid`是一个强大的jQuery插件,用于创建数据网格,支持...

    spring mvc+spring+maven框架项目,纯净项目

    Spring MVC、Spring 和 Maven 是Java开发中非常重要的三个框架,它们在构建现代企业级Web应用程序中扮演着核心角色。这个"spring mvc+spring+maven框架项目"提供了一个纯净的基础,便于开发者快速搭建和理解这三者...

    spring mvc demo下载地址

    这个简易的Spring MVC demo包含了一系列关键知识点,对于初学者来说是很好的学习资源。下面将详细阐述这些知识点: 1. **MVC模式**:Spring MVC的核心设计模式,它将应用程序分为三个主要部分:模型(Model)、视图...

    spring-mvc 基础功能之源码debug

    这篇博客“spring-mvc 基础功能之源码debug”似乎深入探讨了Spring MVC的核心功能,并通过源码级别的调试来帮助读者理解其工作原理。 首先,我们来看Spring MVC的请求处理流程。当一个HTTP请求到达服务器时,...

    java 页面静态化

    - **PageCache**:一些Web框架如Spring MVC提供了内置的缓存机制,可以用于实现页面静态化。 - **Nginx** 或 **Apache** 的URL重写功能:可以通过配置规则,将动态请求重定向到对应的静态HTML文件。 在进行页面静态...

    spring mvc过程详解

    Spring MVC 作为一种成熟且高性能的 MVC 框架,已经成为了现代 Java Web 开发的首选工具之一。其简洁的设计理念、强大的功能集和出色的性能表现使其在众多框架中脱颖而出。无论是在大型企业级应用还是中小规模项目中...

    页面静态化

    页面静态化是Web开发中的一个重要概念,主要目的是提高网站的访问速度和搜索引擎优化(SEO)。在Java Web开发中,页面静态化通常涉及到将动态生成的HTML页面转化为纯HTML文件,以便用户请求时无需通过服务器执行复杂...

    jetty 手动 加载spring mvc demo

    在本文中,我们将深入探讨如何不依赖于自动化工具或集成开发环境(IDE)来完成这个过程,这对于理解Spring MVC与Jetty的底层交互以及提升手动配置技能非常有帮助。 首先,让我们了解Jetty。Jetty是一个轻量级、高...

Global site tag (gtag.js) - Google Analytics