最近从事的工作是web方面的,主要j2ee,spring jsp这些内容,由于刚入门,很多的技术都不了解。所谓初生牛犊不怕虎,刚入门,各种不顺手,比如写jsp,总是重复很多的代码,各种不爽,然后就去看jsp的模板技术,

看来看去也是各种不爽,于是就有了自己写一个工具的想法。

ok,废话一堆。先说说jsp模板,最简单的include,成熟的解决有tiles,还有什么setmesh,当日还有更强大的什么fremaker,volocity(是这样写的吗,记不清楚)等等。

include不说,实在太简陋,tiles其实是很不错的,不是很重,学习成本还算好,用的也比较广吧,当然要说广,肯定有后面那几个了。可是这些对我来说,都太重。我要的是什么样的?我记得rails里面的模板,大概就是layout里面写一句yield就ok了。

没错,这就是我想要的。写好layout,把什么header、menu什么的搞定,内容里面一个div套着一个yield,你就可以专注于你的子视图了,框架自动把layout应用到你的视图上去。

就这个简单的功能,为什么要那么复杂的框架、插件呢?

不过jsp,看看好像还真没有。那就自己实现吧,反正我是初入门,什么都不知道,不知者无畏嘛。

屁话一堆,总算到该说些正题了。

那么,怎么实现呢?我的思路是,layout里面写好布局后,正文部分就用${yield}代替,

当请求子视图的时候,自动的将子视图插入到layout中,替换${yield},然后生成一个新的合成视图,存入缓存文件中,由新的视图相应前端的请求。

我们知道spring里面有个配置viewresolver的类,可以在有请求的时候,查找视图,构建视图,并返回给前端。我们就在这里做我们的事情。

我们继承一个InternalResourceViewResolver,该resolver会根据视图查找相应的InternalResourceView来处理jsp视图。InternalResourceViewResolver有一个buildView的调用,该调用根据视图名称构建view。

我们就重载这个方法,根据前面的思路,首先找到模板文件和子视图,然后替换掉模板文件中的${yield},写入到新的jsp文件,然后重定向到该文件,就ok了。具体看代码:

 package lin.layoutsample.framework;

 import lin.layoutsample.utils.FileUtils;
import lin.layoutsample.utils.StringUtils; import org.springframework.web.servlet.view.AbstractUrlBasedView;
import org.springframework.web.servlet.view.InternalResourceViewResolver; public class LayoutViewResolver extends InternalResourceViewResolver { private static String DEFUALT_YIELD_CMD = "${yield}";
private static String DEFUALT_LAYOUT_TEMP_DIR = "/WEB-INF/layout/layout_temp";
private static String DEFUALT_LAYOUT = "/WEB-INF/layout/layout.jsp"; /**
* layout文件。默认为/WEB-INF/layout/layout.jsp。
* */
private String layout = DEFUALT_LAYOUT; /**
* 经过替换后的视图缓存目录,默认为/WEB-INF/layout/layout_temp。
* */
private String temp_path = DEFUALT_LAYOUT_TEMP_DIR; /**
* 默认为${yield}。模板中该命令会被子视图替换。类似rails的yield。
* */
private String yield_cmd = DEFUALT_YIELD_CMD; /**
*
* 函数首先根据指定的view在缓存区生成对应的文件,然后将模板文件(默认为layout.jsp)中的${yield}替换成视图的内容。
* 再调用超类的buildview函数生成新的被视图并返回。这样就完成了模板的替换和重定向到新生成的视图。
* */
@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
String url = getPrefix() + viewName + getSuffix();
String target_view_real_path = super.getServletContext().getRealPath(
getTemp_path())
+ url;
FileUtils.createFile(target_view_real_path);
String layout_real_path = super.getServletContext().getRealPath(
getLayout());
String layout_content = FileUtils.read(layout_real_path);
String view_content = FileUtils.read(super.getServletContext()
.getRealPath(url));
String result_view_content = StringUtils.replace(layout_content, "\\Q"
+ getYield_cmd() + "\\E", view_content);
FileUtils.write(target_view_real_path, result_view_content); AbstractUrlBasedView view = super.buildView(getTemp_path() + getPrefix()+ viewName);
return view;
} public String getLayout() {
return layout;
} public void setLayout(String layout) {
this.layout = layout;
} public String getTemp_path() {
return temp_path;
} public void setTemp_path(String temp_path) {
this.temp_path = temp_path;
} public String getYield_cmd() {
return yield_cmd;
} public void setYield_cmd(String yield_cmd) {
this.yield_cmd = yield_cmd;
}
}

是不是很简单?只需要一个方法,然后就是在web的配置里面将默认的InternalResourceViewResolver 替换成我们的就可以了。

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" 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:dwr="http://www.directwebremoting.org/schema/spring-dwr"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.directwebremoting.org/schema/spring-dwr
http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
"> <!-- 自动扫描controller包下的所有类,使其认为spring mvc的控制器 -->
<context:component-scan base-package="lin.layoutsample.controller" /> <!-- 通过注解,把URL映射到Controller上,该标签默认注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter -->
<mvc:annotation-driven /> <!-- 对模型视图名称的解析,即在模型视图名称添加前后缀 -->
<bean class="lin.layoutsample.framework.LayoutViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp" />
<property name="layout" value="/WEB-INF/layout/layout.jsp" />
</bean>
</beans>

这里我们可以配置我们的模板文件(一般叫layout.jsp)的路径,当然你也可以不用${yield}来占位,你可以自己配置成属性就行了。

完整的layout.jsp文件如下,路径我一般放在/WEB-INF/layout/下面。

 <%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!DOCTYPE html>
<html>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
<base href="<%=basePath%>">
<head>
<%@include file="/WEB-INF/layout/_include.jsp"%>
<title>花花世界</title>
</head>
<body>
<%@include file="/WEB-INF/layout/_header.jsp"%> <div class="container-fluid">
<div class="row">
<%@ include file="/WEB-INF/layout/_menu.jsp"%>
<div class="page-content">
<div class="container-fluid" data-role="main">
<!-- Main component for a primary marketing message or call to action --> ${yield} </div>
<!-- container-fluid -->
</div>
<!-- page-content -->
</div> </div>
<!-- /container --> <%@include file="/WEB-INF/layout/_import.jsp"%>
</body>
</html>

子视图就很简单了只需要一行示例代码就行了,文件say-hi.jsp如下。

 <h2>hi world!!</h2>

我们的控制器完全不需要考虑模板的事情,新建一个子视图返回就行了。

 package lin.layoutsample.controller;

 import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView; @Controller
@RequestMapping("/hello")
public class HelloController {
private Logger logger = LoggerFactory.getLogger(HelloController.class); @RequestMapping("/say-hi")
public ModelAndView sayHi(){
logger.debug("HelloController:sayHi");
ModelAndView mv = new ModelAndView("WEB-INF/views/say-hi");
return mv;
}
}

效果如下图:

是不是很简单,对开发者来说,只需要配置一下,别的都不需要关心,就可以完成模板布局的应用了。

不过我是初学,入门,哪些商业的模板工具自然有他得用武之地,我这个超轻量级的模板解决方案,写写小网页还是足够了。

有兴趣的tx可以去github上下载我的代码https://github.com/linbirg/wish。

欢迎大神批评指正。

超轻量级spring模板方案的更多相关文章

  1. 腾讯正式开源高性能超轻量级 PHP 框架 Biny

    概况 Biny是一款高性能的超轻量级PHP框架 遵循 MVC 模式,用于快速开发现代 Web 应用程序 Biny代码简洁优雅,对应用层,数据层,模板渲染层的封装简单易懂,能够快速上手使用 高性能,框架 ...

  2. dnspod-sr内网轻量级DNS首选方案 - 运维生存时间

    dnspod-sr内网轻量级DNS首选方案 - 运维生存时间 undefined

  3. Discuz3.3精仿小米风格整站模板制作——1、新建模板方案

    术语说明: 模板——模板是一堆按照规定命名方式的html文件,用于指定整个论坛不同页面的外观. 标签——标签和模板共同作用以实现论坛换肤功能,其中标签主要控制页面显示什么数据,显示多少条等. 风格—— ...

  4. 解读超轻量级DI容器-Guice与Spring框架的区别【转载】

    依赖注入,DI(Dependency Injection),它的作用自然不必多说,提及DI容器,例如spring,picoContainer,EJB容器等等,近日,google诞生了更轻巧的DI容器… ...

  5. 【sping揭秘】25、Spring远程方案

    分化:RMI,EJB,Hessian Spring有 Rmi,http,hessian,burlap 基于rmi的remoting方案 RMI要求远程类对象包路径和本地一致 基于HTTP的轻量级rem ...

  6. MongoDB系列三(Spring集成方案).

    一.前言 MongoDB是最为流行的开源文档数据库之一.Spring Data MongoDB提供了三种方式在Spring应用中使用MongoDB: 通过注解实现对象-文档映射: 使用MongoTem ...

  7. 超详细 Spring @RequestMapping 注解使用技巧

    @RequestMapping 是 Spring Web 应用程序中最常被用到的注解之一.这个注解会将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上. 在这篇文章中,你将会看到 @R ...

  8. 传统Java Web(非Spring Boot)、非Java语言项目接入Spring Cloud方案

    技术架构在向spring Cloud转型时,一定会有一些年代较久远的项目,代码已变成天书,这时就希望能在不大规模重构的前提下将这些传统应用接入到Spring Cloud架构体系中作为一个服务以供其它项 ...

  9. 超详细 Spring @RequestMapping 注解使用技巧 (转)

    @RequestMapping 是 Spring Web 应用程序中最常被用到的注解之一.这个注解会将 HTTP 请求映射到 MVC 和 REST 控制器的处理方法上. 在这篇文章中,你将会看到 @R ...

随机推荐

  1. Android设置布局背景为白色的三种方法

    一.在xml文件里可以直接设置: android:background="#ffffff" 其他颜色可以看这里;http://blog.csdn.net/yanzi1225627/ ...

  2. 根据中国气象局提供的API接口实现天气查询

    中国气象局提供了三个天气查询的API接口: [1]http://www.weather.com.cn/data/sk/101190101.html [2]http://www.weather.com. ...

  3. asp.net输出docx文档出现【文件已损坏 无法打开】问题的解决方案

    在某个项目中,有个需求需要将一些附件文档以字节流的形式直接存储在数据库中. 功能实现后,尝试过很多格式文件的上传下载处理,均未发现问题, 唯独在下载docx格式文件后,一打开文件就提示: “无法打开文 ...

  4. c& c++ enum

    1.为什么要用enum       写程序时,我们常常需要为某个对象关联一组可选alternative属性.例如,学生的成绩分A,B,C,D等,天气分sunny, cloudy, rainy等等.   ...

  5. Jedis的JedisSentinelPool源代码分析

    概述 Jedis是Redis官方推荐的Java客户端,更多Redis的客户端可以参考Redis官网客户端列表.Redis-Sentinel作为官方推荐的HA解决方案,Jedis也在客户端角度实现了对S ...

  6. 转载:看c++ primer 学习心得

    学习C++ Primer时遇到的问题及解释 chenm91 感觉: l          啰嗦有时会掩盖主题:这本书确实有些啰嗦,比如在讲函数重载的时候,讲了太长一大段(有两节是打了*号的,看还是不看 ...

  7. Matlab编程实例(2) 同期平均

    %多点同期平均 close all; clear all; pi = 3.14159; Samp2=input('您需要几组信号做同期平均?') Samp1=1000 %设置采样精度 t = lins ...

  8. poj1247 bjfu1239水题

    其实就是读题啦,读懂题很简单,就是问一个数组,存不存在一个点,按这个点切成两半,这两半的数字的和是一样的.不多说了,上代码 /* * Author : ben */ #include <cstd ...

  9. 细雨学习笔记:Jmeter测试计划最基本的元素

    测试计划-用户组下最基本的元素: 1)HTTP请求默认值 2)HTTP Cookie 管理器(有些操作需要登录后才能访问,用户信息记录在Cookie中,各请求之间就可以共享Cookie了) 3)请求S ...

  10. bzoj 3143 [Hnoi2013]游走(贪心,高斯消元,期望方程)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3143 [题意] 给定一个无向图,从1走到n,走过一条边得到的分数为边的标号,问一个边的 ...