Spring 坑路5 -> 封装自定义 JDBC 模版

在上一篇文章中提到了 JDBC 模版语法的基本使用,
https://blog.csdn.net/qq_33811662/article/details/80533046
现在在数据库中多加一个表:
表结构为:
Spring 坑路5 -> 封装自定义 JDBC 模版_第1张图片
表数据为:
Spring 坑路5 -> 封装自定义 JDBC 模版_第2张图片

pom.xml,springConfig.xml 与上文一样,文件结构如下:
Spring 坑路5 -> 封装自定义 JDBC 模版_第3张图片
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;
    }

}

你可能感兴趣的:(javaee,spring)