Spring_04
A.模版模式
1.概述
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式
2.冒泡排序
不管哪种对象的排序,冒泡算法是固定的,所以定义抽象父类固化算法,将不能实现的比较算法延迟到子类中实现,不同的子类就可以共享父类中定义的算法
public abstract class BubbleSorter { public void sort(Object[] arr){ for(int i=1;i<arr.length;i++){ for(int k=0;k<arr.length-i;k++){ if(bigger(arr[k], arr[k+1])){ Object temp=arr[k]; arr[k]=arr[k+1]; arr[k+1]=temp; } } } } public abstract boolean bigger(Object obj1,Object obj2); }
public class IntegerSorter extends BubbleSorter { @Override public boolean bigger(Object obj1, Object obj2) { if (obj1 == null || obj2 == null || !(obj1 instanceof Integer) || !(obj2 instanceof Integer)) throw new IllegalArgumentException("参数错误"); int k1 = (Integer) obj1; int k2 = (Integer) obj2; return k1 > k2; } }
import java.util.Arrays; import java.util.Random; public class Test { public static void main(String[] args) { Integer[] arr = new Integer[10]; Random r = new Random(); for (int i = 0; i < arr.length; i++) { arr[i]=r.nextInt(100); } System.out.println(Arrays.toString(arr)); BubbleSorter bs=new IntegerSorter(); bs.sort(arr); System.out.println(Arrays.toString(arr)); } }
3.意义
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
4.优点
a.封装不变部分,扩展可变部分
b.提取公共代码,便于维护
c.行为由父类控制,子类实现
5.缺点
每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大
6.使用场景
a.有多个子类共有的方法,且逻辑相同
b.重要的、复杂的方法,可以考虑作为模板方法
B.JDBC
1.概述
采用模板模式针对JDBC编程提供了对应的解决方案
在pom.xml下载相应的jar
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.wpf</groupId> <artifactId>Spring</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <!-- 文件拷贝时的编码 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <!-- 编译时的编码 --> <maven.compiler.encoding>UTF-8</maven.compiler.encoding> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.14.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>4.3.14.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
2.获取连接
建立配置文件database.properties
applicationContextjdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///test jdbc.username=root jdbc.password=root
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <context:property-placeholder location="classpath:database.properties" /> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" p:driverClassName="${jdbc.driver}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" destroy-method="close" /> <bean id="userDao" class="org.wpf.dao.UserDaoImpl" p:dataSource-ref="dataSource" /> </beans>
3.编写代码
UserBean
接口package org.wpf.dao; import java.io.Serializable; public class UserBean implements Serializable { private static final long serialVersionUID = 2369146800495660373L; private Long id; private String username; private String password; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
package org.wpf.dao; public interface IUserDao { void save(UserBean user); }
实现类(Spring针对DAO编程提供了一个父类,例如针对jdbc编程提供了一个JdbcDaoSuppor)
package org.wpf.dao; import org.springframework.jdbc.core.support.JdbcDaoSupport; public class UserDaoImpl extends JdbcDaoSupport implements IUserDao { @Override public void save(UserBean user) { String sql = "insert into t_users(username,password) values(?,?)"; this.getJdbcTemplate().update(sql, user.getUsername(), user.getPassword()); } }
测试类
package org.wpf.dao; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.wpf.dao.UserBean; public class Test1 { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); IUserDao userDao=ac.getBean("userDao",IUserDao.class); UserBean temp=new UserBean(); temp.setUsername("zhangsan"); temp.setPassword("123456"); userDao.save(temp); } }
4.异常
Spring对jdbc中的异常进行了二次封装
将受检型异常SQLException转换为运行时异常DataAccessException
异常的颗粒度变小,可以明确异常原因
将受检型异常封装为运行时异常,编码简单
5.增删改update
a.update(String):int返回值表示sql语句执行的受影响行数
参数是SQL语句,其中不能包含?占位符
b.update(String sql,Object...params):int返回值表示sql语句执行的受影响行数
参数1是SQL语句,其中可以包含?占位符,如果有占位符,则params就是对应位置上的数据
注意:数据类型问题 java.util.Date和java.sql.Date
c.update(new PreparedStatementCreator() {}
利用匿名内部类的方式定义PreparedStatement的创建对象
也就是当JdbcTemplate执行时
会自动回调createPreparedStatement方法获取所需要执行的Statement对象
调用时会自动传入Connection对象
public PreparedStatement createPreparedStatement(Connection con) throws SQLException { PreparedStatement res=con.prepareStatement("insert into t_roles(name) values(?)"); res.setString(1, role.getName()); return res; }
如果数据库表中定义了default值时使用,用于根据参数生成不同的SQL语句
d.update("insert into t_roles(name) values(?)", new PreparedStatementSetter(){}
利用匿名内部类的方式定义给要执行的PreparedStatement进行赋值操作
也就是当JdbcTemplate执行PreparedStatement时,会自动回调
PreparedStatementSetter给?赋值操作
public void setValues(PreparedStatement ps) throws SQLException { ps.setString(1, role.getName()); }
e.update("insert into t_roles(name) values(?)", new Object[]{role.getName()}, new int[]{Types.VARCHAR}):int
参数1是包含?的SQL语句
参数2是对应?的具体数据组成的数组
参数3是每个?对应的数据类型说明,类型都定义java.sql.Types类中
f.update(new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
PreparedStatement ps=con.prepareStatement("insert into t_roles(name) values(?)"对应的SQL语句, new String[]{"id"}需要返回的自动生成列的名称);
ps.setString(1, role.getName());
return ps;
}
}, KeyHolder的实现,用于获取自动生成的key值); 用于获取数据库表自动插入的id值
6.查query
a. RowMapper<T>
用于返回List<T>,当SpringJDBC查询后
框架会自动判定是否有数据,一行判定一次
如果有数据在回调方法,处理完成后框架继续判定是否有下一行数据
当方法回调时,框架会自动注入回调次数,从0开始计数
return this.getJdbcTemplate().query("select * from t_roles", new RowMapper<RoleBean>() { @Override public RoleBean mapRow(ResultSet rs, int rowNum) throws SQLException { RoleBean res = new RoleBean(); res.setId(rs.getLong("id")); res.setName(rs.getString("name")); return res; } });
b.ResultSetExtractor<T>
用于返回T,当SpringJDBC查询完成后
不管是否有数据都会进行方法的回调,而且只回调一次
注意因为框架并没有判定是否数据
所以需要自行编码判读,也就是说需要调用resultSet.next方法
return this.getJdbcTemplate().query("select * from t_roles", new ResultSetExtractor<List<RoleBean>>() { @Override public List<RoleBean> extractData(ResultSet rs) throws SQLException, DataAccessException { List<RoleBean> res = new ArrayList<RoleBean>(); while (rs.next()) { RoleBean temp = new RoleBean(); temp.setId(rs.getLong("id")); temp.setName(rs.getString("name")); res.add(temp); } return res; } });