利用反射搭建项目的dao层,从此可以告别被人的dao层框架了(spring+反射)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用反射搭建项目的dao层,从此可以告别被人的dao层框架了(spring+反射)相关的知识,希望对你有一定的参考价值。
作为一名刚入手的小白程序猿,不但"TA"不懂我们,就连自己都不懂自己,苦逼的程序猿,只能每天都是在给自己充电了。让"TA"和自己更了解。今天笔者又来吹吹水了,各位客官请买好零食咯,好了废话不多说了。
在以前做项目的时候,一般想到搭项目都是用别人的框架来做,但是别人的框架都是别人封装好的很多东西,对不太熟源码的码农来说就是苦逼呀,所以像笔者这种小白又不甘心,所以笔者就用反射来自己封装一个操作dao层的框架(不算一个框架,就是这么称呼吧),说起反射可能是很多像笔者这样的小白都不了解吧(不过好在笔者有点小聪明,自己学习一下)。其实大家在做项目时用的框架都是用反射来搭起来的,所以反射我们并不陌生,先不说太多了,怎么搭建自己dao层,笔者今天的实例子是用(spring+反射)搭建的Webapp,怎么入手呢 ,如下:
①:首先我们搭建springmvc的配置吧(笔者喜欢这样的方式呢),先创建一个springmvc.xml的文件吧:配置文件如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd 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-4.1.xsd"> <!--自动注解,扫描如下包 --> <mvc:annotation-driven/> <context:component-scan base-package="com.yw.Contrlloer"/> <bean class="org.springframework.web.servlet.mvc.support.ControllerBeanNameHandlerMapping"></bean> </beans>
没错springmvc的配置文件就是这样简单就行了。
② 配好springmvc 接下来就是配置spring了 ,配spring的配置之前我们创建数据库的配置文件先 jdbc.properties。jdbc.properties的配置如下:
validationQuery=SELECT 1 jdbc_URL=jdbc:mysql://127.0.0.1:3306/testredis?useUnicode=true&characterEncoding=UTF-8 jdbc_username=root jdbc_password=123456 initialSize=0 maxActive=20 maxIdle=20 minIdle=0 maxWait=6000 timeBetweenEvictionRunsMillis=60000 minEvictableIdleTimeMillis=25200000 removeAbandonedTimeout=1800
然后就是spring的配置的文件了,对了笔者这里用的是阿里的连接池哦,为什么用阿里的,因为是阿里的(哈哈,是因为它强大呢) 配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" 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-4.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <context:annotation-config/> <context:component-scan base-package="com.yw.dao"/> <context:component-scan base-package="com.yw.service"/> <!-- 引入属性文件 --> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations" value="classpath:com/yw/conf/config.properties"></property> </bean> <!-- 配置数据源 --> <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc_URL}" /> <property name="username" value="${jdbc_username}" /> <property name="password" value="${jdbc_password}" /> <!-- 初始化连接大小 --> <property name="initialSize" value="${initialSize}" /> <!-- 连接池最大使用连接数量 --> <property name="maxActive" value="${maxActive}" /> <!-- 连接池最大空闲 --> <property name="maxIdle" value="${maxIdle}" /> <!-- 连接池最小空闲 --> <property name="minIdle" value="${minIdle}" /> <!-- 获取连接最大等待时间 --> <property name="maxWait" value="${maxWait}" /> <!-- <property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="33" /> --> <property name="validationQuery" value="${validationQuery}" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <property name="testWhileIdle" value="true" /> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" /> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" /> <!-- 打开removeAbandoned功能 --> <property name="removeAbandoned" value="true" /> <!-- 1800秒,也就是30分钟 --> <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}" /> <!-- 关闭abanded连接时输出错误日志 --> <property name="logAbandoned" value="true" /> <!-- 监控数据库 --> <!-- <property name="filters" value="stat" /> --> <property name="filters" value="mergeStat" /> </bean> <!-- 配置Jdbc模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" > <constructor-arg ref="dataSource"></constructor-arg> </bean> <bean id="baseDao" class="com.yw.dao.BaseDao" abstract="true"> <property name="jdbcTemplate" ref="jdbcTemplate"/> </bean> <bean id="userDAo" class="com.yw.dao.UserDao" parent="baseDao"/> <!-- 配置事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="append*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="modify*" propagation="REQUIRED" /> <tx:method name="edit*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="remove*" propagation="REQUIRED" /> <tx:method name="repair" propagation="REQUIRED" /> <tx:method name="delAndRepair" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" /> <tx:method name="find*" propagation="SUPPORTS" /> <tx:method name="load*" propagation="SUPPORTS" /> <tx:method name="search*" propagation="SUPPORTS" /> <tx:method name="datagrid*" propagation="SUPPORTS" /> <tx:method name="*" propagation="SUPPORTS" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="transactionPointcut" expression="execution(* com.yw.service..*(..))" /> <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" /> </aop:config> </beans>
好了配置文件就这样可以了。
③ 接来下就是配置web.xml 的文件了:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>WebApp</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- spring的配置 开始 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:com/yw/conf/spring.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- spring的配置 结束 --> <!-- springmvc的配置 开始 --> <servlet> <servlet-name>SpringMvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:com/yw/conf/springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>SpringMvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!-- springmvc的配置 结束 --> <!-- 字符的过滤器 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
④ 创建包的结构了:
⑤创建一个base类dao了, 代码如下:
package com.yw.dao; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.sql.Types; import java.util.List; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; /** * 有一个规则哦 ,所有model 的字段属性 id这个属性必须放在第一位, * 因为了后来数组拷贝用的 * @author yw * * @param <T> * @param <Tb> */ public class BaseDao<T,Tb> { public static final String SQL_INSERT="insert"; public static final String SQL_UPDATE="update"; public static final String SQL_DELETE="delete"; private Class<T> entityClass; private Class<Tb> pClass; protected NamedParameterJdbcTemplate namedParameterJdbcTemplate; protected JdbcTemplate jdbcTemplate; public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public BaseDao(){ ParameterizedType type=(ParameterizedType) getClass().getGenericSuperclass(); entityClass=(Class<T>) type.getActualTypeArguments()[0]; ParameterizedType typep=(ParameterizedType) getClass().getGenericSuperclass(); pClass=(Class<Tb>) typep.getActualTypeArguments()[0]; } //封装一下简单的组装sql语句,就是常用的哦 public String SQl(String sqlFla){ StringBuffer sb=new StringBuffer(); //获取改bean所有的字段 Field[] field=entityClass.getDeclaredFields(); if(SQL_INSERT.equals(sqlFla)){ sb.append("INSERT INTO ").append(entityClass.getSimpleName()) .append(" ("); for(int i=0;i<field.length;i++){ field[i].setAccessible(true);//暴露反射 sb.append(field[i].getName()).append(","); } sb.deleteCharAt(sb.length()-1); sb.append(" ) ").append("VALUES ("); for(int i=0;i<field.length;i++){ sb.append("?,"); } sb.deleteCharAt(sb.length()-1); sb.append(" ) "); } else if(SQL_UPDATE.equals(sqlFla)){ sb.append("UPDATE ").append(entityClass.getSimpleName()+" SET "); for(int i=0;i<field.length;i++){ field[i].setAccessible(true); if(field[i].getName().equalsIgnoreCase("id")){ continue; } sb.append(field[i].getName()).append(" = ").append("?,"); } sb.deleteCharAt(sb.length()-1); sb.append(" WHERE id=?"); } else if(SQL_DELETE.equals(sqlFla)){ sb.append("DELETE FROM ").append(entityClass.getSimpleName()); sb.append(" WHERE id=?"); } return sb.toString(); } //设置值 private Object[] setArgs(T entity,String sqlFla){ Field[] fields=entityClass.getDeclaredFields(); if(SQL_INSERT.equals(sqlFla)){ Object []obj=new Object[fields.length]; for (int i = 0; i < obj.length; i++) { fields[i].setAccessible(true); try { obj[i]=fields[i].get(entity); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } return obj; } else if(SQL_UPDATE.equals(sqlFla)){ Object []obj=new Object[fields.length]; int id=0; for (int i = 0; i < obj.length; i++) { fields[i].setAccessible(true); try { obj[i]=fields[i].get(entity); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } Object []objArr=new Object[fields.length]; System.arraycopy(obj, 1, objArr, 0, fields.length-1); objArr[obj.length - 1]=obj[0]; return objArr; }else if(SQL_DELETE.equals("delete")){ Object[] obj=new Object[1]; fields[0].setAccessible(true); try { obj[0]=fields[0].get(entity); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return obj; } return null; } //设置值对应的类型 private int [] setArgsTypes(T entity,String sqlFlag){ Field[] fields = entityClass.getDeclaredFields(); if (sqlFlag.equals(SQL_INSERT)) { int[] argTypes = new int[fields.length]; try { for (int i = 0; argTypes != null && i < argTypes.length; i++) { fields[i].setAccessible(true); // 暴力反射 if (fields[i].get(entity).getClass().getName().equals("java.lang.String")) { argTypes[i] = Types.VARCHAR; } else if (fields[i].get(entity).getClass().getName().equals("java.lang.Double")) { argTypes[i] = Types.DECIMAL; } else if (fields[i].get(entity).getClass().getName().equals("java.lang.Integer")) { argTypes[i] = Types.INTEGER; } else if (fields[i].get(entity).getClass().getName().equals("java.util.Date")) { argTypes[i] = Types.DATE; } else if (fields[i].get(entity).getClass().getName().equals("java.sql.Timestamp")) { argTypes[i] = Types.TIMESTAMP; } else if (fields[i].get(entity).getClass().getName().equals("java.math.BigDecimal")) { argTypes[i] = Types.DECIMAL; } } } catch (Exception e) { e.printStackTrace(); } return argTypes; } else if (sqlFlag.equals(SQL_UPDATE)) { int[] tempArgTypes = new int[fields.length]; int[] argTypes = new int[fields.length]; try { for (int i = 0; tempArgTypes != null && i < tempArgTypes.length; i++) { fields[i].setAccessible(true); // 暴力反射 if (fields[i].get(entity).getClass().getName().equals("java.lang.String")) { tempArgTypes[i] = Types.VARCHAR; } else if (fields[i].get(entity).getClass().getName().equals("java.lang.Double")) { tempArgTypes[i] = Types.DECIMAL; } else if (fields[i].get(entity).getClass().getName().equals("java.lang.Integer")) { tempArgTypes[i] = Types.INTEGER; } else if (fields[i].get(entity).getClass().getName().equals("java.util.Date")) { tempArgTypes[i] = Types.DATE; } else if (fields[i].get(entity).getClass().getName().equals("java.sql.Timestamp")) { tempArgTypes[i] = Types.TIMESTAMP; } else if (fields[i].get(entity).getClass().getName().equals("java.math.BigDecimal")) { tempArgTypes[i] = Types.DECIMAL; } } System.arraycopy(tempArgTypes, 1, argTypes, 0, tempArgTypes.length - 1); // 数组拷贝 argTypes[argTypes.length - 1] = tempArgTypes[0]; } catch (Exception e) { e.printStackTrace(); } return argTypes; } else if (sqlFlag.equals(SQL_DELETE)) { int[] argTypes = new int[1]; // 长度是1 try { fields[0].setAccessible(true); // 暴力反射 if (fields[0].get(entity).getClass().getName().equals("java.lang.String")) { argTypes[0] = Types.VARCHAR; } else if (fields[0].get(entity).getClass().getName().equals("java.lang.Integer")) { argTypes[0] = Types.INTEGER; } } catch (Exception e) { e.printStackTrace(); } return argTypes; } return null; } public void save(T entity){ String sql=this.SQl(SQL_INSERT); Object [] obj=this.setArgs(entity, SQL_INSERT); System.out.println(sql); for (int i = 0; i < obj.length; i++) { System.out.println("--------------------"); System.out.println(obj[i]); System.out.println("--------------------"); } int [] objTypes=this.setArgsTypes(entity, SQL_INSERT); jdbcTemplate.update(sql, obj,objTypes); } public void upate(T entity){ String sql=this.SQl(SQL_UPDATE); Object [] obj=this.setArgs(entity, SQL_UPDATE); int [] objTypes=this.setArgsTypes(entity, SQL_UPDATE); jdbcTemplate.update(sql, obj, objTypes); } public void delete(T entity){ String sql=this.SQl(SQL_DELETE); Object [] obj=this.setArgs(entity, SQL_DELETE); int [] objTypes=this.setArgsTypes(entity, SQL_DELETE); jdbcTemplate.update(sql, obj, objTypes); } public List<T> findAll(){ String sql="SELECT * FROM "+entityClass.getSimpleName(); RowMapper<T> rowMapper=BeanPropertyRowMapper.newInstance(entityClass); return jdbcTemplate.query(sql, rowMapper); } public T findById(Serializable id){ String sql="SELECt * FROM "+entityClass.getSimpleName()+" where id=?"; RowMapper<T> rowMapper=BeanPropertyRowMapper.newInstance(entityClass); if(jdbcTemplate.query(sql, rowMapper, id).size()>0) return jdbcTemplate.query(sql, rowMapper, id).get(0); return null; } }
⑥ 写一个Uerdao集成baseDao,代码如下
package com.yw.dao; import com.yw.Dto.UserDto; import com.yw.model.User; public class UserDao extends BaseDao<User, UserDto> { }
就是这样就行了,想增加一个sql语句就这样慢慢一个添加就的了
⑦ model和dto如下:
package com.yw.model; public class User { @Override public String toString() { return "User [id=" + id + ", name=" + name + ", pass=" + pass + "]"; } private Integer id; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPass() { return pass; } public void setPass(String pass) { this.pass = pass; } private String name; private String pass; } /---------------------/ package com.yw.Dto; public class UserDto { private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPass() { return pass; } public void setPass(String pass) { this.pass = pass; } private String name; private String pass; }
⑧ service层创建 一个Userservice,代码如下:
package com.yw.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.yw.dao.UserDao; import com.yw.model.User; @Service("userService") public class UserService { @Autowired private UserDao userDao; public void save(User user){ userDao.save(user); } public void delete(User user){ userDao.delete(user); } public void update(User user){ userDao.upate(user); } public User findById(int id){ return userDao.findById(id); } public void findAll(){ List<User> user=userDao.findAll(); System.out.println(user); } }
⑨ 就是Contrlloer层了 创建一个userController
package com.yw.Contrlloer; import java.io.IOException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import com.yw.model.User; import com.yw.service.UserService; @Controller @RequestMapping("/test/controller") public class UserController { @Autowired private UserService userService; @RequestMapping("/test.do") public void test(HttpServletRequest reServletRequest,HttpServletResponse response) throws IOException{ response.getWriter().println("23456789-"); //查询所有的用户 userService.findAll(); //查询id为2的用户 User user=userService.findById(2); //增加一个用户 User user2=new User(); user2.setId(0); //增加数据的是数据库的id为在自增的,所以在这里就写死了 user2.setName("夏明"); user2.setPass("12345678"); userService.save(user2); //删除一个用户 userService.delete(user); //更新一个用户,更新之前最好是查询一次在更新 User user3=userService.findById(2); user3.setName("GaVien"); userService.update(user3); } }
好了到这里算是真正完成了,直接跑起来O了,项目就这样就结束。
笔者说说在遇到问题和注意事项以及心得吧:
(1)笔者老是在配置spring配置出错的,老是报bean创建失败,出现这个问题 第一个可能是 扫描包可能没有扫到
第二可能是bean的配置的class的包的路径不对
第三可能是你的jdk编译有问题,如是:自己百度一下,更换一下jdk吧
第四可能是你没有添加bean吧
(2)创建model的时候有id的必须在所有字段的属性前面,为后来的baseDao的数据拷贝方便呢
(3)经过笔者的测试 ,自己的写反射运行和数据库响应时间并没有比mybatis和hibernate慢甚至还快呢呢,而且自己写的反射所有sql语句都可以自己去控制,没有任何多余的数据呢,
(4)对于宇宙无敌的spring框架不熟,那你就只能自己去补了,反射也是咯 哈哈
最后项目下载路径 http://pan.baidu.com/s/1c2mMHiS
以上是关于利用反射搭建项目的dao层,从此可以告别被人的dao层框架了(spring+反射)的主要内容,如果未能解决你的问题,请参考以下文章
springboot整合knife4j,从此告别手写接口文档