同步操作将从 selfly/dexcoder-assistant 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
#Dexcoder快速开发辅助工具包
最近更新:
update更新支持选择是否更新值为null的属性
增加表别名支持
具体请看:增加表别名支持
本版本进行了彻底的重构,并且api做了一些细微的改变,具体可以看使用说明对比和原来的区别。
需要旧版请看这里:通用dao v1.2.4
##核心组件dexcoder-dal使用说明
如果你不喜欢用Hibernate
、Mybaits
这类ORM框架,喜欢JdbcTemplate
或DbUtils
,那么可以试试这个封装的通用dal,这可能是目前封装的最方便易用的通用dal层了。
dexcoder-dal的一些特性:
Entity
外,支持更强大的Criteria
方式。=
、!=
、or
、in
、not in
甚至是执行函数。count()
、max()
、to_char()
、甚至是distinct
,理论上都可以支持。{}
和[]
完成一些特殊的操作,{}
中的代码将原生执行,[]
中的代码会进行命名转换,一般fieldName转columnName。该通用dao是在使用过程中,针对常规的泛型dao经常遇到的一些不便问题进行了改进。命名上遵循了约定优于配置的原则,典型约定如下:
USER_INFO
表实体类名为UserInfo
。USER_NAME
实体类中属性名为userName
。USER_INFO
表主键名为USER_INFO_ID
,同理实体类中属性名为userInfoId
。Oracle
序列名约定 USER_INFO
表对应的主键序列名为SEQ_USER_INFO
当然,这些你可以在扩展中改变它,但不建议这么做,这本身就是一个良好的规范。
要在项目中使用通用dao十分简单,目前已上maven中央库,直接在pom.xml中添加依赖:
<dependency>
<groupId>com.dexcoder</groupId>
<artifactId>dexcoder-dal-spring</artifactId>
<version>2.2.0-beta1</version>
</dependency>
然后在spring的配置文件中声明如下bean:
<bean id="jdbcDao" class="com.dexcoder.dal.spring.JdbcDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<!--需要分页时声明-->
<bean id="pageControl" class="com.dexcoder.dal.spring.page.PageControl"></bean>
接下来就可以注入到您的Service
或者其它类中使用了。
##下面是一些常用的方法示例,这里的Entity
对象为User
,对于任何的Entity
都是一样的.
先来看一下User
对象及它继承的Pageable
public class User extends Pageable {
private Long userId;
private String loginName;
private String password;
private Integer userAge;
private String userType;
private String email;
private Date gmtCreate;
//......
}
Pageable对象,用来保存页码、每页条数信息以支持分页
public class Pageable implements Serializable {
/** 每页显示条数 */
protected int itemsPerPage = 20;
/** 当前页码 */
protected int curPage = 1;
//......
}
都是普通的JavaBean对象,下面来看看如何进行具体的增删改查,每种操作都演示了Entity
和Criteria
两种方式。
public void insert() {
User user = new User();
user.setLoginName("selfly_a");
user.setPassword("123456");
user.setEmail("javaer@live.com");
user.setUserAge(18);
user.setUserType("1");
user.setGmtCreate(new Date());
Long id = jdbcDao.insert(user);
System.out.println("insert:" + id);
}
public void insert2() {
Criteria criteria = Criteria.insert(User.class).into("loginName", "selfly_b").into("password", "12345678")
.into("email", "selflly@foxmail.com").into("userAge", 22).into("userType", "2").into("gmtCreate", new Date());
Long id = jdbcDao.insert(criteria);
System.out.println("insert:" + id);
}
###save操作,和insert的区别在于不处理主键,由调用者指定
public void save() {
User user = new User();
user.setUserId(-1L);
user.setLoginName("selfly-1");
user.setPassword("123456");
user.setEmail("javaer@live.com");
user.setUserAge(18);
user.setUserType("1");
user.setGmtCreate(new Date());
jdbcDao.save(user);
}
public void save2() {
Criteria criteria = Criteria.insert(User.class).into("userId", -2L).into("loginName", "selfly-2")
.into("password", "12345678").into("email", "selflly@foxmail.com").into("userAge", 22).into("userType", "2")
.into("gmtCreate", new Date());
jdbcDao.save(criteria);
}
###update操作
public void update() {
User user = new User();
user.setUserId(57L);
user.setPassword("abcdef");
user.setGmtModify(new Date());
jdbcDao.update(user);
}
public void update2() {
Criteria criteria = Criteria.update(User.class).set("password", "update222")
.where("userId", new Object[] { 56L, -1L, -2L });
jdbcDao.update(criteria);
}
###get操作
public void get1() {
User u = jdbcDao.get(User.class, 63L);
Assert.assertNotNull(u);
System.out.println(u.getUserId() + " " + u.getLoginName() + " " + u.getUserType());
}
public void get2() {
//criteria,主要用来指定字段白名单、黑名单等
Criteria criteria = Criteria.select(User.class).include("loginName");
User u = jdbcDao.get(criteria, 73L);
Assert.assertNotNull(u);
System.out.println(u.getUserId() + " " + u.getLoginName() + " " + u.getUserType());
}
###delete操作
public void delete() {
//会把不为空的属性做为where条件
User u = new User();
u.setLoginName("selfly-1");
u.setUserType("1");
jdbcDao.delete(u);
}
public void delete2() {
//where条件使用了or
Criteria criteria = Criteria.delete(User.class).where("loginName", new Object[] { "liyd2" })
.or("userAge", new Object[]{64});
jdbcDao.delete(criteria);
}
public void delete3() {
//根据主键
jdbcDao.delete(User.class, 57L);
}
###列表查询操作
public void queryList() {
//所有结果
List<User> users = jdbcDao.queryList(User.class);
}
public void queryList1() {
//以不为空的属性作为查询条件
User u = new User();
u.setUserType("1");
List<User> users = jdbcDao.queryList(u);
}
public void queryList2() {
//Criteria方式
Criteria criteria = Criteria.select(User.class).exclude("userId")
.where("loginName", new Object[]{"liyd"});
List<User> users = jdbcDao.queryList(criteria);
}
public void queryList3() {
//使用了like,可以换成!=、in、not in等
Criteria criteria = Criteria.select(User.class).where("loginName", "like",
new Object[] { "%liyd%" });
user.setUserAge(16);
//这里entity跟criteria方式混合使用了,建议少用
List<User> users = jdbcDao.queryList(user, criteria.include("userId"));
}
###count记录数查询,除了返回值不一样外,其它和列表查询一致
public void queryCount() {
user.setUserName("liyd");
int count = jdbcDao.queryCount(user);
}
public void queryCount2() {
Criteria criteria = Criteria.select(User.class).where("loginName", new Object[] { "liyd" })
.or("userAge", new Object[]{27});
int count = jdbcDao.queryCount(criteria);
}
###查询单个结果
public void querySingleResult() {
user = jdbcDao.querySingleResult(user);
}
public void querySingleResult2() {
Criteria criteria = Criteria.select(User.class).where("loginName", new Object[] { "liyd" })
.and("userId", new Object[]{23L});
User u = jdbcDao.querySingleResult(criteria);
}
###指定字段白名单,在任何查询方法中都可以使用
public void get(){
//将只返回loginName
Criteria criteria = Criteria.select(User.class).include("loginName");
User u = jdbcDao.get(criteria, 23L);
}
###指定字段黑名单,在任何查询方法中都可以使用
public void get4(){
//将不返回loginName
Criteria criteria = Criteria.select(User.class).exclude("loginName");
User u = jdbcDao.get(criteria, 23L);
}
###指定排序
public void queryList() {
//指定多个排序字段,asc、desc
Criteria criteria = Criteria.select(User.class).exclude("userId")
.where("loginName", new Object[]{"liyd"}).asc("userId").desc("userAge");
List<User> users = jdbcDao.queryList(criteria);
}
###分页
public void queryList1() {
//进行分页
PageControl.performPage(user);
//分页后该方法即返回null,由PageControl中获取
jdbcDao.queryList(user);
Pager pager = PageControl.getPager();
//列表
List<User> users = pager.getList(User.class);
//总记录数
int itemsTotal = pager.getItemsTotal();
}
public void queryList2() {
//直接传入页码和每页条数
PageControl.performPage(1, 10);
//使用Criteria方式,并指定排序字段方式为asc
Criteria criteria = Criteria.select(User.class).include("loginName", "userId")
.where("loginName", new Object[]{"liyd"}).asc("userId");
jdbcDao.queryList(criteria);
Pager pager = PageControl.getPager();
}
Criteria criteria = Criteria.select(User.class)
.where("userType", new Object[] { "1" }).begin()
.and("loginName", new Object[] { "selfly" })
.or("email", new Object[] { "javaer@live.com" }).end()
.and("password", new Object[] { "123456" });
User user = jdbcDao.querySingleResult(criteria);
//max()
Criteria criteria = Criteria.select(User.class).addSelectFunc("max([userId])");
Long userId = jdbcDao.queryForObject(criteria);
//count()
Criteria criteria = Criteria.select(User.class).addSelectFunc("count(*)");
Long count = jdbcDao.queryForObject(criteria);
//distinct
Criteria criteria = Criteria.select(User.class).addSelectFunc("distinct [loginName]");
List<Map<String, Object>> mapList = jdbcDao.queryForList(criteria);
默认情况下,addSelectFunc
方法返回结果和表字段互斥,并且没有排序,如果需要和表其它字段一起返回并使用排序,可以使用如下代码:
Criteria criteria = Criteria.select(User.class).addSelectFunc("DATE_FORMAT(gmt_create,'%Y-%m-%d %h:%i:%s') date",false,true);
List<Map<String, Object>> mapList = jdbcDao.queryForList(criteria);
这是在select中执行函数,那怎么在update和where条件中执行函数呢?前面提到的{}
和[]
就可以起到作用了。
看下面代码:
Criteria criteria = Criteria.update(User.class).set("[userAge]", "[userAge]+1")
.where("userId", new Object[] { 56L });
jdbcDao.update(criteria);
以上代码将执行sql:UPDATE USER SET USER_AGE = USER_AGE+1 WHERE USER_ID = ?
,[]
中的fieldName被转换成了columnName,
也可以使用{}
直接写columnName,因为在{}
中的内容都是不做任何操作原生执行的,下面代码效果是一样的:
Criteria criteria = Criteria.update(User.class).set("{USER_AGE}", "{USER_AGE + 1}")
.where("userId", new Object[] { 56L });
jdbcDao.update(criteria);
同理,在where中也可以使用该方式来执行函数:
Criteria criteria = Criteria.select(User.class).where("[gmtCreate]", ">",
new Object[] { "str_to_date('2015-10-1','%Y-%m-%d')" });
List<User> userList = jdbcDao.queryList(criteria);
有些时候,就算单表操作也必须用到表别名,例如oracle中的xmltype类型。可以在Criteria中设置表别名:
Criteria criteria = Criteria.select(Table.class).tableAlias("t").addSelectFunc("[xmlFile].getclobval() xmlFile")
.where("tableId", new Object[]{10000002L});
Object obj = jdbcDao.queryForObject(criteria);
//对应的sql
select t.XML_FILE.getclobval() xmlFile from TABLE t where t.TABLE_ID = ?
在实际的应用中,一些复杂的查询如联表查询、子查询等是省不了的。鉴于这类sql的复杂性和所需要的各类优化,通用dao并没有直接封装而是提供了执行自定义sql的接口。
执行自定义sql支持两种方式:直接传sql执行和mybatis方式执行。
该方式可能会让除了dao层之外的业务层出现sql代码,因此是不推荐的,它适合一些不在项目中的情况。
何为不在项目中的情况?例如做一个开发自用的小工具,临时处理一批业务数据等这类后期不需要维护的代码。
要执行自定义sql首先需要在jdbcDao
中注入sqlFactory
,这里使用SimpleSqlFactory
:
<bean id="jdbcDao" class="com.dexcoder.dal.spring.JdbcDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
<property name="sqlFactory" ref="sqlFactory"/>
</bean>
<bean id="sqlFactory" class="com.dexcoder.dal.SimpleSqlFactory">
</bean>
然后就可以直接传入sql执行了:
List<Map<String, Object>> list = jdbcDao.queryForSql("select * from USER where login_name = ?",
new Object[] { "selfly_a99" });
这个实现比较简单,参数Object数组中不支持复杂的自定义对象。
采用了插件式实现,使用该方式首先添加依赖:
<dependency>
<groupId>com.dexcoder</groupId>
<artifactId>dexcoder-dal-batis</artifactId>
<version>2.2.0-beta1</version>
</dependency>
之后同样注入sqlFactory
,把上面的SimpleSqlFactory
替换成BatisSqlFactoryBean
:
<bean id="jdbcDao" class="com.dexcoder.dal.spring.JdbcDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
<property name="sqlFactory" ref="sqlFactory"/>
</bean>
<bean id="sqlFactory" class="com.dexcoder.dal.batis.BatisSqlFactoryBean">
<property name="sqlLocation" value="user-sql.xml"/>
</bean>
BatisSqlFactoryBean
有一个sqlLocation
属性,指定自定义的sql文件,因为使用了spring的解析方式,所以可以和指定spring配置文件时一样使用各类通配符。
user-sql.xml
是一个和mybatis的mapper类似的xml文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//dexcoder.com//DTD Mapper 2.0//EN"
"http://www.dexcoder.com/dtd/batis-mapper.dtd">
<mapper namespace="User">
<sql id="columns">
user_id,login_name,password,user_age,user_type
</sql>
<select id="getUser">
select
<include refid="columns"/>
from user
<where>
<if test="params[0] != null">
user_type = #{params[0].userType}
</if>
<if test="params[1] != null">
and login_name in
<foreach collection="params[1]" index="index" item="item" separator="," open="(" close=")">
#{item}
</foreach>
</if>
</where>
</select>
</mapper>
然后使用代码调用:
User user = new User();
user.setUserType("1");
Object[] names = new Object[] { "selfly_a93", "selfly_a94", "selfly_a95" };
List<Map<String, Object>> mapList = jdbcDao.queryForSql("User.getUser", "params", new Object[] { user, names });
for (Map<String, Object> map : mapList) {
System.out.println(map.get("userId"));
System.out.println(map.get("loginName"));
}
我们调用queryForSql
方法时传入了三个参数:
item
。可以看到这里支持复杂参数,第一个是User
bean对象,第二个是Object数组,至于获取方式可以看上面的xml代码。
除了传入的参数为Object数组并使用item[0]
这种方式访问相应的元素外,其它的和mybatis可以说是一样的,mybatis支持的动态sql方式这里也可以支持,因为他本身就是来源于mybatis。
另外返回结果中map的key做了LOGIN_NAME
到骆驼命名法loginName
的转换。
###项目结构说明
dexcoder-commons 一些通用的工具类,里面的maven依赖可以按需添加。
dexcoder-dal 通用dal的接口,这里对于数据库访问没有具体的实现。具体的数据库操作取决于选择的实现方式(目前只有Spring JdbcTemplate)。
dexcoder-dal-spring Spring JdbcTemplate的dal实现。
dexcoder-dal-batis mybatis方式执行sql实现。
dexcoder-test 测试工程
###一些说明
BatisSqlFactory
方式由分析了mybatis源码后,提取使用了大量mybatis的代码。
JdbcDao在声明时可以根据需要注入其它几个参数:
<bean id="jdbcDao" class="com.dexcoder.dal.spring.JdbcDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
<property name="sqlFactory" ref="..."/>
<property name="nameHandler" ref="..."/>
<property name="rowMapperClass" value="..."/>
<property name="dialect" value="..."/>
</bean>
BeanPropertyRowMapper.newInstance(clazz)
,需要自定义可以自行实现,标准spring的RowMapper实现即可。很多人问如果我要实现一个自己的dao是不是要继承这个dao然后实现自己的方法?其实不用,自己实现的dao按spring标准的JdbcTemplate路子走就可以,完全无耦合。 另外自己实现的dao这个通用的分页组件仍然可以一样使用。
##其它主要包含的组件:
比Apache BeanUtils更强大高效的Bean转换工具类BeanConverter
。支持属性的过滤及实现自定义的类型转换器。
office操作封装工具类ExcelReadTools
和ExcelWriteTools
。对程序员来说office操作最多的莫过于excel了,提供了对excel的读写实现。支持扩展实现自宝义的表格样式。
运行时的异常结果拦截器。RunBinderInterceptor
可以和RunBinderMvcInterceptor
配对使用(web项目),RunBinder
用以获取异常结果信息。
其它:
自行实现的轻量简易缓存。包括LRUCache
,LFUCache
,FIFOCache
,目前只用到了LRUCache,可以使用已有的缓存工具类CacheUtils
直接进行操作。
枚举操作工具类EnumUtils
。结合当中定义的枚举接口IEnum
进行操作,可以方便清晰的使用枚举处理及显示一些信息。
加密工具类EncryptUtils
。目前只有MD5实现。
Class工具类ClassUtils
。获取BeanInfo,自身+指定父类BeanInfo,加载class,反射实例化对象等。
图片工具类ImageUtils
。支持图片缩放,裁剪,加水印等。
名称及命名转换工具类NameUtils
。提供下划线命名到骆驼命名的相互转换,及首字母大写、首字母小写、保留后缀生成唯一文件名等操作。
配置文件属性获取工具类PropertyUtils
。默认优先从tomcat的conf目录获取,如果conf目录下没有则从classpath获取,方便部署时不用修改properties配置文件。
序列化工具类SerializeUtils
。序列化和反序列化,jdk原生实现。
代码格式化工具类SourceCodeFormatter
。使用了eclipse的组件,目前只能完美格式化Java代码,另外使用dom4j增加了xml的格式化。ps:本来打算站点用的后来感觉比较鸡肋了。
字符文本内容工具类TextUtils
。一些StringUtils中没有的字符串操作,奈何StringUtils这类太多了,只能命名TextUtils了。
时间工具类TimeUtils
。提供返回跟当前时间几分钟前
,几小时前
这种xxxx前的时间格式。
UUID工具类UUIDUtils
。提供返回8位、16位、32位的UUID。
线程执行工具类ThreadExecutionUtils
。方便执行多线程任务。
Sitemap工具类SiteMapUtils
。做网站的可能会用到,生成sitemap用。
Spring mvc中针对上面定义的IEnum从页面字符值到枚举的转换类IEnumConverterFactory
。
#相关链接
博客:http://www.dexcoder.com/selfly
作者邮箱: javaer@live.com
交流QQ群: 32261424
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。