java-springmvc4+freemarker-实现layout布局页

java-springmvc4+freemarker-实现layout布局页


使用 jsp 开发业务系统时,一般一个页面的js脚本针对当前页面的逻辑比较复杂无法公用,js 又常常更新。
客户端由于缓存问题,浏览器会缓存js到本地,不去下载最新的 js 文件(除非引用js时加版本号,如:order.js?v=1.0)


为了解决以上开发问题,可以将 js 写到 jsp 页面的下方,这样就可以每次加载页面时下载最新的 js 了。


但是,在开发时就不方便了。开发时经常需要看“html 结构”还要看“js 逻辑”,这时需要上下不停拖动jsp编辑器的滚动条。


为了解决上述问题:可以考虑在开发时,使 jsp 和 js 页面分离,再响应时将js文件合并到 jsp 中进行输出。


这样既保证了开发的时效和开发体验,也兼顾了客户端得不到最新js导致的各种问题。


下面,利用 maven + springmvc + freemarker 实现布局页,开发时将一个页面分割成三部分,使用时组合成一个页面输出:
1.layout 部分:只定义布局
2.js 部分:只定义当前页面使用的 js 脚本
3.body 部分:只定义页面中 body 标签内容的内容


约定:三部分必须有相同的前缀,如 order 页面,分为三部分时个文件的命名为:
1.layout 部分:orderLayout.ftl
2.js 部分:orderJs.js
3.body 部分:orderViewer.ftl


目标:实现两种 jsp 响应方式;
1.jsp(模板+数据)在请求时同时输出
2.只输出页面和js,数据使用 ajax 请求


前置:已经搭建好 springmvc + freemarker 项目,项目命名为 mavens-web


1.目录结构
1.1 后台代码目录
-demo
.+-mvc
..+-base
...|-PageController.java
..+-controllers
...|-HelloController.java


1.2 前端代码目录
-webapp
.+-views
..+-hello  //对应 controller 名
...+-js
....|-indexJs.js
....|-masterJs.js
...+-layout
....|-indexLayout.ftl
....|-masterLayout.ftl
...+-pub
....|-indexViewer.ftl
....|-masterViewer.ftl


2.controller 代码
2.1 控制器基类 PageController.java
package demo.mvc.base;


import java.io.File;
import java.util.Map;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


import freemarker.cache.*;


/** 
*
*/
public abstract class PageController {
	/**
	 * 控制器名称,不包含“Controller”后缀
	 * @param controllerName
	 */
	public PageController(String controllerName){
		ctrlName= controllerName.toLowerCase();
	}
	String ctrlName="";
	@Autowired
	org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer _fmc;
	//static freemarker.cache.FileTemplateLoader _ftl = null;
	static String _templateLoaderPath=null;
	/**
	 * 初始化 freemarker 模板地址
	 * 
	 */
	boolean initTemplateLoaderPath() {
		if(_templateLoaderPath!=null)
			return true;
		gsPrintln("_fmc = {0}", _fmc==null?"null":_fmc.toString());
		//布局模板是否存在
		if(_fmc!=null){
			MultiTemplateLoader utll = (MultiTemplateLoader)_fmc
					.getConfiguration()					
					.getTemplateLoader();
			int n=utll.getTemplateLoaderCount();
			gsPrintln("TemplateLoaderCount="+n);
			TemplateLoader tl = null;
			File file = null;
			for(int i=0;i<n;i++) {
				tl= utll.getTemplateLoader(i);
				gsPrintln(tl.toString());
				//获取模板加载目录地址
				if(tl instanceof freemarker.cache.FileTemplateLoader){
					_templateLoaderPath = ((freemarker.cache.FileTemplateLoader)tl)
							.getBaseDirectory()
							.getAbsolutePath();
				}
			}
		}
		gsPrintln("freemark 模板地址:{0}", _templateLoaderPath);
		return _templateLoaderPath!=null;
	}
	/**
	 * 判断模板是否存在
	 * @param filePath
	 * @return
	 */
	boolean IsExistsTemplate(String filePath){
		initTemplateLoaderPath();
		File file = new File(gsFormat("{0}/{1}", _templateLoaderPath,filePath));
		boolean exist = file.exists();
		gsPrintln("viewer[{1}]:{0}",file,exist);
		return exist;
	}
	/**
	 * 公共视图解析器:controllerName/viewer/{file}/{prefix}
	 * @param prefix
	 * @param pars
	 * @return
	 */
	@RequestMapping("viewer/{prefix}")
	public String viewer(@PathVariable String prefix
			,Map<String, Object> pars){
		return freeMarkerViewResult(prefix, pars);//布局模板
	}
	/**
	 * freemarker 布局视图解析
	 * @param prefix
	 * @param pars
	 * @return
	 */
	public String freeMarkerViewResult(String prefix
			,Map<String, Object> pars){
		//布局模板
		String layout = gsFormat("{0}/layout/{1}Layout.ftl", ctrlName,prefix);
		//js内容
		String js = gsFormat("{0}/js/{1}Js.js", ctrlName,prefix);
		if(!IsExistsTemplate(js)){
			js="";//不存在时,地址赋值为空
		}
		//页模板
		String body = gsFormat("{0}/pub/{1}Viewer.ftl", ctrlName,prefix);
		
		//页面参数
		pars.put("body_file_path", body);
		pars.put("js_file_path", js);
		
		//优先使用布局页
		if(IsExistsTemplate(layout)){
			return layout.replaceAll("\\.ftl$", ""); //模板不需要后缀
		}
		return body.replaceAll("\\.ftl$", "");//模板不需要后缀
	}
	public static void gsPrintln(String msg, Object... args){
		System.out.println(gsFormat(msg,args));
	}
	/**
	 * 字符串内容格式化输出,内部使用{0}\{1}\{2}...为参数占位符
	 * @param msg 格式化模板
	 * @param args 不固定参数
	 * @return
	 */
	public static String gsFormat(String msg, Object... args)
	{
		return java.text.MessageFormat.format(msg, args);
	}
}




2.1 hello 控制器 HelloController.java
package demo.mvc.controllers;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


import org.springframework.mail.MailParseException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;


import demo.models.hello.UserInfoModel;
import demo.mvc.base.PageController;


/** 
*
*/
@Controller
@RequestMapping("/hello")
public class HelloController extends PageController {
	public HelloController(){
		super("Hello"); //将当前 controller 名传入,与 viewer 中的 hello 文件夹名对应
	}
	/**
	 * 请求地址:项目名/hello/master
	 * @return
	 */
	@RequestMapping("master")
	public String freemarkerLayout(Map<String, Object> map){
		map.put("name", "张三");
		map.put("date", new Date());
		return this.freeMarkerViewResult("master", map);
	}
}




3. js 文件
3.1 webapp/views/hello/js/indexJs.js
<script language="JavaScript">
	function init(){
		document.write("<div>这个是 indexJs.ftl 内容</div>");
	}
	init();
</script>




3.2 webapp/views/hello/js/masterJs.js
<script language="JavaScript">
	function init(){
		document.write("<div>这个是 masterJs.ftl 内容</div>");
	}
	init();
</script>




4. layout 布局文件
4.1 webapp/views/hello/layout/indexLayout.ftl
<!doctype html>
<html>
 <head>
  <meta charset="UTF-8">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>index 布局页</title>
 </head>
 <body>
<#--body内容-->
<#include "${body_file_path}">
 </body>
</html>
<#--js内容,不进行 ftl 解析;include 地址为空时,不抛出异常-->
<#include "${js_file_path}" parse=false ignore_missing=true>




4.2 webapp/views/hello/layout/masterLayout.ftl
<!doctype html>
<html>
 <head>
  <meta charset="UTF-8">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>index 布局页</title>
 </head>
 <body>
<#--body内容-->
<#include "${body_file_path}">
 </body>
</html>
<#--js内容,不进行 ftl 解析;include 地址为空时,不抛出异常-->
<#include "${js_file_path}" parse=false ignore_missing=true>




5. 页面 body 部分
5.1 webapp/views/hello/pub/indexViewer.ftl
<div>
	这个是 indexViewer.ftl 页面内容
</div>
<#--模板+数据-->
<div>
</div>




5.2 views/hello/pub/masterViewer.ftl
<div>
	这个是 indexViewer.ftl 页面内容
</div>
<#--模板+数据-->
<div>
</div>




6.部署到 tomcat 测试页面
6.1 jsp(模板+数据)在请求时同时输出
http://localhost:8080/mavens-web/hello/master
6.2 只输出页面和js,数据使用 ajax 请求(这种方式可以手动在tomcat添加页面,然后修改与之对应的前缀名即可访问到页面,这里index 即是前缀名)

http://localhost:8080/mavens-web/hello/viewer/index





  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
springboot:是一个基于Java开发的框架,简化了Spring应用的初始化配置和部署过程。它提供了一套开发规范和约定,帮助开发人员快速搭建高效稳定的应用程序。 mybatis-plus:是基于MyBatis的增强工具,提供了一些便捷的CRUD操作方法和代码生成功能,简化了数据库操作的开发工作。它能够轻松集成到SpringBoot应用中,提高开发效率。 springmvc:是一种基于MVC设计模式的Web框架,用于构建Web应用程序。它能够从URL中解析请求参数,并将请求分发给对应的Controller进行处理。SpringMVC提供了一套灵活的配置和注解方式,支持RESTful风格的API开发。 shiro:是一种用于身份验证和授权的框架,可以集成到SpringBoot应用中。它提供了一套简单易用的API,可以处理用户认证、角色授权、会话管理等安全相关的功能。Shiro还支持集成其他认证方式,如LDAP、OAuth等。 redis:是一种开源的内存数据库,采用键值对存储数据。Redis具有高性能、高并发和持久化等特点,常用于缓存、消息队列和分布式锁等场景。在企业级报表后台管理系统中,可以使用Redis来进行缓存数据,提高系统的响应速度和性能。 企业级报表后台管理系统:是一种用于统一管理和生成报表的系统。它通常包括用户权限管理、报表设计、报表生成、数据分析等功能。使用SpringBoot、MyBatis-Plus、SpringMVC、Shiro和Redis等技术,可以快速搭建一个可靠、高效的报表管理系统,满足企业对数据分析和决策的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值