让你从繁琐的sql语句中脱身(mybatis框架的进一步封装 )
2016-07-25 15:55
351 查看
让你从繁琐的sql语句中脱身(mybatis框架的进一步封装 )
小编刚入职就接到项目组长的要求–写一个基于mybatis的对象关系映射框架,让他从sql语句中脱身。起初感觉像这种问题应该交给hibernate这种成熟的框架解决,对于我这种刚入职的新码农来说写这种框架是一种什么样的体验连自己都不清楚。由于刚入职,心情总是诚惶诚恐,索性还是硬着头皮写了一个极其简陋的小框架出来(可以实现普通的增删查改 后期有时间加入一些拼表,排序,等复杂查询) 下面干货立马端上来:
思路: 由于mysql可以实现纯手工的sql语句书写,并且可以通过sqlSessionTemplate类来实现将sql语句进行注入,查询的结果可以封装成Map集合进行接收,那么所有的问题就在sql串的拼接了。由于数据库的表结构和实体机构相同,所以我们完全可以通过实体得到实体的属性名和属性值来进行sql串的拼接。
BaseMapper.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.huishenghuo.dao.BaseDao"> <!-- 根据条件查询查询 --> <select id="findentitylist" resultType="hashmap"> ${value} </select> <!-- 添加 --> <insert id="insertentity"> ${value} </insert> <!-- 根据条件修改 --> <update id="updateentity"> ${value} </update> </mapper>
BaseDao.java文件
public interface BaseDao { /** 查询列表 */ public <T> List<T> findEntityList(Class<T> obj, Map<String, Object> param); /** 添加操作 */ public boolean insertEntity(Object obj); /** 修改操作 */ public boolean updateEntity(Object obj, Map<String, Object> param); }
BaseDaoImpl.java文件(重点就在这里)
@Component public class BaseDaoImpl implements BaseDao { @Resource(name = "sqlSessionTemplate") private SqlSessionTemplate sqlSessionTemplate; /** * @author: chen1chen2 * 根据传入值进行查询sql串的拼接 */ public <T> List<T> findEntityList(Class<T> obj, Map<String, Object> param) { // 将实体字段名变为与数据库相同字段(小写转为大写) List 4000 <String> paramNameUpperList = DataUtil.paramLowToUpper(obj); // 将查询条件的属性名小写转为大写 param = DataUtil.conditionLowToUpper(param); // 得到类文件数组 Field[] paramNameLowerArray = obj.getDeclaredFields(); // 通过class文件得到表的名字 String tableName = DataUtil.classNameLowToUpper(obj); // select后面的拼接串 String tabField = ""; // where后面的拼接串 String whereField = " WHERE 0=0"; // 得到select后面的拼接串 for (int i = 1; i < paramNameUpperList.size(); i++) { // 得到属性大写名 String UpperParam = paramNameUpperList.get(i); // 得到属性小写名 String LowerParam = paramNameLowerArray[i].getName(); // 判断是否为第一次拼串 if (i == 1) { tabField += "CAST(IFNULL(" + tableName + "." + UpperParam + ", '') AS CHAR) " + LowerParam; } else { tabField += ",CAST(IFNULL(" + tableName + "." + UpperParam + ", '') AS CHAR) " + LowerParam; } } // where后面的拼接串 for (Map.Entry<String, Object> entry : param.entrySet()) { // 得到条件名 String key = entry.getKey().toString(); // 得到条件值 Object value = entry.getValue(); // 判断条件是否为字符串 if (value instanceof String) {// 是 whereField = whereField + " AND " + key + "= '" + value + "'"; } else {// 否 whereField = whereField + " AND " + key + "=" + value; } } // 得到sql串 String sql = "SELECT " + tabField + " FROM " + tableName + whereField; /* System.out.println("拼接的selectbyparam的sql为:"+sql); */ List<Map<String, String>> modelList = sqlSessionTemplate.selectList( "findentitylist", sql); List<T> beanList = new ArrayList<T>(); // 通过beanutils将list<map>封装成实体集合 for (Map map : modelList) { T bean = null; try { bean = obj.newInstance(); BeanUtils.populate(bean, map); } catch (Exception e) { throw new RuntimeException(e); } beanList.add(bean); } return beanList; } /** * @author: chen1chen2 * 拼接插入sql串 */ public boolean insertEntity(Object obj) { //将属性名小写转化为与数据库字段相同的大写 List<String> paramNameUpperList = DataUtil.paramLowToUpper(obj.getClass()); //得到表名 String tableName = DataUtil.classNameLowToUpper(obj.getClass()); //into 后面的sql串 String paramField = "("; //value后面的sql串 String valueField = " values ("; //得到into后面的sql串 for(int i = 1; i < paramNameUpperList.size(); i ++) { if(i == 1) {//为第一次 paramField = paramField + paramNameUpperList.get(i); } else { paramField = paramField + "," + paramNameUpperList.get(i); } } paramField = paramField + ")"; //得到类文件数组 Field[] fields = obj.getClass().getDeclaredFields(); //拼接values后面sql串 for(int i = 1; i < fields.length; i ++) { Object value;//属性值 //得到属性名 String paramName = fields[i].getName(); //通过属性名得到getXxx方法名 String paramNameGet = "get"+paramName.substring(0, 1).toUpperCase() + paramName.substring(1); //根据java中的反射得到属性值 try { Method m = obj.getClass().getMethod(paramNameGet); value = m.invoke(obj); } catch (Exception e) { throw new RuntimeException(e); } //得到的值是否为空 if(value != null) { if(value instanceof String) {//为String类型 if(i == 1) {//第一次 valueField = valueField + "'" + value + "'"; } else { valueField = valueField + "," + "'" + value + "'"; } } else {//不是String类型 if(i == 1) { valueField = valueField + "'" +value + "'"; } else { valueField = valueField + "," + value; } } } else {//属性值为空 if(i == 1) {//第一次 valueField = valueField + null; } else { valueField = valueField + "," + null; } } } valueField = valueField + ")"; //拼接sql串 String sql = "INSERT INTO " + tableName + paramField + valueField; /*System.out.println("插入model的sql语句为:"+ sql);*/ int count = sqlSessionTemplate.insert("insertentity", sql); return count == 1 ? true : false; } /** * @author: chen1chen2 * 拼接更新sql串 */ public boolean updateEntity(Object obj, Map<String, Object> param) { //将属性名转化为大写 List<String> paramNameUpperList = DataUtil.paramLowToUpper(obj.getClass()); //得到表名 String tableName = DataUtil.classNameLowToUpper(obj.getClass()); //将条件名转换为大写 param = DataUtil.conditionLowToUpper(param); //set后面sql串 String setField = " SET "; //where后面sql串 String whereField = " WHERE 0=0 "; //得到类文件数组 Field[] fields = obj.getClass().getDeclaredFields(); //拼接set后面sql串 for(int i = 1; i < fields.length; i ++) { Object value; String paramName = fields[i].getName(); String paramNameGet = "get"+paramName.substring(0, 1).toUpperCase() + paramName.substring(1); //java反射得到属性值 try { Method m = obj.getClass().getMethod(paramNameGet); value = m.invoke(obj); } catch (Exception e) { throw new RuntimeException(e); } if(i == 1) {//第一次 if(value instanceof String) {//值为String类型 setField = setField + tableName + "." + paramNameUpperList.get(i) + " = " + "'" + value + "'"; } else { setField = setField + tableName + "." + paramNameUpperList.get(i) + " = " + value; } } else { if(value instanceof String) {//值为String类型 setField =setField + ", " + tableName + "." + paramNameUpperList.get(i) + " = " + "'" + value + "'"; } else { setField = setField + ", " + tableName + "." + paramNameUpperList.get(i) + " = " + value; } } } //拼接where后面子串 for (Map.Entry<String, Object> entry : param.entrySet()) { String key = entry.getKey().toString(); Object value = entry.getValue(); if(value instanceof String) { whereField = whereField + " AND " + key + "= '" + value + "'"; } else { whereField = whereField + " AND " + key + "=" + value; } } String sql = "UPDATE " + tableName + setField + whereField; /*System.out.println("跟新的sql串为:"+sql);*/ int count = sqlSessionTemplate.update("updateentity", sql); return count == 1 ? true : false; } }
其中用到的字符串小写转大写工具包为:
public static List<String> paramLowToUpper(Class obj) { Field[] fields=obj.getDeclaredFields(); List<String> fieldNames = new ArrayList<String>(); for(int i=0; i<fields.length; i++){ String param = ""; String paramName = fields[i].getName(); String[] splitParamName = paramName.split("(?=[A-Z])"); for(int j = 0; j < splitParamName.length; j ++) { if(j == 0) { param = param + splitParamName[j].toUpperCase(); } else { param = param + "_" + splitParamName[j].toUpperCase(); } } fieldNames.add(param); } return fieldNames; } public static String classNameLowToUpper(Class obj) { String classFullNameLower = obj.getName(); String classNameLower = classFullNameLower.substring(classFullNameLower.lastIndexOf(".") + 1); String[] splitClassNameLower = classNameLower.split("(?=[A-Z])"); String tableName = ""; for(int j = 1; j < splitClassNameLower.length; j ++) { if(j == 1) { tableName = tableName + splitClassNameLower[j].toUpperCase(); } else { tableName = tableName + "_" + splitClassNameLower[j].toUpperCase(); } } return tableName; } public static Map<String, Object> conditionLowToUpper(Map<String, Object> param) { Map<String, Object> map = new HashMap<String, Object>(); for (Map.Entry<String, Object> entry : param.entrySet()) { String lowKey = entry.getKey(); String upperKey = ""; String[] splitParamName = lowKey.split("(?=[A-Z])"); for(int j = 0; j < splitParamName.length; j ++) { if(j == 0) { upperKey = upperKey + splitParamName[j].toUpperCase(); } else { upperKey = upperKey + "_" + splitParamName[j].toUpperCase(); } } map.put(upperKey, entry.getValue()); } return map; } public static void main(String[] args) { List<String> fieldNames = new ArrayList<String>(); String[] fields = {"integer","inteGood","inteGoodKeed"}; for(int i=0; i<fields.length; i++){ String param = ""; String paramName = fields[i]; String[] splitParamName = paramName.split("(?=[A-Z])"); for(int j = 0; j < splitParamName.length; j ++) { if(j == 0) { param = param + splitParamName[j].toUpperCase(); } else { param = param + "_" + splitParamName[j].toUpperCase(); } } fieldNames.add(param); } for(String s : fieldNames) { System.out.println("+++++++++"+s); } }
service层中的调用
public <T> List<T> getModelList(Class<T> obj, Map<String, Object> param) { return baseDao.selectByParam(obj, param); } public boolean insertModel(Object obj) { return baseDao.insertModel(obj); } @Override public boolean updateModel(Object obj, Map<String, Object> param) { boolean b = baseDao.updateByParam(obj, param); return b; }
controller层中的调用
/** * *@description:测试通过条件查询是否可用 *@author: chen1chen2 *@date: 日期:2016年7月22日 时间:下午1:29:04 */ @RequestMapping("getModelList") public ModelAndView getModelList() { //模拟前台传过来的参数 Map map = new HashMap<String, String>(); map.put("goodsTypeId", 1); map.put("typeName", "蔬菜"); /**通过条件查询商品种类*/ List<GoodsTypeInfo> list = goodTypeInfoServiceImpl.getModelList(GoodsTypeInfo.class, map); //输出查询结果用于测试 System.out.println("查询出来的值为:"+list.get(0).toString()); return null; } /** * *@description:测试插入是否可用 *@author: chen1chen2 *@date: 日期:2016年7月22日 时间:下午1:29:36 */ @RequestMapping("addModel") public ModelAndView addModel() { //模拟前台传入的数据 GoodsTypeInfo goodsTypeInfo = new GoodsTypeInfo(); goodsTypeInfo.setCreateTime("1998-12-30"); goodsTypeInfo.setShowSort(2); Map map = new HashMap<String, String>(); /**插入方法*/ boolean b = goodTypeInfoServiceImpl.insertModel(goodsTypeInfo); //测试插入是否成功! System.out.println("+++++++++++++" + b); return null; } /** * *@description:测试修改是否成功(业务逻辑没有实际删除,只有逻辑删除) *@author: chen1chen2 *@date: 日期:2016年7月22日 时间:下午1:31:05 */ @RequestMapping(method = RequestMethod.GET, value = "/updateModel", headers = "Accept=application/json,application/xml") @ResponseBody public ModelAndView updateModel(String goods_type_id) { //模拟测试数据 Map map = new HashMap<String, String>(); map.put("goodsTypeId", Integer.parseInt(goods_type_id)); /**得到给定条件数据*/ List<GoodsTypeInfo> goodsTypeInfo = goodTypeInfoServiceImpl.getModelList(GoodsTypeInfo.class, map); goodsTypeInfo.get(0).setTypeName("我喜欢的水果的水果"); /**修改方法*/ boolean b = goodTypeInfoServiceImpl.updateModel(goodsTypeInfo.get(0), map); //测试结果 System.out.println("测试结果:" + b); return null; }
总结:小白刚入职,这种直白粗糙的代码拿出来就是为了激励自己,希望代码中有什么其他的好的想法可以分享出来供大家讨论,自己实现的代码毕竟bug多多后期会不断完善并且添加功能,整个代码的核心就在sql语句的拼接方面,由于用到了java的反射机制,所以能够得到实体中的属性名与属性值,拼接sql串后使用sqlsessionTemplate来进行数据库的访问。
注:使用中需要遵守的规范:
1.实体属性命名时必须服从驼峰式的规范 如:id userId isForbiddenModel 等
2.表的名字和表中的字段字母必须全大写,词之间用下划线如:ID USER_ID IS_FORBIDDEN_MODEL 等
3.实体中的属性一定要一一对应,不能出现多一个或者少一个的字段
相关文章推荐
- Python动态类型的学习---引用的理解
- 土人系列AS入门教程 -- 对象篇
- C#托管堆对象实例包含内容分析
- 插件管理框架 for Delphi(一)
- C#实现获取不同对象中名称相同属性的方法
- javascript asp教程第十一课--Application 对象
- PowerShell中使用Out-String命令把对象转换成字符串输出的例子
- VBS教程:对象-正则表达式(RegExp)对象
- 使用CSS框架布局的缺点和优点小结
- C#检查指定对象是否存在于ArrayList集合中的方法
- sql2008启动代理未将对象应用到实例解决方案
- 一起动手编写Android图片加载框架
- 基于.NET平台常用的框架和开源程序整理
- C#编程自学之类和对象
- C++中对象的常引用、动态建立和释放相关知识讲解
- C++之类和对象课后习题简单实例
- 深入理解PHP JSON数组与对象
- php中将一个对象保存到Session中的方法
- php对象和数组相互转换的方法
- PHP中把对象转换为关联数组代码分享