SpringBoot + Mybatis + RESTful(Jersey)
2017-04-14 08:22
609 查看
概述
Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。Spring Boot 内置了大量的常用习惯性的配置,使你无需手动配置,使用 Spring Boot 你可以不用或者只需要很少的配置就可以快速的构建你自己的项目。MyBatis 是时下非常流行的支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
Jersey RESTful 框架是开源的RESTful框架, 实现了 JAX-RS 规范。它扩展了JAX-RS 参考实现, 提供了更多的特性和工具, 可以进一步地简化 RESTful service 和 client 开发。
SpringBoot + Mybatis + RESTful(Jersey, RestEasy)可以说是时下主流的服务端WEB开发的黄金搭配,本文主要介绍如何在生产项目开发中正确的集成 Spring Boot + MyBatis + Jersey。
整合案例介绍
在一些大型的网站或者应用中,数据库服务器单点难以支撑大的访问压力,升级服务器性能成本又太高,所以通用的做法是水平扩展,本案例采用多数据源的配置方式(主从配置)即主库主要用来处理增,删,改操作,从库用来只读操作,也就是常说的读写分离。接下来将主要介绍多数据源的配置以及Mybatis的基本仓储实现,由于篇幅原因这里不一一贴出所有的代码,具体完整案例代码可以看这里https://github.com/AIFEINIK/SpringBoot-Learn/tree/master/spring-boot-mybatis
案例多数据源配置详细解释
1、基本目录如下,datasource包目录下主要存放多数据源的配置类,db根目录下的类主要是Mybatis操作的基本仓储实现。2、DsConfig类是主从库的公共数据库连接配置
public class DsConfig { private String name; // 可以在连接池中同时被分配的有效连接数的最大值,如设置为负数,则不限制 private int maxTotal = 8; // 可以在连接池中保持空闲的最大连接数,超出设置值之外的空闲连接将被回收,如设置为负数,则不限制 private int maxIdle = 8; // 可以在连接池中保持空闲的最小连接数,超出设置值之外的空闲连接将被创建,如设置为0,则不创建 private int minIdle = 0; // 当这个连接池被启动时初始化的创建的连接个数 private int initialSize = 0; // 在连接池返回连接给调用者前用来进行连接校验的查询sql。如果指定,则这个查询必须是一个至少返回一行数据的SQL // SELECT语句。如果没有指定,则连接将通过调用isValid() 方法进行校验。 private String validationQuery; // 指明对象是否需要通过对象驱逐者进行校验(如果有的话),假如一个对象校验失败,则对象将被从连接池中释放。 private boolean testWhileIdle = false; // 指明在从连接池中租借对象时是否要进行校验,如果对象校验失败,则对象将从连接池释放,然后我们将尝试租借另一个 private boolean testOnBorrow = true;// false? // 指明在将对象归还给连接池前是否需要校验。 private boolean testOnReturn = false; // (如果没有可用连接)连接池在抛出异常前等待的一个连接被归还的最大毫秒数,设置为-1则等待时间不确定 private long maxWaitMillis = -1; // 空闲对象驱逐线程运行时的休眠毫秒数,如果设置为非正数,则不运行空闲对象驱逐线程 private long timeBetweenEvictionRunsMillis = -1; // 在每个空闲对象驱逐线程运行过程中中进行检查的对象个数。(如果有的话) private int numTestsPerEvictionRun = 3; // 符合对象驱逐对象驱逐条件的对象在池中最小空闲毫秒总数(如果有的话) private long minEvictableIdleTimeMillis = 1000 * 60 * 30; set{...} get{...} }
3、MasterDsConfig类是主库的连接配置
@Configuration @ConfigurationProperties("datasource.master") public class MasterDsConfig extends DsConfig { //这里可以写master库自己的属性 }
注:@ConfigurationProperties 注解可以用来读取配置文件中的值然后注入到类属性中
4、MasterDataSourceConfig类为主库数据源配置
@Configuration public class MasterDataSourceConfig { @Value("${mybatis.config-location}") private String mybatisConfigLocation; @Autowired private MasterDsConfig config; @Primary @Bean(name = "masterDataSource") @ConfigurationProperties(prefix = "datasource.master") public DataSource masterDataSource() { BasicDataSource ds = (BasicDataSource) DataSourceBuilder.create().type(BasicDataSource.class).build(); ds.setMaxTotal(config.getMaxTotal()); ds.setMaxIdle(config.getMaxIdle()); ds.setMinIdle(config.getMinIdle()); ds.setInitialSize(config.getInitialSize()); ds.setValidationQuery(config.getValidationQuery()); ds.setTestWhileIdle(config.isTestWhileIdle()); ds.setTestOnBorrow(config.isTestOnBorrow()); ds.setTestOnReturn(config.isTestOnReturn()); ds.setMaxWaitMillis(config.getMaxWaitMillis()); // ds.setTimeBetweenEvictionRunsMillis(config.getTimeBetweenEvictionRunsMillis()); // ds.setNumTestsPerEvictionRun(config.getNumTestsPerEvictionRun()); // ds.setMinEvictableIdleTimeMillis(config.getMinEvictableIdleTimeMillis()); ds.setDefaultAutoCommit(false); return ds; } @Bean(name = "masterTransactionManager") public DataSourceTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean(name = "masterSqlSessionFactory") public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception { String path = mybatisConfigLocation.replace("classpath:", "/"); ClassPathResource resource = new ClassPathResource(path); SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setConfigLocation(resource); return factory.getObject(); } @Bean(name = "masterSqlSessionTemplate") public SqlSessionTemplate masterSqlSessionTemplate( @Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception { return new SqlSessionTemplate(sqlSessionFactory); } }
注:1、@Primary 注解表示当有多个相同的Bean时,优先使用该Bean。
2、@ConfigurationProperties 注解到@Bean注解的方法上表示将配置文件中前缀为datasource.master的值注入到该Bean对应的属性字段上。如这里将application.yml配置文件中前缀为datasource.master的值注入到了BasicDataSource实例的对应属性字段中。
从库数据源配置与主库数据源配置基本相同,这里不再介绍。
Mybatis数据库操作的基本仓储实现
1、EntityRepository 仓储访问接口, 提供通用仓储方法public interface EntityRepository<T extends Entity> { // 添加一个实体 public T insert(T t) throws RepositoryException; // gen一个实体 public int update(T t) throws RepositoryException; // 添加一个实体(update and insert) public T save(T t) throws RepositoryException; // 更新一个实体 public int updateSpecify(T t) throws RepositoryException; // 移除一个实体 public int delete(T t) throws RepositoryException; // 根据实体ID,删除实体 public int deleteById(Integer id) throws RepositoryException; // 根据实体ID,查找实体 public T getById(Integer id); // 查询符合查询参数的实体结果集数量 public int findResultCount(QueryParameters param); // 查询符合查询参数的实体结果集 public List<T> findResults(QueryParameters param); }
2、MybatisEntityRepository基于MyBatis的基本仓储实现
public abstract class MybatisEntityRepository<T extends Entity> implements EntityRepository<T> { protected final static Logger logger = LoggerFactory.getLogger(MybatisEntityRepository.class); protected SqlSessionFactory sqlSessionFactory; protected abstract void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory); //自定义Mybatis的sql配置文件中的访问命名空间 protected abstract String nameSpaceForSqlId(); //自定义Mybatis的sql配置文件中的SqlId protected String fullSqlId(String sqlId) { return nameSpaceForSqlId() + "." + sqlId; } @Override public T insert(T t) throws RepositoryException { try (SqlSession session = sqlSessionFactory.openSession()) { session.insert(fullSqlId("insert"), t); session.commit(true); } catch (Exception e) { logger.error("Insert Entity failed: ", e); throw new RepositoryException(e); } return t; } @Override public int update(T t) throws RepositoryException { int ret = 0; try (SqlSession session = sqlSessionFactory.openSession()) { ret = session.update(fullSqlId("update"), t); session.commit(true); } catch (Exception e) { logger.error("Update Entity failed: ", e); throw new RepositoryException(e); } return ret; } @Override public T save(T t) throws RepositoryException { try (SqlSession session = sqlSessionFactory.openSession()) { int ret = 0; if (t.getId() != null) { ret = session.update(fullSqlId("update"), t); } if (ret == 0) { ret = session.insert(fullSqlId("insert"), t); } session.commit(true); } catch (Exception e) { logger.error("Save/Update Entity failed: ", e); throw new RepositoryException(e); } return t; } @Override public int updateSpecify(T t) throws RepositoryException { int count = 0; try (SqlSession session = sqlSessionFactory.openSession()) { count = session.update(fullSqlId("updateSpecify"), t); session.commit(true); } catch (Exception e) { logger.error("UpdateSpecify Entity failed: ", e); throw new RepositoryException(e); } return count; } @Override public int deleteById(Integer id) throws RepositoryException { int count = 0; try (SqlSession session = sqlSessionFactory.openSession()) { count = session.delete(fullSqlId("deleteById"), id); session.commit(true); } catch (Exception e) { logger.error("Remove Entity failed: ", e); throw new RepositoryException(e); } return count; } @Override public int delete(T t) throws RepositoryException { int count = 0; try (SqlSession session = sqlSessionFactory.openSession()) { count = session.delete(fullSqlId("delete"), t); session.commit(true); } catch (Exception e) { logger.error("Remove Entity failed: ", e); throw new RepositoryException(e); } return count; } @Override public T getById(Integer id) { try (SqlSession session = sqlSessionFactory.openSession()) { return session.selectOne(fullSqlId("getById"), id); } } @Override public int findResultCount(QueryParameters params) { if (params == null) { // 纠错 params = new QueryParameters(); } try (SqlSession session = sqlSessionFactory.openSession()) { return session.selectOne(fullSqlId("findResultCount"), params); } } @Override public List<T> findResults(QueryParameters params) { if (params == null) { // 纠错 params = new QueryParameters(); } try (SqlSession session = sqlSessionFactory.openSession()) { return session.selectList(fullSqlId("findResults"), params); } } }
3、MasterMybatisEntityRepository 主库的Mybatis仓储
public abstract class MasterMybatisEntityRepository<T extends Entity> extends MybatisEntityRepository<T> { @Autowired @Qualifier("masterSqlSessionFactory") public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } }
4、SlaveMybatisEntityRepository 从库的Mybatis仓储
public abstract class SlaveMybatisEntityRepository<T extends Entity> extends MybatisEntityRepository<T> { @Autowired @Qualifier("slaveSqlSessionFactory") public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; } }
5、最后就可以编写repo类来通过Myabtis基础仓储访问数据库了
@Repository public class PersonRepo extends MasterMybatisEntityRepository<Person> { @Override protected String nameSpaceForSqlId() { //这里配置的namespace与PersonMapper.xml中的namespace要保持一致 return "com.os.china.mapper.PersonMapper"; } /** * Mybatis基本仓储中没有的可以自己写 * @param userName * @return */ public Person getPersonByName(String userName) { try (SqlSession session = sqlSessionFactory.openSession()) { return session.selectOne(fullSqlId("getPersonByName"), userName); } } }
集成 RESTful 框架 Jersey
1、Maven导入Jersey包<!-- 使用jersey RESTful 框架 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jersey</artifactId> <version>${boot.version}</version> </dependency>
2、编写Jersey配置类
@Configuration public class JerseyConfig extends ResourceConfig { /** * 扫描com.os.china包,使其识别JAX-RS注解 */ public JerseyConfig() { packages("com.os.china"); } }
RESTful风格的资源请求处理类编写
@Component @Path("personMgr") public class PersonMgrResource { @Autowired private PersonService personService; @GET @Path("getPersonById") @Produces(MediaType.APPLICATION_JSON) public JsonResp getPersonById(@QueryParam("id") Integer id) { Person person = personService.getPersonById(id); return JsonResp.success(person); } @GET @Path("getPersonByName") @Produces(MediaType.APPLICATION_JSON) public JsonResp getPersonByName(@QueryParam("userName") String userName) { Person person = personService.getPersonByName(userName); return JsonResp.success(person); } /** * 分页查询用户信息 * @param req 封装分页参数 * @return */ @POST @Path("getPersons") @Produces(MediaType.APPLICATION_JSON) public PageResp getAllPersons(@Valid PageReq req) { QueryParameters params = new QueryParameters(req); int total = personService.getPersonCount(params); if (total == 0) { return PageResp.emptyResult(); } PageInfo page = new PageInfo(req.getPage(), req.getCount(), total); params.setPage(page); List<Person> persons = personService.getPersons(params); return PageResp.success(total, persons); } }
测试
在浏览器中使用postman插件来测试总结
本文主要介绍了 SpringBoot 集成 Mybatis 多数据源的配置,以及如何集成 RESTful 框架 Jersey,最后通过简单测试来验证整个流程是否流转成功,完整代码可在GitHub中查看,如有任何疑问,请赐教!相关文章推荐
- SpringBoot + Mybatis + RESTful(Jersey)
- 整合springboot-mybatis提供RESTful风格SaaS服务
- 使用spring boot+mybatis+mysql 构建RESTful Service
- Springboot + Mybatis (注解+动态Sql)+RESTFUL+thymeleaf
- SpringBoot+JWT+Shiro+MybatisPlus实现Restful快速开发后端脚手架
- 使用SpringBoot整合Jersey 实现Restful webservice.可以同时使用springmvc。
- Spring Boot+Jersey+Mybatis打包
- idea+spring boot+mybatis+restful风格的demo
- 使用Jersey客户端请求Spring Boot(RESTFul)服务
- jersey+spring+mybatis,使用jetty容器,druid连接池,构建restful风格项目
- Spring boot整合mybatis实现Restful服务demo
- 企业分布式微服务云架构技术分享 Spring Cloud + Spring Boot + Mybatis + shiro + RestFul + 微服务
- Spring Boot、Mybatis框架整合开发Java RESTful Web Service
- Spring Cloud Spring Boot mybatis分布式微服务云架构(五)构建RESTful API
- SpringCloud SpringBoot mybatis 分布式微服务(三)Spring Boot构建RESTful API与单元测试
- 详解如何使用Jersey客户端请求Spring Boot(RESTFul)服务
- spring(spring-boot) + mybatis多数据源
- springboot与mybatis整合操作数据库
- 企业分布式微服务云SpringCloud SpringBoot mybatis (十四)Spring Boot中使用MyBatis注解配置详解