在上一篇文章中提到了 JDBC 模版语法的基本使用,
https://blog.csdn.net/qq_33811662/article/details/80533046
现在在数据库中多加一个表:
表结构为:
表数据为:
pom.xml,springConfig.xml 与上文一样,文件结构如下:
BookVO 的代码如下:
package springjdbc.vo;
public class BookVO {
private Integer id;
private String name;
private Double price;
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 Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public BookVO(Integer id, String name, Double price) {
super();
this.id = id;
this.name = name;
this.price = price;
}
public BookVO() {
super();
}
@Override
public String toString() {
return "BookVO [id=" + id + ", name=" + name + ", price=" + price + "]";
}
}
BookDao 代码如下:
package springjdbc.impl;
import java.util.List;
import springjdbc.vo.BookVO;
public interface BookDao {
List listBook();
}
BookService 代码如下:
package springjdbc.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import springjdbc.impl.BookDao;
import springjdbc.vo.BookVO;
@Component
public class BookService {
@Autowired
private BookDao bookDao;
public void listBook() {
List list = bookDao.listBook();
for (BookVO bookVo : list)
System.out.println(bookVo);
}
}
BookMapper 代码如下:
package springjdbc.mapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import springjdbc.vo.BookVO;
public class BookMapper implements RowMapper {
public BookVO mapRow(ResultSet rs, int rowNum) throws SQLException {
BookVO bookVo = new BookVO();
bookVo.setId(rs.getInt("id"));
bookVo.setName(rs.getString("name"));
bookVo.setPrice(rs.getDouble("price"));
return bookVo;
}
}
BookDaoImple 代码如下:
package springjdbc;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import springjdbc.impl.BookDao;
import springjdbc.mapper.BookMapper;
import springjdbc.vo.BookVO;
@Component
public class BookDaoImpl implements BookDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public List listBook() {
String sql = "select * from book";
List list = jdbcTemplate.query(sql, new BookMapper());
return list;
}
}
简单的几个操作,就可以拿出一个新增的表中的内容,但是,如果有多个表,是否需要写多个Mapper?这样的模版方法是否正确呢?答案当然是否定的。
首先封装map的集合,新建MapMapper类,实现 RowMapper,代码如下:
package springjdbc.mapper;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.springframework.jdbc.core.RowMapper;
public class MapMapper implements RowMapper {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
Map map = new HashMap();
ResultSetMetaData metaData = rs.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
Object value = rs.getObject(i);
String name = metaData.getColumnName(i).toLowerCase();
if (name != null && !name.equals("")) {
map.put(name, value);
}
}
return map;
}
}
修改 SpringDaoImpl 的第40行
List list = jdbcTemplate.query(sql, new SpringMapper());
改为
List list = jdbcTemplate.query(sql, new MapMapper());
运行程序,报错,报错信息为:
Exception in thread "main" java.lang.ClassCastException: java.util.HashMap cannot be cast to springjdbc.vo.SpringVO
at springjdbc.service.SpringService.listSpring(SpringService.java:23)
at springjdbc.SpringTest.main(SpringTest.java:13)
定位到代码部分,SpringService 的 23 行(22-24行):
List list = springDao.listSpring();
for (SpringVO springVo : list)
System.out.println(springVo);
因为此时 list 中的是 Map 对象,使用 SpringVO 转化是有问题的,改为:
List> list = springDao.listSpring();
list.forEach(System.out::println);
再次运行,输出结果:
{spring_name=SpringIOC, spring_id=1, spring_version=3.0}
{spring_name=SpringAOP, spring_id=2, spring_version=3.5}
{spring_name=SpringJDBC, spring_id=3, spring_version=3.8}
{spring_name=SpringTX, spring_id=4, spring_version=4.2}
BookVO [id=1, name=Java, price=10.0]
BookVO [id=2, name=Python, price=15.0]
同理,将 BookDaoImpl 和 BookService 也改为 MapMapper:
BookDaoImol:
@Override
public List listBook() {
String sql = "select * from book";
List list = jdbcTemplate.query(sql, new MapMapper());
return list;
}
BookService:
public void listBook() {
List> list = bookDao.listBook();
list.forEach(System.out::println);
}
再次运行,输出结果:
{spring_name=SpringIOC, spring_id=1, spring_version=3.0}
{spring_name=SpringAOP, spring_id=2, spring_version=3.5}
{spring_name=SpringJDBC, spring_id=3, spring_version=3.8}
{spring_name=SpringTX, spring_id=4, spring_version=4.2}
{price=10.0, name=Java, id=1}
{price=15.0, name=Python, id=2}
但是问题来,我不希望这只是一个 Map 对象,而是希望返回的就是拿到的对象,即所见即所得。
那么此时可以封装通用的 Mapper 类,增加一个类,CommonMapper:
package springjdbc.mapper;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.jdbc.core.RowMapper;
public class CommonMapper implements RowMapper {
private Class clz;
public CommonMapper(Class clz) {
this.clz = clz;
}
public T mapRow(ResultSet rs, int rowNum) {
try {
T obj = clz.newInstance();
ResultSetMetaData metaData = rs.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
Object value = rs.getObject(i);
String name = metaData.getColumnName(i).toLowerCase();
if (name != null && !name.equals("")) {
BeanUtils.setProperty(obj, name, value);
}
}
return obj;
} catch (InstantiationException | IllegalAccessException | SQLException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
将 BookDaoImpl 中的代码改为:
@Override
public List listBook() {
String sql = "select * from book";
List list = jdbcTemplate.query(sql, new CommonMapper(BookVO.class));
return list;
}
运行 main 方法输出结果:
{spring_name=SpringIOC, spring_id=1, spring_version=3.0}
{spring_name=SpringAOP, spring_id=2, spring_version=3.5}
{spring_name=SpringJDBC, spring_id=3, spring_version=3.8}
{spring_name=SpringTX, spring_id=4, spring_version=4.2}
BookVO [id=1, name=Java, price=10.0]
BookVO [id=2, name=Python, price=15.0]
此时 BookService 所拿到的就是普通的 Book 对象了,符合了我们的需求,此时,将 SpringDaoImple 的 listSpring 也改为 CommonMapper:
@Override
public List listSpring() {
String sql = "select * from spring_text";
List list = jdbcTemplate.query(sql, new CommonMapper(SpringVO.class));
return list;
}
运行程序,结果为:
SpringVO [springId=0, springName=null, springVersion=null]
SpringVO [springId=0, springName=null, springVersion=null]
SpringVO [springId=0, springName=null, springVersion=null]
SpringVO [springId=0, springName=null, springVersion=null]
BookVO [id=1, name=Java, price=10.0]
BookVO [id=2, name=Python, price=15.0]
发现不对经,什么都没取到,找错后发现,数据库中的 Spring 是以下划线命名法,而 Java 中是以驼峰命名法,只能修改下 CommonMapper 方法:
package springjdbc.mapper;
import java.lang.reflect.InvocationTargetException;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.jdbc.core.RowMapper;
public class CommonMapper1 implements RowMapper {
private Class clz;
public CommonMapper(Class clz) {
this.clz = clz;
}
public T mapRow(ResultSet rs, int rowNum) {
try {
T obj = clz.newInstance();
ResultSetMetaData metaData = rs.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
Object value = rs.getObject(i);
String name = metaData.getColumnName(i);
if (name.indexOf("_") > 0) {
name = name.toLowerCase();
String[] params = name.split("_");
StringBuffer strb = new StringBuffer(params[0]);
for (int j = 1; j < params.length; j++)
if (params[j] != null && !params[j].equals(""))
strb.append(params[j].substring(0, 1).toUpperCase() + params[j].substring(1));
name = strb.toString();
}
if (name != null && !name.equals("")) {
BeanUtils.setProperty(obj, name, value);
}
}
return obj;
} catch (InstantiationException | IllegalAccessException | SQLException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
此时运行程序输出:
SpringVO [springId=1, springName=SpringIOC, springVersion=3.0]
SpringVO [springId=2, springName=SpringAOP, springVersion=3.5]
SpringVO [springId=3, springName=SpringJDBC, springVersion=3.8]
SpringVO [springId=4, springName=SpringTX, springVersion=4.2]
BookVO [id=1, name=Java, price=10.0]
BookVO [id=2, name=Python, price=15.0]
完善模版:
package springjdbc.mapper;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.jdbc.core.RowMapper;
public class CommonMapper3 implements RowMapper {
private Class clz;
public CommonMapper(Class clz) {
this.clz = clz;
}
public T mapRow(ResultSet rs, int rowNum) {
try {
T obj = clz.newInstance();
ResultSetMetaData metaData = rs.getMetaData();
for (int i = 1; i <= metaData.getColumnCount(); i++) {
Object value = rs.getObject(i);
StringBuffer strbGet = new StringBuffer("get");
StringBuffer strbSet = new StringBuffer("set");
String name = metaData.getColumnName(i);
if (name.indexOf("_") > 0) {
name = name.toLowerCase();
String[] params = name.split("_");
for (String param : params) {
if (param != null && param.length() > 0) {
String suffix = param.substring(0, 1).toUpperCase() + param.substring(1);
strbGet.append(suffix);
strbSet.append(suffix);
}
}
} else {
strbGet.append(name.substring(0, 1).toUpperCase() + name.substring(1));
strbSet.append(name.substring(0, 1).toUpperCase() + name.substring(1));
}
Method methodGet;
Method methodSet;
try {
methodGet = clz.getDeclaredMethod(strbGet.toString());
methodSet = clz.getDeclaredMethod(strbSet.toString(), methodGet.getReturnType());
methodSet.invoke(obj, value);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
if (name != null && !name.equals("")) {
BeanUtils.setProperty(obj, name, value);
}
}
return obj;
} catch (InstantiationException | IllegalAccessException | SQLException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}