mysql, es, mongodb 三个数据源用配置文件方式连接,JPA只是正对dao做了封装,本文主要介绍如何对service层进行封装。
Spring Boot - 多个数据源Service层封装
类关系图
封装的一些配置
application.yml
pom.xml
封装后使用
MySQL 动态数据访问
Mongo 动态数据访问
ElasticSearch 动态数据访问(单个index+type)
ElasticSearch 动态数据访问(多个index+type)
源代码托管
类关系图
对多个数据源连接获取数据进行统一封装
ES spring-data方式不支持多个Index和Type的查找功能,添加了DynamicESDao支持
大大简化封装之后的调用, 调用方式如下

封装的一些配置
application.yml
banner: charset: UTF-8 location: classpath:banner.txt server: port: 5555 contextPath: / session: timeout: 0 spring: application: name: 'spring-boot-datasource-demo' output: ansi: enabled: DETECT messages: basename: i18n/messages thymeleaf: cache: false profiles: active: dev # MySQL data source settings datasource: url: jdbc:mysql://localhost:3306/cdc_standalone?useSSL=false username: root password: bfXa4Pt2lUUScy8jakXf # MySQL JPA settings jpa: generate-ddl: true show-sql: true properties: hibernate: dialect: org.hibernate.dialect.MySQLDialect format_sql: true # NoSQL data source settings data: # MongoDB 2.2+ settings mongodb: uri: mongodb://standalone:fhY1tPt1lpUSbS7jwkTf@10.11.60.4:27017/standalone # ElasticSearch settings elasticsearch: cluster-name: es-logs-01 cluster-nodes: 10.11.60.5:9300
pom.xml
4.0.0spring-boot-datasource-demospring-boot-datasource-demo0.0.1-SNAPSHOTspring-boot-datasource-demospring-boot-datasource-demoorg.springframework.bootspring-boot-starter-parent1.4.1.RELEASEUTF-8UTF-81.83.3.22.7.0org.springframework.bootspring-boot-starterorg.springframework.bootspring-boot-starter-data-mongodborg.springframework.bootspring-boot-starter-data-elasticsearchorg.springframework.bootspring-boot-starter-data-jpamysqlmysql-connector-javaruntimeorg.springframework.bootspring-boot-starter-webio.springfoxspringfox-swagger2${springfox.version}io.springfoxspringfox-swagger-ui${springfox.version}com.alibabafastjson1.2.15org.apache.commonscommons-lang3${commons.lang.version}org.apache.commonscommons-collections44.1com.github.wenhaojpa-spec3.2.3srcmaven-compiler-plugin1.81.8封装后使用
封装之后使用将非常简单,公共的Service行为将被封装处理
MySQL 动态数据访问
通过几行代码即可实现对MySQL的访问,同时支持动态的条件查询;
User
@Entity
@Table(name = "tb_user")
public class User extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 用户id
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false)
private Integer id;
private String userName;
private String nickName;
private String password;
private Integer sex;
private String telephone;
private String email;
private String address;
private Integer deleteStatus;
private Integer locked = 0;
private String description;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
@ManyToMany(cascade = { CascadeType.REFRESH }, fetch = FetchType.LAZY)
@JoinTable(name = "tb_user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = {
@JoinColumn(name = "role_id") })
private java.util.Setroles;
// getter & setter
}Dao
@Repository
public interface IUserDao extends IBaseJpaDao{
}Service
public interface IUserService extends IBaseJpaService{
}
@Service
public class UserServiceImpl extends BaseJpaServiceImplimplements IUserService {
@Autowired
private IUserDao userDao;
@Override
public IBaseJpaDaogetBaseDao() {
return this.userDao;
}
@Override
public void delete(Integer id) {
User user = find(id);
Assert.state(!"admin".equals(user.getUserName()), "超级管理员用户不能删除");
super.delete(id);
}
}Controller
@RestController
@RequestMapping("/admin/user")
public class UserController {
/**
* user service
*/
@Autowired
private IUserService userService;
/**
* @param searchText
* @param user
* @param model
* @return
*/
@GetMapping(value = "/list")
public Listlist(@RequestParam(value = "searchText", required = false, defaultValue="a") String searchText) {
return userService.findAll(Specifications.and().like("userName", "%" + searchText + "%").build());
}
}Mongo 动态数据访问
通过几行代码即可实现对Mongo的访问,同时支持动态的条件查询;
Entity
@Document(collection = "security_alert_rules")
public class EventRule extends BaseEntity {
private static final long serialVersionUID = -2013673868028645757L;
public static final int EVENT_STATUS_ENABLE = 0, EVENT_STATUS_DISABLE = 1;
private String component;
private String name;
private String eventId;
private String ciaLevel;
private String remarks;
private String script;
private long threshold;
private long timeWindow;
private String parseEsResultKeys;
private String nameCN;
private String remarkCN;
private String ruleType;
private String redisEventKey;
private int status = EVENT_STATUS_ENABLE;
// getter & setter
}Dao
@Repository
public interface IEventRuleDao extends IBaseMongoDao{
}Service
public interface IEventRuleService extends IBaseMongoService{
}
@Service
public class EventRuleServiceImpl extends BaseMongoServiceImplimplements IEventRuleService {
@Autowired
IEventRuleDao eventRuleDao;
@Override
public IBaseMongoDaogetBaseDao() {
return eventRuleDao;
}
}Controller
@RestController
@RequestMapping("/admin/eventRule")
public class EventRuleController {
/**
*/
@Autowired
private IEventRuleService eventRuleService;
/**
* @param searchText
* @param user
* @param model
* @return
*/
@GetMapping(value = "/list")
public Listlist(@RequestParam(value = "searchText", required = false) String searchText) {
EventRule param = new EventRule();
param.setName(searchText);
// Examplerule = Example.of(param,
// ExampleMatcher.matching().withMatcher("name", ExampleMatcher.GenericPropertyMatchers.exact()));
Examplerule = Example.of(param, ExampleMatcher.matching().withIgnoreCase("name","nameCN"));
return eventRuleService.findAll(rule);
}
}ElasticSearch 动态数据访问(单个index+type)
通过几行代码即可实现对ElasticSearch的访问,同时支持动态的条件查询;适合数据类型比较固定,且index和type独立的,比如强类型映射的实体类;
Entity
@Document(indexName="syslog", type="logs")
public class SysLog extends BaseEntity {
private static final long serialVersionUID = -4491916941883088972L;
@Id
private String _id;
private SetphyPorts = new LinkedHashSet<>();
private Setports = new LinkedHashSet<>();
private String sensor;
private int vlan;
private Setip = new LinkedHashSet<>();
private Setmac = new LinkedHashSet<>();
private String description;
private String type;
private String vendor;
private long timestamp;
private String name;
private String chassisId;
// getter & setter
}Dao
@Repository
public interface ISysLogDao extends IBaseESDao{
}Service
public interface ILogService extends IBaseESService{
}
@Service
public class LogServiceImpl extends BaseESServiceImplimplements ILogService {
@Autowired
ISysLogDao sysLogDao;
@Override
public IBaseESDaogetBaseDao() {
return sysLogDao;
}
}Controller
@RestController
@RequestMapping("/admin/log")
public class LogController {
/**
* user service
*/
@Autowired
private ILogService logService;
/**
* @param searchText
* @param user
* @param model
* @return
*/
@GetMapping(value = "/list")
public Pagelist(@RequestParam(value = "searchText", required = false) String searchText) {
return logService.search(QueryBuilders.matchQuery("_all", searchText), new PageRequest(0, 100));
}
}ElasticSearch 动态数据访问(多个index+type)
通过几行代码即可实现对ElasticSearch的访问,同时支持动态的条件查询;适合数据类型不固定,且index和type有多个,这些index具备相同结构类型,比如syslog-EVERY-DATE(由于日志量大,将每天的日志单独存放在一个Index中);
Entity
@Document(indexName="syslog", type="logs")
public class SysLog extends BaseEntity {
private static final long serialVersionUID = -4491916941883088972L;
@Id
private String _id;
private SetphyPorts = new LinkedHashSet<>();
private Setports = new LinkedHashSet<>();
private String sensor;
private int vlan;
private Setip = new LinkedHashSet<>();
private Setmac = new LinkedHashSet<>();
private String description;
private String type;
private String vendor;
private long timestamp;
private String name;
private String chassisId;
// getter & setter
}Dao
public interface IDymLogDao extends IDynamicEsDao{
}
@Repository
public class DymLogDaoImpl extends SimpleDynamicEsDaoImplimplements IDymLogDao {
@Autowired
protected ElasticsearchTemplate elasticsearchTemplate;
@Override
public ElasticsearchOperations getElasticsearchOperations() {
return elasticsearchTemplate;
}
}Service
public interface IDymLogService extends IDynamicESService{
}
@Service
public class DymLogServiceImpl extends DynamicESServiceImplimplements IDymLogService {
@Autowired
IDymLogDao sysLogDao;
@Override
public IDynamicEsDaogetBaseDao() {
return sysLogDao;
}
}Controller
@RestController
@RequestMapping("/admin/dymLog")
public class DymLogController {
/**
* logService
*/
@Autowired
private IDymLogService logService;
/**
* @param searchText
* @param user
* @param model
* @return
*/
@GetMapping(value = "/list")
public Pagelist(
@RequestParam(value = "searchText", required = false, defaultValue = "Siemens") String searchText) {
QueryBuilder queryBuilder = QueryBuilders.matchQuery("vendor", searchText);
return logService.search(new NativeSearchQueryBuilder().withIndices("syslog-2018-12-17").withTypes("logs")
.withQuery(queryBuilder).build());
}
}
















