(六)SpringBoot+SpringCloud —— 集成MyBatis

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

主要是MyBatis与SpringBoot的继承,此处与SpringCloud无关,作为记录。

依赖与配置

数据库使用的是MySql,所以需要加入以下的依赖:

		
			org.mybatis.spring.boot
			mybatis-spring-boot-starter
			1.3.0
		
		
			mysql
			mysql-connector-java
			runtime
		

配置文件application.yml如下:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 7001
spring:
  application:
    name: SERVICE-USER
  datasource: #数据源
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/owl-bookstore?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
    username: root
    password: root
    dbcp2: #dbcp2连接池
      max-idle: 10
mybatis:
  #实体类的包
  type-aliases-package: cn.net.bysoft.owl.bookstore.facade.user.entity
  #mapper.xml存放的路径
  mapperLocations: classpath:mapper/*.xml
  #mybatis配置文件存放的路径
  configLocation: classpath:mybatis-config.xml

实现代码

通过上面的依赖和配置,基本可以用自己熟悉的方式使用Mybatis了。

下面来记录一下我自己的实现,实现很简单,没有考虑过多的东西。

可以采用注解的方式使用mybatis,但是此处我使用的是比较原始的方法,配置mapper来使用mybatis。

  1. 定义一个BaseDao接口和BaseDaoImpl实现类,编写一些通用的Dao方法。
  2. 定义一个BaseEntity实体类,同样定义一些常用的方法。
  3. 分页采用了Mybatis的拦截器实现。

直接贴出代码,BaseEntity类:

package cn.net.bysoft.owl.bookstore.common.entity;

import java.io.Serializable;

public abstract class BaseEntity implements Serializable {

	private static final long serialVersionUID = -1105239108084459358L;
	private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

}

分页的实体类:

package cn.net.bysoft.owl.bookstore.common.entity;

import java.io.Serializable;
import java.util.List;

/**
 * 分页组件。
* 用于前端DataGrid控件初始化。
* 组件内包含当前页、每页显示条数、总记录数、数据、总页数、页码索引等信息。 * * @author XuePeng */ public class PageBean implements Serializable { private static final long serialVersionUID = 8470697978259453214L; private int currentPage; private int numPerPage; private int totalCount; private List recordList; private int pageCount; private int beginPageIndex; private int endPageIndex; public PageBean(int currentPage, int numPerPage, int totalCount, List recordList) { this.currentPage = currentPage; this.numPerPage = numPerPage; this.totalCount = totalCount; this.recordList = recordList; // 计算总页码 pageCount = (totalCount + numPerPage - 1) / numPerPage; // 计算 beginPageIndex 和 endPageIndex // 总页数不多于10页,则全部显示 if (pageCount <= 10) { beginPageIndex = 1; endPageIndex = pageCount; } // 总页数多于10页,则显示当前页附近的共10个页码 else { // 当前页附近的共10个页码(前4个 + 当前页 + 后5个) beginPageIndex = currentPage - 4; endPageIndex = currentPage + 5; // 当前面的页码不足4个时,则显示前10个页码 if (beginPageIndex < 1) { beginPageIndex = 1; endPageIndex = 10; } // 当后面的页码不足5个时,则显示后10个页码 if (endPageIndex > pageCount) { endPageIndex = pageCount; beginPageIndex = pageCount - 10 + 1; } } } public int getCurrentPage() { return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } public int getNumPerPage() { return numPerPage; } public void setNumPerPage(int numPerPage) { this.numPerPage = numPerPage; } /** * @return 获得总记录数。 */ public int getTotalCount() { return totalCount; } public void setTotalCount(int totalCount) { this.totalCount = totalCount; } public List getRecordList() { return recordList; } public void setRecordList(List recordList) { this.recordList = recordList; } public int getPageCount() { return pageCount; } public void setPageCount(int pageCount) { this.pageCount = pageCount; } public int getBeginPageIndex() { return beginPageIndex; } public void setBeginPageIndex(int beginPageIndex) { this.beginPageIndex = beginPageIndex; } public int getEndPageIndex() { return endPageIndex; } public void setEndPageIndex(int endPageIndex) { this.endPageIndex = endPageIndex; } }
package cn.net.bysoft.owl.bookstore.common.entity;

import java.io.Serializable;

/**
 * 分页参数的实体类。
* 设置对象的当前页数和每页记录数,进行数据库分页查询。 * * @author XuePeng */ public class PageParam implements Serializable { private static final long serialVersionUID = 6297178964005032338L; private int pageNum; private int numPerPage; public PageParam(int pageNum, int numPerPage) { this.pageNum = pageNum; this.numPerPage = numPerPage; } public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public int getNumPerPage() { return numPerPage; } public void setNumPerPage(int numPerPage) { this.numPerPage = numPerPage; } }

接下来,BaseDao接口,定义了CURD的基本方法,和通过分页查询的方法,具体如下:

package cn.net.bysoft.owl.bookstore.common.core.dao;

import java.util.List;
import java.util.Map;

import cn.net.bysoft.owl.bookstore.common.entity.BaseEntity;
import cn.net.bysoft.owl.bookstore.common.entity.PageBean;
import cn.net.bysoft.owl.bookstore.common.entity.PageParam;

public interface BaseDao {

    long insert(T entity);

    int update(T entity);

    int deleteById(long id);

    int deleteByIds(long... id);

    T findById(long id);

    T findByParam(Map paramMap);

    List listByParam(Map paramMap);

    PageBean listByPageAndParam(PageParam pageParam, Map paramMap);

    PageBean listByPageAndParam(PageParam pageParam, Map paramMap, String sqlId);

    long countByParam(Map paramMap);

}

BaseDaoImpl类,实现了BaseDao接口:

package cn.net.bysoft.owl.bookstore.common.core.dao;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;

import cn.net.bysoft.owl.bookstore.common.entity.BaseEntity;
import cn.net.bysoft.owl.bookstore.common.entity.PageBean;
import cn.net.bysoft.owl.bookstore.common.entity.PageParam;

public abstract class BaseDaoImpl extends SqlSessionDaoSupport implements BaseDao {

    private static final String SQL_INSERT = "insert";
    private static final String SQL_UPDATE = "update";
    private static final String SQL_DELETE_BY_ID = "deleteById";
    private static final String SQL_DELETE_BY_IDS = "deleteByIds";
    private static final String SQL_FIND_BY_ID = "findById";
    private static final String SQL_FIND_BY_PARAM = "findByParam";
    private static final String SQL_LIST_BY_PARAM = "listByParam";
    private static final String SQL_LIST_BY_PAGE = "listByPageAndParam";
    private static final String SQL_COUNT_BY_PARAM = "countByParam";

    // SqlSessionTemplate实例(要求Spring中进行SqlSessionTemplate的配置)
    // 可以调用sessionTemplate完成数据库操作
    private SqlSessionTemplate sessionTemplate;

    // SqlSessionFactory实例(要求Spring中进行SqlSessionFactory的配置)
    // 可以调用sessionFactory打开一个SqlSession
    private SqlSessionFactory sessionFactory;

    public SqlSessionTemplate getSessionTemplate() {
        return this.sessionTemplate;
    }

    @Autowired
    public void setSessionTemplate(SqlSessionTemplate sessionTemplate) {
        super.setSqlSessionTemplate(sessionTemplate);
        this.sessionTemplate = sessionTemplate;
    }

    public SqlSessionFactory getSessionFactory() {
        return this.sessionFactory;
    }

    @Override
    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sessionFactory) {
        super.setSqlSessionFactory(sessionFactory);
        this.sessionFactory = sessionFactory;
    }

    @Override
    public long insert(T entity) {
        // 对数据库进行insert操作。
        // 执行Mapper配置文件中的insert方法。
        int result = sessionTemplate.insert(getStatement(SQL_INSERT), entity);
        // 判断如果要新建的实体对象不为null,并且成功保存到数据库了,则返回其主键。
        if (entity != null && entity.getId() != null && result > 0) {
            return entity.getId();
        }
        return result;
    }

    @Override
    public int update(T entity) {
        // 对数据库进行update操作,并返回影响行数。
        // 执行Mapper配置文件中的update方法。
        return sessionTemplate.update(getStatement(SQL_UPDATE), entity);
    }

    @Override
    public int deleteById(long id) {
        // 对数据库进行删除操作。
        // 执行Mapper配置文件中的deleteById方法。
        return sessionTemplate.delete(getStatement(SQL_DELETE_BY_ID), id);
    }

    @Override
    public int deleteByIds(long... ids) {
        return sessionTemplate.delete(getStatement(SQL_DELETE_BY_IDS), ids);
    }

    @Override
    public T findById(long id) {
        // 对数据库进行查询操作。
        // 执行Mapper配置文件中的findById方法。
        return sessionTemplate.selectOne(getStatement(SQL_FIND_BY_ID), id);
    }

    @Override
    public T findByParam(Map param) {
        // 对数据库进行查询操作。
        // 执行Mapper配置文件中的findByParam方法。
        if (param == null || param.isEmpty()) {
            return null;
        }
        return sessionTemplate.selectOne(getStatement(SQL_FIND_BY_PARAM), param);
    }

    @Override
    public List listByParam(Map param) {
        // 对数据库进行查询操作。
        // 执行Mapper配置文件中的findListByParam方法。
        return sessionTemplate.selectList(getStatement(SQL_LIST_BY_PARAM), param);
    }

    @Override
    public PageBean listByPageAndParam(PageParam pageParam, Map param) {
        // 对数据库进行查询操作。
        // 执行Mapper配置文件中的findListByPageAndParam方法。
        HashMap params;
        if (param == null) {
            params = new HashMap<>();
        } else {
            params = (HashMap) param;
        }

        // 获取分页数据集 , 注切勿换成 sessionTemplate 对象。
        // 使用RowBounds进行分页。
        List list = getSqlSession().selectList(getStatement(SQL_LIST_BY_PAGE), params,
                new RowBounds((pageParam.getPageNum() - 1) * pageParam.getNumPerPage(), pageParam.getNumPerPage()));

        // 统计总记录数
        Object countObject = (Object) getSqlSession().selectOne(getStatement(SQL_LIST_BY_PAGE),
                new ExecutorInterceptor.CountParameter(params));
        Long count = Long.valueOf(countObject.toString());

        return new PageBean<>(pageParam.getPageNum(), pageParam.getNumPerPage(), count.intValue(), list);
    }

    @Override
    public PageBean listByPageAndParam(PageParam pageParam, Map param, String sqlId) {
        // 对数据库进行查询操作。
        // 执行Mapper配置文件中的自定义的方法。
        HashMap params;
        if (param == null) {
            params = new HashMap<>();
        } else {
            params = (HashMap) param;
        }

        // 获取分页数据集 , 注切勿换成 sessionTemplate 对象
        List list = getSqlSession().selectList(getStatement(sqlId), params,
                new RowBounds((pageParam.getPageNum() - 1) * pageParam.getNumPerPage(), pageParam.getNumPerPage()));

        // 统计总记录数
        Object countObject = (Object) getSqlSession().selectOne(getStatement(sqlId),
                new ExecutorInterceptor.CountParameter(params));
        Long count = Long.valueOf(countObject.toString());

        return new PageBean<>(pageParam.getPageNum(), pageParam.getNumPerPage(), count.intValue(), list);
    }

    @Override
    public long countByParam(Map param) {
        // 对数据库进行查询操作。
        // 执行Mapper配置文件中的findCountByParam方法。
        return sessionTemplate.selectOne(getStatement(SQL_COUNT_BY_PARAM), param);
    }

    protected String getStatement(String sqlId) {
        String name = this.getClass().getName();
        StringBuilder sb = new StringBuilder();
        sb.append(name).append(".").append(sqlId);
        return sb.toString();
    }

}

用于分页的拦截器类:

package cn.net.bysoft.owl.bookstore.common.core.dao;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.MappedStatement.Builder;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Interceptor;

public abstract class AbstractInterceptor implements Interceptor {

    protected MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource, boolean isCount) {
        Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource,
                ms.getSqlCommandType());
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        String[] s = ms.getKeyProperties();
        if (s == null) {
            builder.keyProperty(null);
        } else {
            builder.keyProperty(s[0]);
        }
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        if (isCount) {
            List resultMaps = new ArrayList<>();
            resultMaps.add(new ResultMap.Builder(ms.getConfiguration(), ms.getId(), Integer.class,
                    new ArrayList()).build());
            builder.resultMaps(resultMaps);
        } else {
            builder.resultMaps(ms.getResultMaps());
        }
        builder.cache(ms.getCache());
        return builder.build();
    }

    public static class BoundSqlSqlSource implements SqlSource {
        BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        @Override
        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }
    }

}
package cn.net.bysoft.owl.bookstore.common.core.dao;

public interface Dialect {

    default boolean supportsLimit() {
        return false;
    }

    default boolean supportsLimitOffset() {
        return supportsLimit();
    }

    default String getLimitString(String sql, int offset, int limit) {
        return getLimitString(sql, offset, Integer.toString(offset), limit, Integer.toString(limit));
    }

    String getLimitString(String sql, int offset, String offsetPlaceholder, int limit, String limitPlaceholder);
    
}
package cn.net.bysoft.owl.bookstore.common.core.dao;

import java.util.Properties;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.log4j.Logger;

@Intercepts({ @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
        RowBounds.class, ResultHandler.class }) })
public class ExecutorInterceptor extends AbstractInterceptor {

    private static final Logger LOGGER = Logger.getLogger(ExecutorInterceptor.class);
    private static final int MAPPED_STATEMENT_INDEX = 0;
    private static final int PARAMETER_INDEX = 1;
    private static final int ROWBOUNDS_INDEX = 2;

    private static final String ORDER_BY = "order by";

    private Dialect dialect;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        processIntercept(invocation.getArgs());
        return invocation.proceed();
    }

    private void processIntercept(final Object[] queryArgs) {
        MappedStatement ms = (MappedStatement) queryArgs[MAPPED_STATEMENT_INDEX];
        Object parameter = queryArgs[PARAMETER_INDEX];
        final RowBounds rowBounds = (RowBounds) queryArgs[ROWBOUNDS_INDEX];
        int offset = rowBounds.getOffset();
        int limit = rowBounds.getLimit();
        // 分页
        if (dialect.supportsLimit() && (offset != RowBounds.NO_ROW_OFFSET || limit != RowBounds.NO_ROW_LIMIT)) {
            BoundSql boundSql = ms.getBoundSql(parameter);

            String sql = boundSql.getSql().replaceAll("\\s{2,}", " ").trim();
            if (dialect.supportsLimitOffset()) {
                sql = dialect.getLimitString(sql, offset, limit);
                offset = RowBounds.NO_ROW_OFFSET;
            } else {
                sql = dialect.getLimitString(sql, 0, limit);
            }

            limit = RowBounds.NO_ROW_LIMIT;

            queryArgs[ROWBOUNDS_INDEX] = new RowBounds(offset, limit);
            BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(),
                    boundSql.getParameterObject());
            MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql), false);
            queryArgs[MAPPED_STATEMENT_INDEX] = newMs;

            LOGGER.debug("==>" + sql);

        } else if (parameter instanceof CountParameter) {
            // 获取总数
            parameter = ((CountParameter) parameter).getParameter();
            BoundSql boundSql = ms.getBoundSql(parameter);

            String sql = boundSql.getSql().replaceAll("\\s{2,}", " ").replace(" FROM", " from")
                    .replace("ORDER BY", ORDER_BY).replace("GROUP BY", ORDER_BY).trim();

            if (sql.split("from").length > 2 || sql.split(ORDER_BY).length > 2 || sql.indexOf(ORDER_BY) > -1) {
                sql = "select count(1) from (" + sql + ") tmp";
            } else {
                int fromIndex = sql.indexOf(" from");
                sql = "select count(1)" + sql.substring(fromIndex);

                int orderByIndex = sql.indexOf(ORDER_BY);
                if (orderByIndex > 0) {
                    sql = sql.substring(0, orderByIndex);
                }
            }

            BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(),
                    boundSql.getParameterObject());
            MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql), true);
            queryArgs[MAPPED_STATEMENT_INDEX] = newMs;
            queryArgs[PARAMETER_INDEX] = parameter;

            LOGGER.debug("==>" + sql);
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        String dialectClass = properties.getProperty("dialectClass");
        try {
            dialect = (Dialect) Class.forName(dialectClass).newInstance();
        } catch (Exception e) {
            throw new RuntimeException("方言加载属性异常");
        }

    }

    public static class CountParameter {
        private Object parameter;

        public CountParameter(Object parameter) {
            this.parameter = parameter;
        }

        public Object getParameter() {
            return parameter;
        }
    }

}
package cn.net.bysoft.owl.bookstore.common.core.dao;

public class MySqlDialect implements Dialect {

    @Override
    public String getLimitString(String sql, int offset, String offsetPlaceholder, int limit, String limitPlaceholder) {
        StringBuilder stringBuilder = new StringBuilder(sql);

        stringBuilder.append(" limit ");
        if (offset > 0) {
            stringBuilder.append(offsetPlaceholder);
            stringBuilder.append(",");
        }
        stringBuilder.append(limitPlaceholder);
        return stringBuilder.toString();
    }
}

最后是Mapper和Mybatis.Config配置文件:





	
		
			email = #{email}
		
	

	
		
		
		
		
	

	
		INSERT INTO obs_user (email, mobile, pwd) VALUES
		(#{email}, #{mobile}, #{password})
	

	

	




	
	
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		  
        
	

Github

https://github.com/XuePeng87/owl-bookstore

转载于:https://my.oschina.net/u/2450666/blog/1489963

你可能感兴趣的:(java,数据库,python)