├── src
└── main
│ ├── webapp
│ ├── index.jsp
│ └── WEB-INF
│ │ └── web.xml
│ ├── java
│ └── com
│ │ └── closer
│ │ ├── tenant
│ │ ├── service
│ │ │ ├── TenantSupport.java
│ │ │ └── TenantService.java
│ │ ├── repository
│ │ │ ├── TenantRepository.java
│ │ │ └── impl
│ │ │ │ └── TenantRepositoryImpl.java
│ │ ├── event
│ │ │ └── TenantCreateEvent.java
│ │ ├── domain
│ │ │ └── Tenant.java
│ │ └── web
│ │ │ └── TenantController.java
│ │ ├── department
│ │ ├── repository
│ │ │ └── DepartmentRepository.java
│ │ ├── service
│ │ │ └── DepartmentService.java
│ │ ├── web
│ │ │ └── DepartmentController.java
│ │ └── domain
│ │ │ └── Department.java
│ │ ├── employee
│ │ ├── repository
│ │ │ └── EmployeeRepository.java
│ │ ├── web
│ │ │ └── EmployeeController.java
│ │ ├── service
│ │ │ └── EmployeeService.java
│ │ ├── domain
│ │ │ └── Employee.java
│ │ └── job
│ │ │ └── HappyBirthdayJob.java
│ │ └── common
│ │ ├── handler
│ │ ├── DynamicRoutingDataSource.java
│ │ ├── TableMapperInterceptor.java
│ │ ├── TableProvider.java
│ │ ├── TenantHandlerInterceptor.java
│ │ ├── TableHandler.java
│ │ └── DistributedIdentifierGenerator.java
│ │ ├── view
│ │ └── View.java
│ │ ├── repository
│ │ ├── BaseRepository.java
│ │ └── BaseTenantRepository.java
│ │ ├── constant
│ │ └── IDG.java
│ │ ├── domain
│ │ ├── BaseTenantDomain.java
│ │ └── BaseDomain.java
│ │ ├── config
│ │ ├── ServiceConfig.java
│ │ ├── WebInitializer.java
│ │ ├── QuartzConfig.java
│ │ ├── WebConfig.java
│ │ ├── RDMSConfig.java
│ │ └── RedisConfig.java
│ │ ├── helper
│ │ └── ContextHelper.java
│ │ └── service
│ │ ├── BaseTenantService.java
│ │ └── BaseService.java
│ ├── resources
│ ├── idg.lua
│ ├── log4j.properties
│ └── quartz.properties
│ └── init-sql
│ ├── hsqldb
│ └── quartz-init.sql
│ └── mysql
│ ├── tables_mysql.sql
│ └── tables_mysql_innodb.sql
├── .gitignore
├── dynamic-table-mapper-postman.json
├── pom.xml
└── README.md
/src/main/webapp/index.jsp:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World!
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/tenant/service/TenantSupport.java:
--------------------------------------------------------------------------------
1 | package com.closer.tenant.service;
2 |
3 | /**
4 | * Created by closer on 2016/1/27.
5 | */
6 | public interface TenantSupport {
7 |
8 | Class[] getEntities();
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/resources/idg.lua:
--------------------------------------------------------------------------------
1 | local sequence = redis.call("INCR", ARGV[1])
2 | local expire = redis.call("TTL", ARGV[1])
3 | if expire == -1 then
4 | redis.call("EXPIRE", ARGV[1], ARGV[2])
5 | expire = ARGV[2]
6 | end
7 |
8 | return expire .. "," .. sequence
--------------------------------------------------------------------------------
/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | Archetype Created Web Application
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # maven ignore
2 | target/
3 | *.jar
4 | *.war
5 | *.zip
6 | *.tar
7 | *.tar.gz
8 |
9 | # eclipse ignore
10 | .settings/
11 | .project
12 | .classpath
13 |
14 | # idea ignore
15 | .idea/
16 | *.ipr
17 | *.iml
18 | *.iws
19 |
20 | # temp ignore
21 | *.log
22 | *.cache
23 | *.diff
24 | *.patch
25 | *.tmp
26 |
27 | # system ignore
28 | .DS_Store
29 | Thumbs.db
30 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/tenant/repository/TenantRepository.java:
--------------------------------------------------------------------------------
1 | package com.closer.tenant.repository;
2 |
3 | import com.closer.common.repository.BaseRepository;
4 | import com.closer.tenant.domain.Tenant;
5 | import org.springframework.stereotype.Repository;
6 |
7 | /**
8 | * Created by closer on 2016/1/27.
9 | */
10 | @Repository
11 | public interface TenantRepository extends BaseRepository {
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/department/repository/DepartmentRepository.java:
--------------------------------------------------------------------------------
1 | package com.closer.department.repository;
2 |
3 | import com.closer.common.repository.BaseTenantRepository;
4 | import com.closer.department.domain.Department;
5 | import org.springframework.stereotype.Repository;
6 |
7 | /**
8 | * Created by closer on 2016/1/20.
9 | */
10 | @Repository
11 | public interface DepartmentRepository extends BaseTenantRepository {
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/employee/repository/EmployeeRepository.java:
--------------------------------------------------------------------------------
1 | package com.closer.employee.repository;
2 |
3 | import com.closer.common.repository.BaseTenantRepository;
4 | import com.closer.employee.domain.Employee;
5 | import org.springframework.stereotype.Repository;
6 |
7 | /**
8 | * 员工Dao
9 | * Created by closer on 2016/1/4.
10 | */
11 | @Repository
12 | public interface EmployeeRepository extends BaseTenantRepository {
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/handler/DynamicRoutingDataSource.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.handler;
2 |
3 | import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
4 |
5 | /**
6 | * Created by closer on 2016/1/27.
7 | */
8 | public class DynamicRoutingDataSource extends AbstractRoutingDataSource{
9 |
10 | @Override
11 | protected Object determineCurrentLookupKey() {
12 | return TableProvider.getDataSoureName();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/tenant/event/TenantCreateEvent.java:
--------------------------------------------------------------------------------
1 | package com.closer.tenant.event;
2 |
3 | import com.closer.tenant.domain.Tenant;
4 |
5 | /**
6 | * 公司新增事件
7 | * Created by closer on 2016/1/5.
8 | */
9 | public class TenantCreateEvent {
10 | private Tenant tenant;
11 |
12 | public TenantCreateEvent(Tenant tenant) {
13 | this.tenant = tenant;
14 | }
15 |
16 | public Tenant getTenant() {
17 | return tenant;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/view/View.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.view;
2 |
3 | /**
4 | * 定义的公共View供@JsonView使用
5 | * Created by closer on 2016/1/24.
6 | */
7 | public class View {
8 |
9 | public interface Detail {
10 | }
11 |
12 | public interface List {
13 | }
14 |
15 | public interface Eager {
16 | }
17 |
18 | public interface EagerDetail extends Eager {
19 | }
20 |
21 | public interface EagerList extends Eager {
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/handler/TableMapperInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.handler;
2 |
3 | import org.hibernate.EmptyInterceptor;
4 |
5 | /**
6 | * 表映射拦截器
7 | * Created by Zhang Jinlong(150429) on 2016/1/4.
8 | */
9 | public class TableMapperInterceptor extends EmptyInterceptor {
10 |
11 | @Override
12 | public String onPrepareStatement(String sql) {
13 | return sql.replace(TableProvider.PREFIX, TableProvider.getTablePrefix());
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/repository/BaseRepository.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.repository;
2 |
3 | import com.closer.common.domain.BaseDomain;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.data.repository.NoRepositoryBean;
6 |
7 | import java.io.Serializable;
8 |
9 | /**
10 | * 基础Repository
11 | * Created by closer on 2016/1/5.
12 | */
13 | @NoRepositoryBean
14 | public interface BaseRepository,I extends Serializable> extends JpaRepository{
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/constant/IDG.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.constant;
2 |
3 | /**
4 | * 主健生成策略
5 | * Created by Zhang Jinlong(150429) on 2016/2/14.
6 | */
7 | public final class IDG {
8 |
9 | public static final String UUID = "uuid2";
10 | public static final String IDENTITY = "identity";
11 | public static final String ASSIGNED = "assigned";
12 | public static final String DISTRIBUTED_IDENTITY = "com.closer.common.handler.DistributedIdentifierGenerator";
13 |
14 | private IDG() {
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/repository/BaseTenantRepository.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.repository;
2 |
3 | import com.closer.common.domain.BaseTenantDomain;
4 | import org.springframework.data.repository.NoRepositoryBean;
5 |
6 | import java.io.Serializable;
7 | import java.util.List;
8 |
9 | /**
10 | * 租户业务基础Dao
11 | * Created by closer on 2016/1/27.
12 | */
13 | @NoRepositoryBean
14 | public interface BaseTenantRepository,I extends Serializable> extends BaseRepository {
15 |
16 | T findByIdAndTenant(I id, long tenant);
17 |
18 | List findByTenant(long tenant);
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/department/service/DepartmentService.java:
--------------------------------------------------------------------------------
1 | package com.closer.department.service;
2 |
3 | import com.closer.common.service.BaseTenantService;
4 | import com.closer.department.domain.Department;
5 | import com.closer.tenant.service.TenantSupport;
6 | import org.springframework.stereotype.Service;
7 |
8 | /**
9 | * Created by closer on 2016/1/20.
10 | */
11 | @Service
12 | public class DepartmentService extends BaseTenantService implements TenantSupport {
13 |
14 |
15 | @Override
16 | public Class[] getEntities() {
17 | return new Class[]{Department.class};
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/domain/BaseTenantDomain.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.domain;
2 |
3 | import javax.persistence.Column;
4 | import javax.persistence.MappedSuperclass;
5 | import java.io.Serializable;
6 |
7 | /**
8 | * Created by closer on 2016/1/27.
9 | */
10 | @MappedSuperclass
11 | public abstract class BaseTenantDomain extends BaseDomain {
12 |
13 | @Column(updatable = false)
14 | private Long tenant;
15 |
16 | public Long getTenant() {
17 | return tenant;
18 | }
19 |
20 | public void setTenant(Long tenant) {
21 | this.tenant = tenant;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, stdout, logfile
2 |
3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
4 | log4j.appender.stdout.Target=System.out
5 | log4j.appender.stdout.Threshold=INFO
6 | log4j.appender.stdout.ImmediateFlush=true
7 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
8 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %X{RequestId} - %m%n
9 |
10 | log4j.appender.logfile=org.apache.log4j.RollingFileAppender
11 | log4j.appender.logfile.File=logs/web.log
12 | #100*1024*1024
13 | log4j.appender.logfile.MaxFileSize=104857600
14 | log4j.appender.logfile.MaxBackupIndex=5
15 | log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
16 | log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/config/ServiceConfig.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.config;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.scheduling.annotation.EnableAsync;
6 | import org.springframework.stereotype.Controller;
7 | import org.springframework.stereotype.Repository;
8 | import org.springframework.web.bind.annotation.ControllerAdvice;
9 |
10 | /**
11 | * Created by closer on 2016/1/3.
12 | */
13 | @Configuration
14 | @EnableAsync(proxyTargetClass = true)
15 | @ComponentScan(basePackages = "com.closer",
16 | excludeFilters = @ComponentScan.Filter({Controller.class, Configuration.class,
17 | Repository.class, ControllerAdvice.class}))
18 | public class ServiceConfig {
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/config/WebInitializer.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.config;
2 |
3 | import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
4 |
5 | /**
6 | * Created by closer on 2016/1/3.
7 | */
8 | public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
9 | @Override
10 | protected Class>[] getRootConfigClasses() {
11 | return null;
12 | }
13 |
14 | @Override
15 | protected Class>[] getServletConfigClasses() {
16 | return new Class>[]{WebConfig.class, ServiceConfig.class, RDMSConfig.class,
17 | RedisConfig.class, QuartzConfig.class};
18 | }
19 |
20 | @Override
21 | protected String[] getServletMappings() {
22 | return new String[]{"/"};
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/helper/ContextHelper.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.helper;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 | import org.springframework.stereotype.Component;
7 |
8 | /**
9 | * Created by closer on 2016/2/4.
10 | */
11 | @Component
12 | public class ContextHelper implements ApplicationContextAware {
13 |
14 | private static ApplicationContext _applicationContext;
15 |
16 | @Override
17 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
18 | _applicationContext = applicationContext;
19 | }
20 |
21 | public static ApplicationContext applicationContext() {
22 | return _applicationContext;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/tenant/service/TenantService.java:
--------------------------------------------------------------------------------
1 | package com.closer.tenant.service;
2 |
3 | import com.closer.common.service.BaseService;
4 | import com.closer.tenant.domain.Tenant;
5 | import com.closer.tenant.event.TenantCreateEvent;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.ApplicationEventPublisher;
8 | import org.springframework.stereotype.Service;
9 |
10 | /**
11 | * Created by closer on 2016/1/27.
12 | */
13 | @Service
14 | public class TenantService extends BaseService {
15 |
16 | @Autowired
17 | private ApplicationEventPublisher publisher;
18 |
19 | @Override
20 | public Tenant add(Tenant tenant) {
21 | super.add(tenant);
22 | publisher.publishEvent(new TenantCreateEvent(tenant));
23 | return tenant;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/resources/quartz.properties:
--------------------------------------------------------------------------------
1 | #调度集群名称,集群需要保持一致
2 | org.quartz.scheduler.instanceName = QuartzScheduler
3 | #实例id,这里使用AUTO表示自动生成
4 | org.quartz.scheduler.instanceId = AUTO
5 |
6 | org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
7 | org.quartz.threadPool.threadCount = 10
8 | org.quartz.threadPool.threadPriority = 5
9 | org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
10 |
11 | org.quartz.jobStore.misfireThreshold = 60000
12 | org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
13 | org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
14 | org.quartz.jobStore.tablePrefix = QRTZ_
15 | org.quartz.jobStore.maxMisfiresToHandleAtATime=10
16 | #是否为集群模式
17 | org.quartz.jobStore.isClustered = true
18 | #心跳检测的频率,频率越小将越早发现集群其它机器失效
19 | org.quartz.jobStore.clusterCheckinInterval = 20000
20 |
21 | #新版本检查
22 | org.quartz.scheduler.skipUpdateCheck:true
--------------------------------------------------------------------------------
/src/main/java/com/closer/tenant/domain/Tenant.java:
--------------------------------------------------------------------------------
1 | package com.closer.tenant.domain;
2 |
3 | import com.closer.common.constant.IDG;
4 | import com.closer.common.domain.BaseDomain;
5 | import org.hibernate.annotations.GenericGenerator;
6 |
7 | import javax.persistence.Entity;
8 | import javax.persistence.Table;
9 |
10 | /**
11 | * Created by closer on 2016/1/27.
12 | */
13 | @Entity
14 | @Table(name = "t_tenant")
15 | @GenericGenerator(name = "id", strategy = IDG.IDENTITY)
16 | public class Tenant extends BaseDomain {
17 |
18 | private String name;
19 |
20 | private String dataSourceName;
21 |
22 | public String getName() {
23 | return name;
24 | }
25 |
26 | public void setName(String name) {
27 | this.name = name;
28 | }
29 |
30 | public String getDataSourceName() {
31 | return dataSourceName;
32 | }
33 |
34 | public void setDataSourceName(String dataSourceName) {
35 | this.dataSourceName = dataSourceName;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/tenant/web/TenantController.java:
--------------------------------------------------------------------------------
1 | package com.closer.tenant.web;
2 |
3 | import com.closer.tenant.domain.Tenant;
4 | import com.closer.tenant.service.TenantService;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.*;
7 |
8 | import java.util.Map;
9 |
10 | /**
11 | * Created by closer on 2016/1/27.
12 | */
13 | @RestController
14 | @RequestMapping("/tenants")
15 | public class TenantController {
16 |
17 | @Autowired
18 | private TenantService tenantService;
19 |
20 | @RequestMapping(method = RequestMethod.POST)
21 | public Tenant add(@RequestBody Tenant tenant) {
22 | return tenantService.add(tenant);
23 | }
24 |
25 | @RequestMapping(value = "/{id}", method = RequestMethod.GET)
26 | public Tenant get(@PathVariable long id) {
27 | return tenantService.findStrictOne(id);
28 | }
29 |
30 | @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
31 | public Tenant add(@PathVariable long id, @RequestBody Map tenantMap) {
32 | return tenantService.update(id, tenantMap);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/service/BaseTenantService.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.service;
2 |
3 | import com.closer.common.domain.BaseTenantDomain;
4 | import com.closer.common.handler.TableProvider;
5 | import com.closer.common.repository.BaseTenantRepository;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 |
8 | import java.io.Serializable;
9 | import java.util.List;
10 |
11 | /**
12 | * Created by closer on 2016/1/27.
13 | */
14 | public abstract class BaseTenantService, I extends Serializable> extends BaseService {
15 |
16 | @Autowired
17 | private BaseTenantRepository baseTenantRepository;
18 |
19 | @Override
20 | public T findOne(I id) {
21 | return baseTenantRepository.findByIdAndTenant(id, TableProvider.getTenantId());
22 | }
23 |
24 | @Override
25 | public List findAll() {
26 | return baseTenantRepository.findByTenant(TableProvider.getTenantId());
27 | }
28 |
29 | @Override
30 | public T add(T t) {
31 | t.setTenant(TableProvider.getTenantId());
32 | return super.add(t);
33 | }
34 |
35 | @Override
36 | public boolean exists(I id) {
37 | return findOne(id) != null;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/employee/web/EmployeeController.java:
--------------------------------------------------------------------------------
1 | package com.closer.employee.web;
2 |
3 | import com.closer.common.view.View;
4 | import com.closer.employee.domain.Employee;
5 | import com.closer.employee.service.EmployeeService;
6 | import com.fasterxml.jackson.annotation.JsonView;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.web.bind.annotation.*;
9 |
10 | import java.util.List;
11 |
12 | /**
13 | * 员工控制器
14 | * Created by closer on 2016/1/4.
15 | */
16 | @RestController
17 | @RequestMapping("/employees")
18 | public class EmployeeController {
19 |
20 | @Autowired
21 | private EmployeeService service;
22 |
23 | @JsonView(View.EagerDetail.class)
24 | @RequestMapping(value = "/{id}",method = RequestMethod.GET)
25 | public Employee get(@PathVariable("id") long id) {
26 | return service.findOne(id);
27 | }
28 |
29 | @JsonView(View.List.class)
30 | @RequestMapping(method = RequestMethod.GET)
31 | public List list() {
32 | return service.findAll();
33 | }
34 |
35 | @RequestMapping(method = RequestMethod.POST)
36 | public Employee add(@RequestBody Employee employee) {
37 | return service.add(employee);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/domain/BaseDomain.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.domain;
2 |
3 | import org.springframework.data.annotation.CreatedDate;
4 | import org.springframework.data.annotation.LastModifiedDate;
5 | import org.springframework.data.jpa.domain.support.AuditingEntityListener;
6 |
7 | import javax.persistence.*;
8 |
9 | /**
10 | * Created by closer on 2016/1/5.
11 | */
12 | @MappedSuperclass
13 | @EntityListeners(AuditingEntityListener.class)
14 | public abstract class BaseDomain {
15 |
16 | @Id
17 | @GeneratedValue(generator = "id")
18 | @Column(length = 36)
19 | private I id;
20 |
21 | @LastModifiedDate
22 | private long updateTime;
23 |
24 | @CreatedDate
25 | @Column(updatable = false)
26 | private long createTime;
27 |
28 | public I getId() {
29 | return id;
30 | }
31 |
32 | public void setId(I id) {
33 | this.id = id;
34 | }
35 |
36 | public long getUpdateTime() {
37 | return updateTime;
38 | }
39 |
40 | public void setUpdateTime(long updateTime) {
41 | this.updateTime = updateTime;
42 | }
43 |
44 | public long getCreateTime() {
45 | return createTime;
46 | }
47 |
48 | public void setCreateTime(long createTime) {
49 | this.createTime = createTime;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/tenant/repository/impl/TenantRepositoryImpl.java:
--------------------------------------------------------------------------------
1 | package com.closer.tenant.repository.impl;
2 |
3 | import com.closer.tenant.domain.Tenant;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.cache.annotation.CacheConfig;
6 | import org.springframework.cache.annotation.CacheEvict;
7 | import org.springframework.cache.annotation.Cacheable;
8 | import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
9 | import org.springframework.stereotype.Repository;
10 |
11 | import javax.persistence.EntityManager;
12 |
13 | /**
14 | * Created by closer on 2016/1/27.
15 | */
16 | @Repository
17 | @CacheConfig(cacheNames = "tenants")
18 | public class TenantRepositoryImpl extends SimpleJpaRepository {
19 |
20 | @Autowired
21 | public TenantRepositoryImpl(EntityManager entityManager) {
22 | super(Tenant.class, entityManager);
23 | }
24 |
25 | @Cacheable
26 | @Override
27 | public Tenant findOne(Long id) {
28 | return super.findOne(id);
29 | }
30 |
31 | @CacheEvict
32 | @Override
33 | public void delete(Long id) {
34 | super.delete(id);
35 | }
36 |
37 | @CacheEvict(key = "#p0.id")
38 | @Override
39 | public Tenant save(Tenant entity) {
40 | return super.save(entity);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/department/web/DepartmentController.java:
--------------------------------------------------------------------------------
1 | package com.closer.department.web;
2 |
3 | import com.closer.department.domain.Department;
4 | import com.closer.department.service.DepartmentService;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.*;
7 |
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | /**
12 | * 部门Controller
13 | * Created by closer on 2016/1/20.
14 | */
15 | @RestController
16 | @RequestMapping("/departments")
17 | public class DepartmentController {
18 |
19 | @Autowired
20 | private DepartmentService service;
21 |
22 | @RequestMapping(value = "/{id}", method = RequestMethod.GET)
23 | public Department get(@PathVariable long id) {
24 | return service.findStrictOne(id);
25 | }
26 |
27 | @RequestMapping(method = RequestMethod.GET)
28 | public List list() {
29 | return service.findAll();
30 | }
31 |
32 | @RequestMapping(method = RequestMethod.POST)
33 | public Department add(@RequestBody Department department) {
34 | return service.add(department);
35 | }
36 |
37 | @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
38 | public Department update(@PathVariable long id,
39 | @RequestBody Map departmentMap) {
40 | return service.update(id, departmentMap);
41 | }
42 |
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/handler/TableProvider.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.handler;
2 |
3 | import com.closer.tenant.domain.Tenant;
4 | import org.apache.commons.lang3.StringUtils;
5 |
6 | /**
7 | * Created by Zhang Jinlong(150429) on 2016/1/4.
8 | */
9 | public class TableProvider {
10 |
11 | private static final String DEFAULT_PREFIX = "default";
12 | public static final String PREFIX = "#org#";
13 | public static final String PREFIX_ = PREFIX + "_";
14 | private static ThreadLocal tenantThreadLocal = new ThreadLocal<>();
15 |
16 | public static void setTenant(Tenant tenant) {
17 | tenantThreadLocal.set(tenant);
18 | }
19 |
20 | public static String getTablePrefix() {
21 | Tenant tenant = tenantThreadLocal.get();
22 | if (tenant == null) {
23 | return "";
24 | }
25 | return StringUtils.defaultString("T"+String.valueOf(getTableNum()), DEFAULT_PREFIX);
26 | }
27 |
28 | public static long getTableNum() {
29 | return getTenantId() & 7;
30 | }
31 |
32 | public static long getTenantId() {
33 | Tenant tenant = tenantThreadLocal.get();
34 | if (tenant == null) {
35 | throw new RuntimeException("未标识您请求的是租户id");
36 | }
37 | return tenant.getId();
38 | }
39 |
40 | public static String getDataSoureName() {
41 | Tenant tenant = tenantThreadLocal.get();
42 | if (tenant == null) {
43 | return "";
44 | }
45 | return tenant.getDataSourceName();
46 | }
47 |
48 | public static void clear() {
49 | tenantThreadLocal.remove();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/department/domain/Department.java:
--------------------------------------------------------------------------------
1 | package com.closer.department.domain;
2 |
3 | import com.closer.common.constant.IDG;
4 | import com.closer.common.domain.BaseTenantDomain;
5 | import com.closer.common.handler.TableProvider;
6 | import com.closer.employee.domain.Employee;
7 | import com.fasterxml.jackson.annotation.JsonIgnore;
8 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
9 | import org.hibernate.annotations.GenericGenerator;
10 |
11 | import javax.persistence.*;
12 | import java.util.List;
13 |
14 | /**
15 | * 部门实体
16 | * Created by closer on 2016/1/20.
17 | */
18 | @Entity
19 | @Table(name = TableProvider.PREFIX_ + "department")
20 | @GenericGenerator(name = "id", strategy = IDG.DISTRIBUTED_IDENTITY)
21 | public class Department extends BaseTenantDomain {
22 |
23 | private String name;
24 |
25 | @JsonIgnore
26 | @OneToMany(mappedBy = "department", cascade = CascadeType.DETACH)
27 | private List employees;
28 |
29 | @OneToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
30 | @JsonIgnoreProperties("department")
31 | private Employee manager;
32 |
33 | public String getName() {
34 | return name;
35 | }
36 |
37 | public void setName(String name) {
38 | this.name = name;
39 | }
40 |
41 | public List getEmployees() {
42 | return employees;
43 | }
44 |
45 | public void setEmployees(List employees) {
46 | this.employees = employees;
47 | }
48 |
49 | public Employee getManager() {
50 | return manager;
51 | }
52 |
53 | public void setManager(Employee manager) {
54 | this.manager = manager;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/employee/service/EmployeeService.java:
--------------------------------------------------------------------------------
1 | package com.closer.employee.service;
2 |
3 | import com.closer.common.service.BaseTenantService;
4 | import com.closer.employee.domain.Employee;
5 | import com.closer.employee.job.HappyBirthdayJob;
6 | import com.closer.tenant.service.TenantSupport;
7 | import org.quartz.Scheduler;
8 | import org.quartz.SchedulerException;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.context.ApplicationEventPublisher;
11 | import org.springframework.stereotype.Service;
12 | import org.springframework.transaction.event.TransactionalEventListener;
13 |
14 | import java.util.Map;
15 |
16 | /**
17 | * 员工Service
18 | * Created by Zhang Jinlong(150429) on 2016/1/4.
19 | */
20 | @Service
21 | public class EmployeeService extends BaseTenantService implements TenantSupport {
22 |
23 | @Autowired
24 | private ApplicationEventPublisher eventPublisher;
25 |
26 | @Autowired
27 | private Scheduler scheduler;
28 |
29 | @Override
30 | public Class[] getEntities() {
31 | return new Class[]{Employee.class};
32 | }
33 |
34 | @Override
35 | public Employee update(Long id, Map map) {
36 | Employee employee = super.update(id, map);
37 | eventPublisher.publishEvent(employee);
38 | return employee;
39 | }
40 |
41 | @Override
42 | public Employee add(Employee employee) {
43 | employee = super.add(employee);
44 | eventPublisher.publishEvent(employee);
45 | return employee;
46 | }
47 |
48 | @TransactionalEventListener
49 | public void handleEmployee(Employee employee) throws SchedulerException {
50 | HappyBirthdayJob.trigger(scheduler, employee);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/config/QuartzConfig.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.config;
2 |
3 | import com.closer.employee.job.HappyBirthdayJob;
4 | import org.quartz.JobDetail;
5 | import org.quartz.Scheduler;
6 | import org.quartz.SchedulerException;
7 | import org.springframework.context.ApplicationContext;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 | import org.springframework.core.io.ClassPathResource;
11 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
12 |
13 | import javax.sql.DataSource;
14 |
15 | import static org.quartz.JobBuilder.newJob;
16 |
17 | /**
18 | * Created by closer on 2016/2/22.
19 | */
20 | @Configuration
21 | public class QuartzConfig {
22 |
23 | public static final String EMPLOYEE_HAPPY_BIRTHDAY = "Employee-HappyBirthdayJob";
24 | public static final String JOB = "Job";
25 |
26 | @Bean
27 | public SchedulerFactoryBean quartzScheduler(DataSource dataSource, ApplicationContext applicationContext) throws Exception {
28 | SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
29 | scheduler.setDataSource(dataSource);
30 | scheduler.setApplicationContext(applicationContext);
31 | scheduler.setConfigLocation(new ClassPathResource("quartz.properties"));
32 | scheduler.afterPropertiesSet();
33 | return scheduler;
34 | }
35 |
36 | @Bean
37 | public JobDetail happyBirthday(Scheduler scheduler) throws SchedulerException {
38 | JobDetail jobDetail = newJob(HappyBirthdayJob.class)
39 | .withIdentity(JOB, EMPLOYEE_HAPPY_BIRTHDAY)
40 | .requestRecovery()
41 | .storeDurably()
42 | .build();
43 | scheduler.addJob(jobDetail, true);
44 | return jobDetail;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/handler/TenantHandlerInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.handler;
2 |
3 | import com.closer.tenant.domain.Tenant;
4 | import com.closer.tenant.service.TenantService;
5 | import org.apache.commons.lang3.StringUtils;
6 | import org.apache.commons.lang3.math.NumberUtils;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.web.servlet.HandlerInterceptor;
9 | import org.springframework.web.servlet.ModelAndView;
10 |
11 | import javax.servlet.http.HttpServletRequest;
12 | import javax.servlet.http.HttpServletResponse;
13 |
14 | /**
15 | * Created by closer on 2016/1/27.
16 | */
17 | public class TenantHandlerInterceptor implements HandlerInterceptor {
18 |
19 | @Autowired
20 | private TenantService tenantService;
21 |
22 | @Override
23 | public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
24 | if (request.getRequestURI().startsWith("/tenants")) {
25 | return true;
26 | }
27 | String tenantIdStr = request.getHeader("tenant");
28 | if (StringUtils.isBlank(tenantIdStr) || !NumberUtils.isNumber(tenantIdStr)) {
29 | throw new RuntimeException("请求头部需要包含有租户的id,类型为整型");
30 | }
31 | long tenantId = NumberUtils.toLong(tenantIdStr);
32 | Tenant tenant = tenantService.findOne(tenantId);
33 | if (tenant == null) {
34 | throw new RuntimeException("指定的租户不存在");
35 | }
36 | TableProvider.setTenant(tenant);
37 | return true;
38 | }
39 |
40 | @Override
41 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
42 |
43 | }
44 |
45 | @Override
46 | public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
47 | TableProvider.clear();
48 | }
49 | }
--------------------------------------------------------------------------------
/src/main/java/com/closer/employee/domain/Employee.java:
--------------------------------------------------------------------------------
1 | package com.closer.employee.domain;
2 |
3 |
4 | import com.closer.common.constant.IDG;
5 | import com.closer.common.domain.BaseTenantDomain;
6 | import com.closer.common.handler.TableProvider;
7 | import com.closer.common.view.View;
8 | import com.closer.department.domain.Department;
9 | import com.fasterxml.jackson.annotation.JsonView;
10 | import org.apache.commons.lang3.time.DateUtils;
11 | import org.hibernate.annotations.GenericGenerator;
12 |
13 | import javax.persistence.*;
14 | import java.util.Calendar;
15 | import java.util.Date;
16 |
17 | /**
18 | * 员工实体
19 | * Created by Zhang Jinlong(150429) on 2016/1/4.
20 | */
21 | @Entity
22 | @Table(name = TableProvider.PREFIX_ + "employee")
23 | @GenericGenerator(name = "id", strategy = IDG.DISTRIBUTED_IDENTITY)
24 | public class Employee extends BaseTenantDomain {
25 |
26 | private String name;
27 |
28 | private String enName;
29 |
30 | private Long birthday;
31 |
32 | @JsonView(View.EagerDetail.class)
33 | @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.DETACH)
34 | private Department department;
35 |
36 | public String getName() {
37 | return name;
38 | }
39 |
40 | public void setName(String name) {
41 | this.name = name;
42 | }
43 |
44 | public String getEnName() {
45 | return enName;
46 | }
47 |
48 | public void setEnName(String enName) {
49 | this.enName = enName;
50 | }
51 |
52 | public Department getDepartment() {
53 | return department;
54 | }
55 |
56 | public void setDepartment(Department department) {
57 | this.department = department;
58 | }
59 |
60 | public Date getBirthday() {
61 | if (birthday == null) {
62 | return null;
63 | }
64 | return new Date(birthday);
65 | }
66 |
67 | public void setBirthday(Date birthday) {
68 | if (birthday == null) {
69 | this.birthday = null;
70 | }
71 | this.birthday = DateUtils.truncate(birthday, Calendar.HOUR).getTime();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/employee/job/HappyBirthdayJob.java:
--------------------------------------------------------------------------------
1 | package com.closer.employee.job;
2 |
3 | import com.closer.common.config.QuartzConfig;
4 | import com.closer.employee.domain.Employee;
5 | import org.quartz.*;
6 |
7 | import java.util.Calendar;
8 | import java.util.Date;
9 |
10 | import static org.quartz.CronScheduleBuilder.cronSchedule;
11 | import static org.quartz.TriggerBuilder.newTrigger;
12 |
13 | /**
14 | * 发送生日福语任务
15 | * Created by closer on 2016/2/23.
16 | */
17 | public class HappyBirthdayJob implements Job {
18 |
19 | public static final String NAME = "Name";
20 |
21 | @Override
22 | public void execute(JobExecutionContext context) throws JobExecutionException {
23 | JobDataMap data = context.getTrigger().getJobDataMap();
24 | String name = (String) data.get(NAME);
25 | System.out.println("--------------------------------");
26 | System.out.println("Happy Birthday to " + name);
27 | System.out.println("--------------------------------");
28 | }
29 |
30 | public static void trigger(Scheduler scheduler, Employee employee) throws SchedulerException {
31 | long id = employee.getId();
32 | String triggerName = String.valueOf(id);
33 | scheduler.unscheduleJob(
34 | TriggerKey.triggerKey(triggerName,
35 | QuartzConfig.EMPLOYEE_HAPPY_BIRTHDAY)
36 | );
37 |
38 | Date birthday = employee.getBirthday();
39 | if (birthday != null) {
40 | Calendar calendar = Calendar.getInstance();
41 | calendar.setTime(birthday);
42 | String cronExpression = String.format("0 10 23 %d %d ?",
43 | calendar.get(Calendar.DATE), calendar.get(Calendar.MONTH)) + 1;
44 | Trigger trigger = newTrigger()
45 | .forJob(QuartzConfig.JOB, QuartzConfig.EMPLOYEE_HAPPY_BIRTHDAY)
46 | .withIdentity(triggerName, QuartzConfig.EMPLOYEE_HAPPY_BIRTHDAY)
47 | .usingJobData(NAME, employee.getName())
48 | .startNow()
49 | .withSchedule(cronSchedule(cronExpression))
50 | .build();
51 | scheduler.scheduleJob(trigger);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/config/WebConfig.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.config;
2 |
3 | import com.closer.common.handler.TenantHandlerInterceptor;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import com.fasterxml.jackson.databind.PropertyNamingStrategy;
6 | import com.fasterxml.jackson.datatype.hibernate4.Hibernate4Module;
7 | import org.hibernate.MappingException;
8 | import org.hibernate.engine.spi.Mapping;
9 | import org.hibernate.id.factory.IdentifierGeneratorFactory;
10 | import org.hibernate.type.Type;
11 | import org.springframework.context.annotation.Bean;
12 | import org.springframework.context.annotation.ComponentScan;
13 | import org.springframework.context.annotation.Configuration;
14 | import org.springframework.http.converter.HttpMessageConverter;
15 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
16 | import org.springframework.stereotype.Controller;
17 | import org.springframework.web.servlet.config.annotation.EnableWebMvc;
18 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
19 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
20 |
21 | import java.util.List;
22 |
23 | /**
24 | * Created by closer on 2016/1/3.
25 | */
26 | @Configuration
27 | @EnableWebMvc
28 | @ComponentScan(value = "com.closer", includeFilters = @ComponentScan.Filter(Controller.class))
29 | public class WebConfig extends WebMvcConfigurerAdapter {
30 |
31 | @Bean
32 | public TenantHandlerInterceptor tenantHandlerInterceptor() {
33 | return new TenantHandlerInterceptor();
34 | }
35 |
36 | @Override
37 | public void addInterceptors(InterceptorRegistry registry) {
38 | registry.addInterceptor(tenantHandlerInterceptor());
39 | super.addInterceptors(registry);
40 | }
41 |
42 | @Override
43 | public void configureMessageConverters(List> converters) {
44 | //Here we add our custom-configured HttpMessageConverter
45 | converters.add(jacksonMessageConverter());
46 | super.configureMessageConverters(converters);
47 | }
48 |
49 | @Bean
50 | public MappingJackson2HttpMessageConverter jacksonMessageConverter() {
51 | MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
52 | messageConverter.setObjectMapper(objectMapper());
53 | return messageConverter;
54 | }
55 |
56 | @Bean
57 | public ObjectMapper objectMapper(){
58 | ObjectMapper mapper = new ObjectMapper();
59 | //Registering Hibernate4Module to support lazy objects
60 | Hibernate4Module module = new Hibernate4Module(mapping());
61 | module.enable(Hibernate4Module.Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS);
62 | mapper.registerModule(module);
63 | mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
64 | return mapper;
65 | }
66 |
67 | @Bean
68 | public Mapping mapping() {
69 | //这里写使用硬编码的方式来获取id字段名,后续如需要再扩展实现
70 | Mapping mapping = new Mapping() {
71 | @Override
72 | public IdentifierGeneratorFactory getIdentifierGeneratorFactory() {
73 | return null;
74 | }
75 |
76 | @Override
77 | public Type getIdentifierType(String className) throws MappingException {
78 | return null;
79 | }
80 |
81 | @Override
82 | public String getIdentifierPropertyName(String className) throws MappingException {
83 | return "id";
84 | }
85 |
86 | @Override
87 | public Type getReferencedPropertyType(String className, String propertyName) throws MappingException {
88 | return null;
89 | }
90 | };
91 |
92 | return mapping;
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/service/BaseService.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.service;
2 |
3 | import com.closer.common.constant.IDG;
4 | import com.closer.common.domain.BaseDomain;
5 | import com.closer.common.repository.BaseRepository;
6 | import com.fasterxml.jackson.databind.ObjectMapper;
7 | import com.google.common.base.CaseFormat;
8 | import com.google.common.base.Converter;
9 | import org.hibernate.annotations.GenericGenerator;
10 | import org.springframework.beans.BeanUtils;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.transaction.annotation.Propagation;
13 | import org.springframework.transaction.annotation.Transactional;
14 |
15 | import java.io.Serializable;
16 | import java.util.List;
17 | import java.util.Map;
18 |
19 | /**
20 | * BaseService
21 | * Created by closer on 2016/1/5.
22 | */
23 | @Transactional
24 | public class BaseService, I extends Serializable> {
25 |
26 | @Autowired
27 | private BaseRepository repository;
28 |
29 | @Autowired
30 | private ObjectMapper objectMapper;
31 |
32 | public static final Converter CONVERTER
33 | = CaseFormat.LOWER_UNDERSCORE.converterTo(CaseFormat.LOWER_CAMEL);
34 |
35 | @Transactional(propagation = Propagation.SUPPORTS)
36 | public T findOne(I id) {
37 | return repository.findOne(id);
38 | }
39 |
40 | @Transactional(propagation = Propagation.SUPPORTS)
41 | public T findStrictOne(I id) {
42 | T t = findOne(id);
43 | if (t == null) {
44 | throw new RuntimeException("未找到指定id的对象");
45 | }
46 | return t;
47 | }
48 |
49 | @Transactional(propagation = Propagation.SUPPORTS)
50 | public List findAll() {
51 | return repository.findAll();
52 | }
53 |
54 | public T add(T t) {
55 | GenericGenerator generator = t.getClass().getAnnotation(GenericGenerator.class);
56 | if (!IDG.ASSIGNED.equals(generator.strategy())) {
57 | t.setId(null);
58 | }
59 | beforeAdd(t);
60 | return repository.save(t);
61 | }
62 |
63 | protected void beforeAdd(T t) {
64 |
65 | }
66 |
67 | /**
68 | * 尽量保护update方法,使得不被滥用,如果仅是修改部分字段时,
69 | * 应该在Service中定义相应的需求方法,底层调用该方法
70 | */
71 | protected T update(T t) {
72 | if (t.getId() == null) {
73 | throw new RuntimeException("主键id不能为空");
74 | }
75 | if (!exists(t.getId())) {
76 | throw new RuntimeException("数据不存在");
77 | }
78 | return repository.save(t);
79 | }
80 |
81 | public T update(I id, Map map) {
82 | T oldDomain = findOne(id);
83 | if (oldDomain == null) {
84 | throw new RuntimeException("找不到相关对象");
85 | }
86 | T newDomain = createDomainFromOldAndMap(oldDomain, map);
87 | beforeUpdate(oldDomain, newDomain);
88 | return update(newDomain);
89 | }
90 |
91 | private T createDomainFromOldAndMap(T oldDomain, Map map) {
92 | int size = map.entrySet().size();
93 | String[] ignoreProperties = new String[size];
94 | int i = 0;
95 | for (Map.Entry entry : map.entrySet()) {
96 | ignoreProperties[i] = CONVERTER.convert(entry.getKey());
97 | i++;
98 | }
99 | T newDomain = (T) objectMapper.convertValue(map, oldDomain.getClass());
100 | BeanUtils.copyProperties(oldDomain, newDomain, ignoreProperties);
101 | return newDomain;
102 | }
103 |
104 | protected void beforeUpdate(T oldDomain, T newDomain) {
105 | }
106 |
107 | public void delete(I id) {
108 | repository.delete(id);
109 | }
110 |
111 | protected void delete(T t) {
112 | beforeDelete(t);
113 | repository.delete(t);
114 | }
115 |
116 | protected void beforeDelete(T t) {
117 | }
118 |
119 | @Transactional(propagation = Propagation.SUPPORTS)
120 | public boolean exists(I id) {
121 | return repository.exists(id);
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/com/closer/common/config/RDMSConfig.java:
--------------------------------------------------------------------------------
1 | package com.closer.common.config;
2 |
3 | import com.closer.common.handler.DynamicRoutingDataSource;
4 | import com.closer.common.handler.TableMapperInterceptor;
5 | import org.hibernate.dialect.Dialect;
6 | import org.hibernate.dialect.HSQLDialect;
7 | import org.hsqldb.jdbc.JDBCDataSource;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.ComponentScan;
10 | import org.springframework.context.annotation.Configuration;
11 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
12 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
13 | import org.springframework.orm.jpa.JpaTransactionManager;
14 | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
15 | import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
16 | import org.springframework.stereotype.Repository;
17 | import org.springframework.transaction.PlatformTransactionManager;
18 | import org.springframework.transaction.annotation.EnableTransactionManagement;
19 |
20 | import javax.persistence.EntityManagerFactory;
21 | import javax.sql.DataSource;
22 | import java.util.HashMap;
23 | import java.util.Map;
24 |
25 | /**
26 | * 关系型数据库配置
27 | * Created by closer on 2016/1/3.
28 | */
29 | @Configuration
30 | @EnableJpaRepositories(value = "com.closer",
31 | includeFilters = {@ComponentScan.Filter(Repository.class)},
32 | enableDefaultTransactions = false)
33 | @EnableTransactionManagement(proxyTargetClass = true)
34 | @EnableJpaAuditing
35 | public class RDMSConfig {
36 |
37 | public static final Dialect DIALECT = new HSQLDialect();
38 | private static final String INTERCEPTOR = TableMapperInterceptor.class.getCanonicalName();
39 |
40 | @Bean
41 | public DataSource dataSource() {
42 | // EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
43 | // return builder.setType(EmbeddedDatabaseType.HSQL).build();
44 | //使用单独的HSQL服务
45 | // java -cp ../hsqldb-2.3.3.jar org.hsqldb.Server -database.0 testdb1 -dbname.0 testdbname1 -database.1 testdb2 -dbname.1 testdbname2
46 | // java -cp ../hsqldb-2.3.3.jar org.hsqldb.util.DatabaseManager -url jdbc:hsqldb:hsql://localhost/testdbname1
47 | JDBCDataSource dataSource1 = new JDBCDataSource();
48 | dataSource1.setUrl("jdbc:hsqldb:hsql://localhost/testdbname1");
49 |
50 | // java -cp ../hsqldb-2.3.3.jar org.hsqldb.util.DatabaseManager -url jdbc:hsqldb:hsql://localhost/testdbname2
51 | JDBCDataSource dataSource2 = new JDBCDataSource();
52 | dataSource2.setUrl("jdbc:hsqldb:hsql://localhost/testdbname2");
53 |
54 | Map