`

使用freemarker创建动态SQL

阅读更多

使用freemarker创建动态SQL

 

    使用Spring的JdbcTempl时为了让SQL文便于管理,一般采用的将SQL文写在静态的字符串常量中。形式如下:

public class UserDao {

	private static final String QUERY_USER_BY_ID = "select id, email, login_name from LOGIN_USER where id=?";
	private static final String QUERY_USER_BY_IDS = "select id, email, login_name from LOGIN_USER where id in(:ids)";
	private static final String QUERY_USER = "select id, email, login_name from LOGIN_USER order by id";
	private static final String QUERY_USER_BY_LOGINNAME = "select id,email,login_name from LOGIN_USER where login_name=:login_name";
	private static final String INSERT_USER = "insert into LOGIN_USER(id, login_name, email) values(:id, :loginName, :email)";

	private SimpleJdbcTemplate jdbcTemplate;

	private UserMapper userMapper = new UserMapper();

	private class UserMapper implements RowMapper<User> {
		public User mapRow(ResultSet rs, int rowNum) throws SQLException {
			User user = new User();
			user.setId(rs.getString("id"));
			user.setEmail(rs.getString("email"));
			user.setLoginName(rs.getString("login_name"));
			return user;
		}
	}

	public void setDataSource(DataSource dataSource) {
		jdbcTemplate = new SimpleJdbcTemplate(dataSource);
	}

	/**
	 * 查询单个对象.
	 */
	public User queryObject(String id) {
		return jdbcTemplate.queryForObject(QUERY_USER_BY_ID, userMapper, id);
	}

	/**
	 * 查询对象列表.
	 */
	public List<User> queryObjectList() {
		return jdbcTemplate.query(QUERY_USER, userMapper);
	}

	/**
	 * 查询结果Map列表.
	 */
	public List<Map<String, Object>> queryMapList() {
		return jdbcTemplate.queryForList(QUERY_USER);
	}

	/**
	 * 使用Map形式的命名参数.
	 */
	public User queryByNamedParameter(String loginName) {
		Map<String, Object> map = Maps.newHashMap();
		map.put("login_name", loginName);

		return jdbcTemplate.queryForObject(QUERY_USER_BY_LOGINNAME, userMapper, map);
	}

	/**
	 * 使用Map形式的命名参数.
	 */
	public List<User> queryByNamedParameterWithInClause(Long... ids) {
		Map<String, Object> map = Maps.newHashMap();
		map.put("ids", Arrays.asList(ids));

		return jdbcTemplate.query(QUERY_USER_BY_IDS, userMapper, map);
	}

	/**
	 * 使用Bean形式的命名参数, Bean的属性名称应与命名参数一致. 
	 */
	public void createObject(User user) {
		//使用BeanPropertySqlParameterSource将User的属性映射为命名参数.
		BeanPropertySqlParameterSource source = new BeanPropertySqlParameterSource(user);
		jdbcTemplate.update(INSERT_USER, source);
	}

	/**
	 * 批量插入/更新对象,使用Bean形式的命名参数.
	 */
	public void batchCreateObject(List<User> userList) {
		int i = 0;
		BeanPropertySqlParameterSource[] sourceArray = new BeanPropertySqlParameterSource[userList.size()];

		for (User user : userList) {
			sourceArray[i++] = new BeanPropertySqlParameterSource(user);
		}

		jdbcTemplate.batchUpdate(INSERT_USER, sourceArray);
	}

}

 

但是实际的项目中的SQL文不可能是这样固定的,他是有条件的动态SQL文,这时候可以使用freemarker来动态生成你需要的SQL文。可以在一个文件里面写SQL文:

<?xml version="1.0" encoding="utf-8" ?>
<commands>
  <command id="sel_login_user_001">
    <desription>
      SQL文的用途的描述。
      例:
      搜索用户时的动态条件SQL文。
    </desription>
    <sql><![CDATA[
		SELECT id, email, login_name 
		FROM login_user
		WHERE 1=1

		<#if loginName??>
		AND login_name=:loginName
		</#if>
		<#if email??>
		AND email=:email
		</#if>

		ORDER BY id
    ]]>
    </sql>
  </command>
...
</commands>

 

 /**
 * 使用freemarker生成sql的工具类.
 * 
 * @author tivan
 */
public class SQLParser {

	public static String getSql(String commandId, Map<String, ?> model) {
		try {
			Configuration cfg = new Configuration();
			StringTemplateLoader sTmpLoader = new StringTemplateLoader();
			sTmpLoader.putTemplate(commandId, getSqlTemplate(commandId));
			cfg.setTemplateLoader(sTmpLoader);
			cfg.setDefaultEncoding("UTF-8");
			Template template = cfg.getTemplate(commandId);    
	        StringWriter writer = new StringWriter();    
	        template.process(model, writer);    
			return writer.toString();
		} catch (TemplateException e) {
			throw new RuntimeException("Parse sql failed", e);
		} catch (IOException e) {
			throw new RuntimeException("Parse sql failed", e);
		}
	}
	
	public static String getSqlTemplate(String commandId) {
		// 取得配置文件中的SQL文模板
		return Commands.GetDbCommand(commandId);
	}
}

 

 使用freemarker生成sql的工具类,没有进行具体的性能测试,实际应用中应该考虑这些因素。

分享到:
评论
8 楼 无根V稻草 2011-04-11  
学习中~~~~~~~~
7 楼 olivechinese 2011-04-11  
楼主有没有测试过性能?
6 楼 joliny 2010-10-27  
不错,学习了。
5 楼 JetMah 2010-07-15  
tivan 写道

启动时把XML文件加载到java的Properties 里面。

代码大概如下

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.List;
import java.util.Properties;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class SQLBuildHelp {
...................
	Properties properties = new Properties();

	private static class Resolver implements EntityResolver {

		public InputSource resolveEntity(String pid, String sid)
				throws SAXException {
			if (sid.equals("http://java.sun.com/dtd/properties.dtd")) {
				InputSource is = new InputSource(
						new StringReader(
								"<?xml version=\"1.0\" encoding=\"UTF-8\"?><!-- DTD for properties --><!ELEMENT properties ( comment?, entry* ) ><!ATTLIST properties version CDATA #FIXED \"1.0\"><!ELEMENT comment (#PCDATA) ><!ELEMENT entry (#PCDATA) ><!ATTLIST entry  key CDATA #REQUIRED>"));
				is.setSystemId("http://java.sun.com/dtd/properties.dtd");
				return is;
			} else {
				throw new SAXException((new StringBuilder()).append(
						"Invalid system identifier: ").append(sid).toString());
			}
		}

		private Resolver() {
		}

	}

	@SuppressWarnings("unchecked")
	public void loadFromXml(InputStream is) throws JDOMException, IOException {

		SAXBuilder builder = new SAXBuilder();
		builder.setEntityResolver(new Resolver());
		Document doc = builder.build(is);
		Element sqls = doc.getRootElement();
		List list = sqls.getChildren("command");
		if (list == null || list.isEmpty())
			return;
		for (int i = 0; i < list.size(); i++) {
			Element element = (Element) list.get(i);
			String key = element.getAttributeValue("id");
			String value = element.getChildText("sql");
			properties.setProperty(key, value);
		}
	}
...........................
}

对于配置文件的读取建议使用 Commons Configuration
4 楼 tivan 2010-07-15  

启动时把XML文件加载到java的Properties 里面。

代码大概如下

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.List;
import java.util.Properties;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class SQLBuildHelp {
...................
	Properties properties = new Properties();

	private static class Resolver implements EntityResolver {

		public InputSource resolveEntity(String pid, String sid)
				throws SAXException {
			if (sid.equals("http://java.sun.com/dtd/properties.dtd")) {
				InputSource is = new InputSource(
						new StringReader(
								"<?xml version=\"1.0\" encoding=\"UTF-8\"?><!-- DTD for properties --><!ELEMENT properties ( comment?, entry* ) ><!ATTLIST properties version CDATA #FIXED \"1.0\"><!ELEMENT comment (#PCDATA) ><!ELEMENT entry (#PCDATA) ><!ATTLIST entry  key CDATA #REQUIRED>"));
				is.setSystemId("http://java.sun.com/dtd/properties.dtd");
				return is;
			} else {
				throw new SAXException((new StringBuilder()).append(
						"Invalid system identifier: ").append(sid).toString());
			}
		}

		private Resolver() {
		}

	}

	@SuppressWarnings("unchecked")
	public void loadFromXml(InputStream is) throws JDOMException, IOException {

		SAXBuilder builder = new SAXBuilder();
		builder.setEntityResolver(new Resolver());
		Document doc = builder.build(is);
		Element sqls = doc.getRootElement();
		List list = sqls.getChildren("command");
		if (list == null || list.isEmpty())
			return;
		for (int i = 0; i < list.size(); i++) {
			Element element = (Element) list.get(i);
			String key = element.getAttributeValue("id");
			String value = element.getChildText("sql");
			properties.setProperty(key, value);
		}
	}
...........................
}
3 楼 JetMah 2010-07-15  
不知楼主Commands类中的GetDbCommand方法是怎么写的?如果是解析xml文件的话是否考虑到线程安全性的问题?
2 楼 mmwy 2010-06-07  
以前有个代替ibatis的开源项目叫o/r broker,它的xml配置文件里面就是用freemarker或者velcity来写脚本的,可惜这个项目在05年以后就没再更新了。
1 楼 badqiu 2010-06-07  
本人曾经也有这个想法,使用Freemarker+ spring jdbc完全替换iBatis,没想到LZ快人一步,呵呵。不错!!!

相关推荐

    SpringBoot+JPA+Freemarker 生成动态SQL

    结合SpringBoot和JPA,我们可以创建一个服务,该服务使用JPA的Repository接口与数据库进行交互,并通过Freemarker生成动态SQL。具体步骤如下: 1. **设置项目**:创建一个SpringBoot项目,添加Spring Data JPA和...

    json、post请求、freemarker模拟生成sql、wsdl2Java生成客户代码

    例如,模拟生成SQL时,我们可以将数据库表结构和字段名等信息作为数据模型,然后在模板中定义SQL语句的结构,通过Freemarker的`process`方法生成动态的SQL脚本。 Wsdl2Java工具是Apache CXF框架的一部分,它用于从...

    hibernate实现动态SQL查询

    本篇文章主要探讨如何利用Hibernate实现动态SQL查询,结合XML配置和FREEMARKER模板引擎来生成执行的SQL语句。 一、Hibernate简介 Hibernate作为一款强大的持久层框架,它简化了Java应用程序与数据库之间的交互。...

    hibernate增删改查和动态sql

    “hibernate增删改查和动态sql”这个标题涵盖了两个主要的Hibernate使用场景。首先,"增删改查"(CRUD操作)是任何数据库操作的基础,包括创建(Create)、读取(Read)、更新(Update)和删除(Delete)。在...

    springmvc+freemarker带sql的登录事例

    在本示例中,我们将探讨如何使用Spring MVC和FreeMarker框架构建一个带有SQL数据库支持的登录系统。Spring MVC是Spring框架的一部分,它提供了一个模型-视图-控制器(MVC)架构,使得开发者可以轻松地处理Web应用的...

    使用freemarker生成controller service impl pojo dao mapper

    使用FreeMarker,我们可以创建一个模板,定义Controller类的基本结构,包括方法签名、注解等。模板变量可以用于动态生成不同的控制器方法,根据业务需求进行扩展。 4. **生成Service和Impl** Service层定义了业务...

    springmvc+mybatis 和一个简单的freemarker代码生成工具

    开发者可以创建FreeMarker模板文件,其中包含变量和控制结构,然后在运行时这些变量会被替换为实际的值。FreeMarker与SpringMVC和MyBatis结合,可以在后台生成动态的视图,比如表单、列表等,使得开发者能快速地构建...

    SpringMVC精品资源--使用SpringMVC+MyBatis+FreeMarker 创建简单的CMS内容发布系统.zip

    - **模板语法**:FreeMarker使用${}表示变量,#{}表示表达式,以及一系列控制结构(如if/else,foreach等)来动态生成内容。 - **在CMS中的应用**:在CMS中,FreeMarker用于渲染后台生成的模型数据,比如文章内容...

    Java利用Freemarker模板自动生成dto、dao、rowmapper、bo、service代码

    本主题涉及的核心技术是使用Freemarker模板引擎来生成DTO(Data Transfer Object)、DAO(Data Access Object)、RowMapper、BO(Business Object)和服务层代码。这些组件在Spring框架中扮演着重要角色。 1. **...

    FreeMarker

    以下是一个简单的 FreeMarker 使用案例,包括搭建 Maven 项目、配置依赖、创建模板文件以及处理变量等内容。 #### 搭建 Maven 项目 创建一个新的 Maven 项目,并添加 FreeMarker 的依赖。`pom.xml` 文件中应该包含...

    利用freemarker根据数据库字段自动生成form表单代码

    根据数据库字段,动态填充SQL语句,如自动创建INSERT语句时,根据字段数量生成相应的占位符(`?`)。 **4. Service层的自动生成** Service层是业务逻辑的核心,通常包含事务管理、业务规则验证等。模板应包含方法...

    Spring boot + Mybatis + Freemarker

    - 模板文件:创建FTL(FreeMarker Template Language)模板文件,其中可以使用FreeMarker语法进行动态内容生成。 - Controller层:在Controller中,通过ModelAndView或Model对象将数据传递给视图,FreeMarker会根据...

    spring mvc 3.0-mybatis-freemarker整合

    6. **创建Freemarker模板**:在项目的视图目录下创建Freemarker模板文件,使用Freemarker语法将数据渲染到页面上。 通过以上步骤,我们便成功地整合了Spring MVC 3.0、MyBatis 3 和 Freemarker 2.3,实现了MVC架构...

    ssm整合外加freemarker

    在SSM项目中,FreeMarker用于视图层,它与Spring MVC协作,根据数据模型动态生成页面。FreeMarker模板语言简单易学,允许开发者专注于页面布局和内容,而不必关心如何把数据注入到页面中。 5. **Maven项目**:Maven...

    基于spring boot 2集成hibernate及freemarker的简单实例

    通过Spring Boot 2、Hibernate和FreeMarker的集成,你可以创建一个轻量级的、面向对象的Web应用,其中数据访问层使用Hibernate简化数据库操作,而视图层利用FreeMarker生成动态HTML。这个简单的实例为初学者提供了一...

    SSH框架和FreeMarker动态网页生成静态技术

    接下来,创建FreeMarker模板文件,定义页面布局和动态内容。在Struts2的动作类中,准备数据模型并传递给FreeMarker。最后,通过FreeMarker的`Template`类加载模板并渲染,生成静态HTML文件,这些文件可以直接被Web...

    SSH项目 有Freemarker模版

    **Hibernate** 是一个流行的ORM框架,它允许开发者使用Java对象来操作数据库,而无需编写SQL。在SSH项目中,Hibernate通过配置文件定义实体类与数据库表的映射,提供了一种简单的方式来执行CRUD(创建、读取、更新、...

    freemarker 中午手册

    - **抽象接口**:通过提供统一的接口来表示不同类型的对象(如 JavaBean、XML 文档、SQL 查询结果等),从而简化了模板开发者的使用过程。 #### 五、为 Web 准备 - **内置 Web 相关功能**:Freemarker 在模板语言...

    ssm整合freemarker---Demo

    接着,创建FreeMarker视图解析器bean;最后,在Controller中使用ModelAndView返回视图名,由FreeMarker渲染生成页面。 PageHelper分页插件的使用也是这个Demo的重要部分: 6. **PageHelper**:这是一款MyBatis的...

Global site tag (gtag.js) - Google Analytics