public class Configuration {
//数据源
private DataSource dataSource;
//map集合: key:statementId value:MappedStatement
private Map mappedStatementMap = new HashMap<>();
public DataSource getDataSource() {
return dataSource;
}
public Configuration setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
return this;
}
public Map getMappedStatementMap() {
return mappedStatementMap;
}
public Configuration setMappedStatementMap(Map mappedStatementMap) {
this.mappedStatementMap = mappedStatementMap;
return this;
}
}
Sql语句信息实体
public class MappedStatement {
//id
private String id;
//sql语句
private String sql;
//输⼊参数
private String parameterType;
//输出参数
private String resultType;
public String getId() {
return id;
}
public MappedStatement setId(String id) {
this.id = id;
return this;
}
public String getSql() {
return sql;
}
public MappedStatement setSql(String sql) {
this.sql = sql;
return this;
}
public String getParameterType() {
return parameterType;
}
public MappedStatement setParameterType(String parameterType) {
this.parameterType = parameterType;
return this;
}
public String getResultType() {
return resultType;
}
public MappedStatement setResultType(String resultType) {
this.resultType = resultType;
return this;
}
}
顺便定义一个Resources类来读取xml文件流
public class Resources {
public static InputStream getResourceAsSteam(String path) {
return Resources.class.getClassLoader().getResourceAsStream(path);
}
}
接下来就是实际的解析了,因为解析代码比较多,我们考虑封装类单独处理解析
定义XMLConfigBuilder类解析数据库配置信息
public class XMLConfigBuilder {
private Configuration configuration;
public XMLConfigBuilder() {
this.configuration = new Configuration();
}
public Configuration parserConfiguration(InputStream inputStream) throws DocumentException, PropertyVetoException, ClassNotFoundException {
Document document = new SAXReader().read(inputStream);
Element rootElement = document.getRootElement();
List propertyElements = rootElement.selectNodes("//property");
Properties properties = new Properties();
for (Element propertyElement : propertyElements) {
String name = propertyElement.attributeValue("name");
String value = propertyElement.attributeValue("value");
properties.setProperty(name,value);
}
//解析到数据库配置信息,设置数据源信息
ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
comboPooledDataSource.setDriverClass(properties.getProperty("driverClass"));
comboPooledDataSource.setJdbcUrl(properties.getProperty("jdbcUrl"));
comboPooledDataSource.setUser(properties.getProperty("username"));
comboPooledDataSource.setPassword(properties.getProperty("password"));
configuration.setDataSource(comboPooledDataSource);
//将configuration传入XMLMapperBuilder中做sql语句解析。
XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(this.configuration);
List mapperElements = rootElement.selectNodes("//mapper");
for (Element mapperElement : mapperElements) {
String mapperPath = mapperElement.attributeValue("resource");
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(mapperPath);
xmlMapperBuilder.parse(resourceAsStream);
}
return configuration;
}
}
定义XMLMapperBuilder类解析数据库配置信息
public class XMLMapperBuilder {
private Configuration configuration;
public XMLMapperBuilder(Configuration configuration) {
this.configuration = configuration;
}
public void parse(InputStream inputStream) throws DocumentException,
ClassNotFoundException {
Document document = new SAXReader().read(inputStream);
Element rootElement = document.getRootElement();
String namespace = rootElement.attributeValue("namespace");
List select = rootElement.selectNodes("select");
for (Element element : select) { //id的值
String id = element.attributeValue("id");
String parameterType = element.attributeValue("parameterType"); //输⼊参数
String resultType = element.attributeValue("resultType"); //返回参数
//statementId,后续调用通过statementId,找到对应的sql执行
String key = namespace + "." + id;
//sql语句
String textTrim = element.getTextTrim();
//封装 mappedStatement
MappedStatement mappedStatement = new MappedStatement();
mappedStatement.setId(id);
mappedStatement.setParameterType(parameterType);
mappedStatement.setResultType(resultType);
mappedStatement.setSql(textTrim);
//填充 configuration
configuration.getMappedStatementMap().put(key, mappedStatement);
}
}
}
public interface SqlSession {
//查询多个
public List selectList(String statementId, Object... param) throws Exception;
//查询一个
public T selectOne(String statementId,Object... params) throws Exception;
}
public interface SqlSession {
public List selectList(String statementId, Object... param) throws Exception;
public T selectOne(String statementId,Object... params) throws Exception;
//为Dao接口生成代理实现类
public T getMapper(Class mapperClass);
}
public class DefaultSqlSession implements SqlSession {
private Configuration configuration;
private Executor simpleExcutor = new SimpleExecutor();
public DefaultSqlSession(Configuration configuration) {
this.configuration = configuration;
}
@Override
public List selectList(String statementId, Object... param) throws Exception {
MappedStatement mappedStatement =
configuration.getMappedStatementMap().get(statementId);
List query = simpleExcutor.query(configuration, mappedStatement, param);
return query;
}
@Override
public T selectOne(String statementId, Object... params) throws Exception {
List objects = selectList(statementId, params);
if (objects.size() == 1) {
return (T) objects.get(0);
} else {
throw new RuntimeException("返回结果过多");
}
}
@Override
public T getMapper(Class mapperClass) {
Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// selectOne
String methodName = method.getName();
// className:namespace
String className = method.getDeclaringClass().getName();
//statementId
String statementId = className+'.'+methodName;
Type genericReturnType = method.getGenericReturnType();
//判断是否实现泛型类型参数化
if (genericReturnType instanceof ParameterizedType){
List objects = selectList(statementId,args);
return objects;
}
return selectOne(statementId,args);
}
});
return (T) proxyInstance;
}
}
定义业务数据dao接口
public interface IUserDao {
//查询所有用户
public List findAll() throws Exception;
//根据条件进行用户查询
public User findByCondition(User user) throws Exception;
}
接下来我们只需获取到代理对象,调用方法即可。
public class Main2 {
public static void main(String[] args) throws Exception {
InputStream resourceAsSteam = Resources.getResourceAsSteam("sqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsSteam);
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取到代理对象
IUserDao userDao = sqlSession.getMapper(IUserDao.class);
List all = userDao.findAll();
for (User user1 : all) {
System.out.println(user1);
}
}
}