Spring +Mybatis 拦截器配置


mybatis-config.xml


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	
	<settings>
		<!-- changes from the defaults -->
		<setting name="lazyLoadingEnabled" value="false" />
	</settings>
	<typeAliases>
		<typeAlias type="com.anubis.user.bean.User" alias="user"/>
	</typeAliases>
	
	<plugins>
		<!-- com.github.pagehelper为PageHelper类所在包名 -->
		<plugin interceptor="com.anubis.common.PageHelper">
			<property name="dialect" value="mysql" />
			<!-- 该参数默认为false -->
			<!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
			<!-- 和startPage中的pageNum效果一样 -->
			<property name="offsetAsPageNum" value="true" />
			<!-- 该参数默认为false -->
			<!-- 设置为true时,使用RowBounds分页会进行count查询 -->
			<property name="rowBoundsWithCount" value="true" />
		</plugin>
	</plugins>
</configuration>



page


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

import org.apache.ibatis.session.RowBounds;

/**
 * Mybatis - 分页对象
 *
 * @author liuzh/abel533/isea533
 * @version 3.2.1
 * @url http://git.oschina.net/free/Mybatis_PageHelper
 */
public class Page<E> extends ArrayList<E> {
    /**
     * 不进行count查询
     */
    public static final int NO_SQL_COUNT = -1;
    public static final int SQL_COUNT = 0;
    private int pageNum;
    private int pageSize;
    private int startRow;
    private int endRow;
    private long total;
    private int pages;

    public Page(int pageNum, int pageSize) {
        this(pageNum, pageSize, SQL_COUNT);
    }

    public Page(int pageNum, int pageSize, int total) {
        super(pageSize);
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        this.total = total;
        this.startRow = pageNum > 0 ? (pageNum - 1) * pageSize : 0;
        this.endRow = pageNum * pageSize;
    }

    public Page(RowBounds rowBounds, int total) {
        super(rowBounds.getLimit());
        this.pageSize = rowBounds.getLimit();
        this.startRow = rowBounds.getOffset();
        //RowBounds方式默认不求count总数,如果想求count,可以修改这里为SQL_COUNT
        this.total = total;
        this.endRow = this.startRow + this.pageSize;
    }

    public List<E> getResult() {
        return this;
    }

    public int getPages() {
        return pages;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    public int getEndRow() {
        return endRow;
    }

    public void setEndRow(int endRow) {
        this.endRow = endRow;
    }

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getStartRow() {
        return startRow;
    }

    public void setStartRow(int startRow) {
        this.startRow = startRow;
    }

    public long getTotal() {
        return total;
    }

    public void setTotal(long total) {
        this.total = total;
    }

    @Override
    public String toString() {
        return "Page{" +
                "pageNum=" + pageNum +
                ", pageSize=" + pageSize +
                ", startRow=" + startRow +
                ", endRow=" + endRow +
                ", total=" + total +
                ", pages=" + pages +
                '}';
    }
}

import java.util.ArrayList;
import java.util.List;
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.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Interceptor;
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.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;


@Intercepts(@Signature(type = Executor.class, method = "query", args = {
		MappedStatement.class, Object.class, RowBounds.class,
		ResultHandler.class }))
public class PageHelper implements Interceptor {
	private static final ThreadLocal<Page> localPage = new ThreadLocal<Page>();

	private static final List<ResultMapping> EMPTY_RESULTMAPPING = new ArrayList<ResultMapping>(
			0);

	// 数据库方言
	private static String dialect = "";
	// RowBounds参数offset作为PageNum使用 - 默认不使用
	private static boolean offsetAsPageNum = false;
	// RowBounds是否进行count查询 - 默认不查询
	private static boolean rowBoundsWithCount = false;

	/**
	 * 开始分页
	 * 
	 * @param pageNum
	 * @param pageSize
	 */
	public static void startPage(int pageNum, int pageSize) {
		startPage(pageNum, pageSize, true);
	}

	/**
	 * 开始分页
	 * 
	 * @param pageNum
	 * @param pageSize
	 */
	public static void startPage(int pageNum, int pageSize, boolean count) {
		localPage.set(new Page(pageNum, pageSize, count ? Page.SQL_COUNT
				: Page.NO_SQL_COUNT));
	}

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		
		System.out.println("page");
		final Object[] args = invocation.getArgs();
		RowBounds rowBounds = (RowBounds) args[2];
		if (localPage.get() == null && rowBounds == RowBounds.DEFAULT) {
			return invocation.proceed();
		} else {
			// 忽略RowBounds-否则会进行Mybatis自带的内存分页
			args[2] = RowBounds.DEFAULT;
			MappedStatement ms = (MappedStatement) args[0];
			Object parameterObject = args[1];
			BoundSql boundSql = ms.getBoundSql(parameterObject);

			// 分页信息
			Page page = localPage.get();
			// 移除本地变量
			localPage.remove();

			if (page == null) {
				if (offsetAsPageNum) {
					page = new Page(rowBounds.getOffset(),
							rowBounds.getLimit(),
							rowBoundsWithCount ? Page.SQL_COUNT
									: Page.NO_SQL_COUNT);
				} else {
					page = new Page(rowBounds,
							rowBoundsWithCount ? Page.SQL_COUNT
									: Page.NO_SQL_COUNT);
				}
			}
			MappedStatement qs = newMappedStatement(ms, new BoundSqlSqlSource(
					boundSql));
			// 将参数中的MappedStatement替换为新的qs,防止并发异常
			args[0] = qs;
			MetaObject msObject = SystemMetaObject.forObject(qs);
			String sql = (String) msObject.getValue("sqlSource.boundSql.sql");
			// 简单的通过total的值来判断是否进行count查询
			if (page.getTotal() > Page.NO_SQL_COUNT) {
				// 求count - 重写sql
				msObject.setValue("sqlSource.boundSql.sql", getCountSql(sql));
				// 查询总数
				Object result = invocation.proceed();
				int totalCount = (Integer) ((List) result).get(0);
				page.setTotal(totalCount);
				int totalPage = totalCount / page.getPageSize()
						+ ((totalCount % page.getPageSize() == 0) ? 0 : 1);
				page.setPages(totalPage);
				// 分页sql - 重写sql
				msObject.setValue("sqlSource.boundSql.sql",
						getPageSql(sql, page));
				// 恢复类型
				msObject.setValue("resultMaps", ms.getResultMaps());
				// 执行分页查询
				result = invocation.proceed();
				// 得到处理结果
				page.addAll((List) result);
				// 返回结果
				return page;
			} else {
				// 分页sql - 重写sql
				msObject.setValue("sqlSource.boundSql.sql",
						getPageSql(sql, page));
				// 恢复类型
				msObject.setValue("resultMaps", ms.getResultMaps());
				// 执行分页查询
				Object result = invocation.proceed();
				// 得到处理结果
				page.addAll((List) result);
				// 返回结果
				return page;
			}
		}
	}

	/**
	 * 获取总数sql - 如果要支持其他数据库,修改这里就可以
	 * 
	 * @param sql
	 * @return
	 */
	private String getCountSql(String sql) {
		return "select count(0) from (" + sql + ") tmp_count";
	}

	/**
	 * 获取分页sql - 如果要支持其他数据库,修改这里就可以
	 * 
	 * @param sql
	 * @param page
	 * @return
	 */
	private String getPageSql(String sql, Page page) {
		StringBuilder pageSql = new StringBuilder(200);
		if("postgresql".equals(dialect)) {
			pageSql.append(sql);
			pageSql.append(" limit " + page.getPageSize() + " offset "
					+ page.getStartRow());
		} else if ("mysql".equals(dialect)) {
			pageSql.append(sql);
			pageSql.append(" limit " + page.getStartRow() + ","
					+ page.getPageSize());
		} else if ("hsqldb".equals(dialect)) {
			pageSql.append(sql);
			pageSql.append(" LIMIT " + page.getPageSize() + " OFFSET "
					+ page.getStartRow());
		} else if ("oracle".equals(dialect)) {
			pageSql.append("select * from ( select temp.*, rownum row_id from ( ");
			pageSql.append(sql);
			pageSql.append(" ) temp where rownum <= ").append(page.getEndRow());
			pageSql.append(") where row_id > ").append(page.getStartRow());
		}
		return pageSql.toString();
	}

	private class BoundSqlSqlSource implements SqlSource {
		BoundSql boundSql;

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

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

	/**
	 * 由于MappedStatement是一个全局共享的对象,因而需要复制一个对象来进行操作,防止并发访问导致错误
	 * 
	 * @param ms
	 * @param newSqlSource
	 * @return
	 */
	private MappedStatement newMappedStatement(MappedStatement ms,
			SqlSource newSqlSource) {
		MappedStatement.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());
		if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
			StringBuffer keyProperties = new StringBuffer();
			for (String keyProperty : ms.getKeyProperties()) {
				keyProperties.append(keyProperty).append(",");
			}
			keyProperties.delete(keyProperties.length() - 1,
					keyProperties.length());
			builder.keyProperty(keyProperties.toString());
		}
		builder.timeout(ms.getTimeout());
		builder.parameterMap(ms.getParameterMap());
		// 由于resultMaps第一次需要返回int类型的结果,所以这里需要生成一个resultMap - 防止并发错误
		List<ResultMap> resultMaps = new ArrayList<ResultMap>();
		ResultMap resultMap = new ResultMap.Builder(ms.getConfiguration(),
				ms.getId(), int.class, EMPTY_RESULTMAPPING).build();
		resultMaps.add(resultMap);
		builder.resultMaps(resultMaps);
		builder.resultSetType(ms.getResultSetType());
		builder.cache(ms.getCache());
		builder.flushCacheRequired(ms.isFlushCacheRequired());
		builder.useCache(ms.isUseCache());

		return builder.build();
	}

	/**
	 * 只拦截Executor
	 * 
	 * @param target
	 * @return
	 */
	@Override
	public Object plugin(Object target) {
		if (target instanceof Executor) {
			return Plugin.wrap(target, this);
		} else {
			return target;
		}
	}

	public void setProperties(Properties p) {
		dialect = p.getProperty("dialect");
		if (dialect == null || dialect.equals("")) {
			throw new RuntimeException("Mybatis分页插件PageHelper无法获取dialect参数!");
		}
		// offset作为PageNum使用
		String offset = p.getProperty("offsetAsPageNum");
		if (offset != null && offset.toUpperCase().equals("TRUE")) {
			offsetAsPageNum = true;
		}
		// RowBounds方式是否做count查询
		String withcount = p.getProperty("rowBoundsWithCount");
		if (withcount != null && withcount.toUpperCase().equals("TRUE")) {
			rowBoundsWithCount = true;
		}
	}
}



用法:


public String getUserList(HttpServletRequest request) {
		String json = "";
		try {
			String page = request.getParameter("page");
			String rows = request.getParameter("rows");
			
			// 开始分页
			PageHelper.startPage(Integer.parseInt(page), Integer.parseInt(rows));
			
			List<Map<String, Object>> mapList = userDao.getUserList(null);
			
			Map<String, Object> map = new HashMap<String, Object>(); 
			map.put("total", ((Page<Map<String, Object>>)mapList).getTotal());
			map.put("rows", mapList);
			
			json = JSONObject.fromObject(map).toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return json;
	}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源简介:SSM Java 项目集合 一、概述 在这个平台上,我们为大家带来了一系列的 JavaSSM(Spring + SpringMVC + MyBatis)项目。这些项目旨在展示SSM框架在实际应用中的魅力,同时也为开发者提供了一个快速学习和实践的机会。通过下载和使用这些项目,您将能够深入了解SSM框架的核心概念、设计模式和最佳实践。 二、项目特点 实战性强:这些项目均来自实际业务场景多个领域,具有很强的实战性和参考价值。 技术先进:所有项目均采用最新的SSM框架版本,包括SpringSpringMVC 和MyBatis 等,确保技术的先进性和稳定性。 代码规范:项目代码严格按照行业标准和最佳实践进行编写,易于阅读和维护。 文档齐全:每个项目都配备了详细的开发文档和使用说明,方便您快速上手和定制开发。 三、适用人群 Java初学者:通过学习和实践这些项目,您将能够快速掌握SSM框架的基础知识和核心技术。 中高级开发者:这些项目将为您提供丰富的实战经验和灵感,帮助您提升技术水平和解决问题的能力。 项目经理和架构师:这些项目可以作为参考和模板,帮助您更好地规划和设计实际业务场景中的Java项目。 四、下载与使用 下载:所有项目均提供下载,您只需在平台上注册并登录即可获取。 安装与部署:每个项目都提供了详细的安装和部署指南,帮助您快速搭建和运行项目。 定制开发:您可以根据实际需求对项目进行定制开发,扩展功能和优化性能。 五、结语 通过这一系列SSM Java项目的下载和学习,您将能够深入了解SSM框架的核心技术,提升自己的编程能力,并在实际业务场景中灵活应用。我们期待您能够通过这些项目获得更多的成长和进步!
下面是使用 AbstractRoutingDataSource 和 MyBatis 拦截器实现动态切换数据源的示例代码: 首先,需要自定义一个继承 AbstractRoutingDataSource 的类,并实现 determineCurrentLookupKey 方法,该方法用于返回当前数据源的 key: ```java public class DynamicDataSource extends AbstractRoutingDataSource { private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<>(); public static void setDataSourceKey(String key) { dataSourceKey.set(key); } @Override protected Object determineCurrentLookupKey() { return dataSourceKey.get(); } } ``` 在 Spring 配置文件中需要配置两个数据源,并将 DynamicDataSource 设置为默认数据源: ```xml <bean id="dataSource1" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/db1"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> <bean id="dataSource2" class="org.apache.commons.dbcp2.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/db2"/> <property name="username" value="root"/> <property name="password" value="123456"/> </bean> <bean id="dynamicDataSource" class="com.example.DynamicDataSource"> <property name="defaultTargetDataSource" ref="dataSource1"/> <property name="targetDataSources"> <map> <entry key="db1" value-ref="dataSource1"/> <entry key="db2" value-ref="dataSource2"/> </map> </property> </bean> ``` 接下来,需要实现一个继承于 MyBatis 的 Interceptor 接口的拦截器类,该类用于在执行 SQL 语句前切换数据源: ```java @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class DynamicDataSourceInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); MetaObject metaObject = SystemMetaObject.forObject(statementHandler); MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); String dataSourceKey = getDataSourceKey(mappedStatement); if (dataSourceKey != null) { DynamicDataSource.setDataSourceKey(dataSourceKey); } return invocation.proceed(); } private String getDataSourceKey(MappedStatement mappedStatement) { String dataSourceKey = null; // 从 Mapper 方法上获取数据源 key if (mappedStatement != null) { String id = mappedStatement.getId(); if (id.startsWith("com.example.mapper1")) { dataSourceKey = "db1"; } else if (id.startsWith("com.example.mapper2")) { dataSourceKey = "db2"; } } return dataSourceKey; } @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } @Override public void setProperties(Properties properties) { // do nothing } } ``` 最后,需要在 Spring 配置文件中配置拦截器: ```xml <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dynamicDataSource"/> <property name="plugins"> <array> <bean class="com.example.DynamicDataSourceInterceptor"/> </array> </property> </bean> ``` 这样,就可以在 Mapper 方法上使用 @DataSource("db1") 或 @DataSource("db2") 注解来指定使用哪个数据源了。例如: ```java @DataSource("db1") List<User> getUserList(); @DataSource("db2") int addUser(User user); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值