From 6ba32b250553f82522f1df49dd654e10cd6113ca Mon Sep 17 00:00:00 2001 From: Ling Hengqian Date: Mon, 28 Aug 2023 09:56:59 +0800 Subject: [PATCH] Add unit tests for `dynamic-datasource-spring-boot-starter` (#555) --- .github/workflows/ci.yml | 4 +- .../pom.xml | 14 ++- .../fixture/AddRemoveDatasourceTest.java | 71 +++++++++++ .../fixture/LoadDatasourceFromJDBCTest.java | 97 ++++++++++++++ .../fixture/NestDataSourceTest.java | 95 ++++++++++++++ .../dynamic/datasource/fixture/SPELTest.java | 118 ++++++++++++++++++ .../fixture/controller/UserController.java | 46 +++++++ .../fixture/service/nest/SchoolService.java | 37 ++++++ .../fixture/service/nest/Student.java | 27 ++++ .../fixture/service/nest/StudentService.java | 75 +++++++++++ .../fixture/service/nest/Teacher.java | 30 +++++ .../fixture/service/nest/TeacherService.java | 78 ++++++++++++ .../service/spel/CustomResultHandler.java | 13 ++ .../datasource/fixture/service/spel/User.java | 39 ++++++ .../fixture/service/spel/UserService.java | 80 ++++++++++++ .../resources/db/add-remove-datasource.sql | 15 +++ .../db/spring-expression-language.sql | 7 ++ .../pom.xml | 2 - .../fixture/NestDataSourceTest.java | 40 +++--- .../dynamic/datasource/fixture/SPELTest.java | 45 +++---- .../fixture/controller/UserController.java | 8 +- .../fixture/service/nest/SchoolService.java | 1 + .../fixture/service/nest/StudentService.java | 1 + .../fixture/service/nest/TeacherService.java | 1 + pom.xml | 28 +++++ 25 files changed, 910 insertions(+), 62 deletions(-) create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/AddRemoveDatasourceTest.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/LoadDatasourceFromJDBCTest.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/NestDataSourceTest.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/SPELTest.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/controller/UserController.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/SchoolService.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/Student.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/StudentService.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/Teacher.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/TeacherService.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/CustomResultHandler.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/User.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/UserService.java create mode 100644 dynamic-datasource-spring-boot-starter/src/test/resources/db/add-remove-datasource.sql create mode 100644 dynamic-datasource-spring-boot-starter/src/test/resources/db/spring-expression-language.sql diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcae819..967b5a3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,7 +42,7 @@ jobs: cache: 'maven' - name: Build test with Maven run: | - ./mvnw -am -pl dynamic-datasource-spring-boot3-starter -T1C -B clean test + ./mvnw -T1C -B clean test test-minimum-jdk-ci: name: Test CI - JDK ${{ matrix.java-version }} on ${{ matrix.os }} runs-on: ${{ matrix.os }} @@ -64,4 +64,4 @@ jobs: ./mvnw -am -pl dynamic-datasource-creator -T1C -B clean package ./mvnw -am -pl dynamic-datasource-spring -T1C -B clean package ./mvnw -am -pl dynamic-datasource-spring-boot-common -T1C -B clean package - ./mvnw -am -pl dynamic-datasource-spring-boot-starter -T1C -B clean package + ./mvnw -am -pl dynamic-datasource-spring-boot-starter -T1C -B clean test diff --git a/dynamic-datasource-spring-boot-starter/pom.xml b/dynamic-datasource-spring-boot-starter/pom.xml index b04a52f..ca998bf 100644 --- a/dynamic-datasource-spring-boot-starter/pom.xml +++ b/dynamic-datasource-spring-boot-starter/pom.xml @@ -27,7 +27,6 @@ com.alibaba druid-spring-boot-starter - 1.2.18 true @@ -35,6 +34,15 @@ spring-boot-configuration-processor true + + com.h2database + h2 + test + + + org.springframework.boot + spring-boot-starter-test + test + - - \ No newline at end of file + diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/AddRemoveDatasourceTest.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/AddRemoveDatasourceTest.java new file mode 100644 index 0000000..4ee735e --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/AddRemoveDatasourceTest.java @@ -0,0 +1,71 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.creator.hikaricp.HikariCpConfig; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.datasource.SimpleDriverDataSource; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.sql.DataSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@SpringBootTest(classes = AddRemoveDatasourceApplication.class, webEnvironment = RANDOM_PORT) +@RunWith(SpringRunner.class) +public class AddRemoveDatasourceTest { + + @Autowired + DataSource dataSource; + + @Autowired + DefaultDataSourceCreator dataSourceCreator; + + @Test + public void testAddAndRemoveDataSource() { + HikariCpConfig hikariCpConfig = new HikariCpConfig(); + hikariCpConfig.setConnectionTestQuery("select 1"); + DataSourceProperty dataSourceProperty = new DataSourceProperty(); + dataSourceProperty.setHikari(hikariCpConfig); + dataSourceProperty.setPoolName("slave_1"); + dataSourceProperty.setUsername("sa"); + dataSourceProperty.setPassword(""); + dataSourceProperty.setType(SimpleDriverDataSource.class); + dataSourceProperty.setUrl("jdbc:h2:mem:test1;MODE=MySQL"); + dataSourceProperty.setDriverClassName("org.h2.Driver"); + DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; + ds.addDataSource(dataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(dataSourceProperty)); + assertThat(ds.getDataSources().keySet()).contains("slave_1"); + ds.removeDataSource("slave_1"); + assertThat(ds.getDataSources().keySet()).doesNotContain("slave_1"); + } +} + +@SpringBootApplication +class AddRemoveDatasourceApplication { + public static void main(String[] args) { + SpringApplication.run(AddRemoveDatasourceApplication.class, args); + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/LoadDatasourceFromJDBCTest.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/LoadDatasourceFromJDBCTest.java new file mode 100644 index 0000000..e884d28 --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/LoadDatasourceFromJDBCTest.java @@ -0,0 +1,97 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider; +import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Bean; +import org.springframework.jdbc.datasource.SimpleDriverDataSource; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.sql.DataSource; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@SpringBootTest(classes = LoadDatasourceFromJDBCApplication.class, webEnvironment = RANDOM_PORT) +@RunWith(SpringRunner.class) +public class LoadDatasourceFromJDBCTest { + + @Autowired + DataSource dataSource; + + @Test + public void testExistDataSource() { + DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; + assertThat(ds.getDataSources().keySet()).contains("master", "db1", "db2", "db3"); + } +} + +@SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection"}) +@SpringBootApplication +class LoadDatasourceFromJDBCApplication { + + public static void main(String[] args) { + SpringApplication.run(LoadDatasourceFromJDBCApplication.class, args); + } + + @Bean + public DynamicDataSourceProvider dynamicDataSourceProvider(DefaultDataSourceCreator dataSourceCreator) { + return new AbstractJdbcDataSourceProvider(dataSourceCreator, "org.h2.Driver", "jdbc:h2:mem:test;MODE=MySQL", "sa", "") { + @Override + protected Map executeStmt(Statement statement) throws SQLException { + statement.execute("CREATE TABLE IF NOT EXISTS `DB`\n" + + "(\n" + + " `name` VARCHAR(30) NULL DEFAULT NULL,\n" + + " `username` VARCHAR(30) NULL DEFAULT NULL,\n" + + " `password` VARCHAR(30) NULL DEFAULT NULL,\n" + + " `url` VARCHAR(30) NULL DEFAULT NULL,\n" + + " `driver` VARCHAR(30) NULL DEFAULT NULL\n" + + ")"); + statement.executeUpdate("insert into DB values ('master','sa','','jdbc:h2:mem:test;MODE=MySQL','org.h2.Driver')"); + statement.executeUpdate("insert into DB values ('db1','sa','','jdbc:h2:mem:test2','org.h2.Driver')"); + statement.executeUpdate("insert into DB values ('db2','sa','','jdbc:h2:mem:test3','org.h2.Driver')"); + statement.executeUpdate("insert into DB values ('db3','sa','','jdbc:h2:mem:test4','org.h2.Driver')"); + Map map = new HashMap<>(); + ResultSet rs = statement.executeQuery("select * from DB"); + while (rs.next()) { + DataSourceProperty dataSourceProperty = new DataSourceProperty(); + dataSourceProperty.setUsername(rs.getString("username")); + dataSourceProperty.setPassword(rs.getString("password")); + dataSourceProperty.setUrl(rs.getString("url")); + dataSourceProperty.setDriverClassName(rs.getString("driver")); + dataSourceProperty.setType(SimpleDriverDataSource.class); + map.put(rs.getString("name"), dataSourceProperty); + } + return map; + } + }; + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/NestDataSourceTest.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/NestDataSourceTest.java new file mode 100644 index 0000000..64363d0 --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/NestDataSourceTest.java @@ -0,0 +1,95 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.fixture.service.nest.SchoolService; +import com.baomidou.dynamic.datasource.fixture.service.nest.Student; +import com.baomidou.dynamic.datasource.fixture.service.nest.StudentService; +import com.baomidou.dynamic.datasource.fixture.service.nest.Teacher; +import com.baomidou.dynamic.datasource.fixture.service.nest.TeacherService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.sql.DataSource; +import java.util.Arrays; +import java.util.Collections; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; + +@SpringBootTest(classes = NestApplication.class, webEnvironment = RANDOM_PORT) +@RunWith(SpringRunner.class) +public class NestDataSourceTest { + + @Autowired + DataSource dataSource; + + @Autowired + DefaultDataSourceCreator dataSourceCreator; + + @Autowired + TeacherService teacherService; + + @Autowired + StudentService studentService; + + @Autowired + SchoolService schoolService; + + @Test + public void testNest() { + DataSourceProperty masterDataSourceProperty = createDataSourceProperty("master"); + DataSourceProperty teacherDataSourceProperty = createDataSourceProperty("teacher"); + DataSourceProperty studentDataSourceProperty = createDataSourceProperty("student"); + DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; + ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty)); + ds.addDataSource(teacherDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(teacherDataSourceProperty)); + ds.addDataSource(studentDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(studentDataSourceProperty)); + assertThat(ds.getDataSources().keySet()).contains("master", "teacher", "student"); + assertThat(teacherService.addTeacherWithTx("ss", 1)).isEqualTo(1); + assertThat(studentService.addStudentWithTx("tt", 2)).isEqualTo(1); + assertThat(teacherService.selectTeachers()).isEqualTo(Collections.singletonList(new Teacher(1, "tt", 2))); + assertThat(studentService.selectStudents()).isEqualTo(Collections.singletonList(new Student(1, "tt", 2))); + assertThat(schoolService.addTeacherAndStudentWithTx()).isEqualTo(2); + assertThat(teacherService.selectTeachers()).isEqualTo(Arrays.asList(new Teacher(1, "tt", 2), new Teacher(2, "bb", 4))); + assertThat(studentService.selectStudents()).isEqualTo(Arrays.asList(new Student(1, "tt", 2), new Student(2, "bb", 4))); + } + + private DataSourceProperty createDataSourceProperty(String poolName) { + DataSourceProperty result = new DataSourceProperty(); + result.setPoolName(poolName); + result.setDriverClassName("org.h2.Driver"); + result.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'"); + result.setUsername("sa"); + result.setPassword(""); + return result; + } +} + +@SpringBootApplication +class NestApplication { + public static void main(String[] args) { + SpringApplication.run(NestApplication.class, args); + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/SPELTest.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/SPELTest.java new file mode 100644 index 0000000..82b1144 --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/SPELTest.java @@ -0,0 +1,118 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture; + +import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.creator.DataSourceProperty; +import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; +import com.baomidou.dynamic.datasource.fixture.service.spel.CustomResultHandler; +import com.baomidou.dynamic.datasource.fixture.service.spel.User; +import com.baomidou.dynamic.datasource.fixture.service.spel.UserService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.web.context.WebApplicationContext; + +import javax.sql.DataSource; +import java.nio.charset.StandardCharsets; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; + +@SpringBootTest(classes = SPELApplication.class, webEnvironment = RANDOM_PORT) +@RunWith(SpringRunner.class) +public class SPELTest { + + MockMvc mockMvc; + + @Autowired + private WebApplicationContext webApplicationContext; + + @Autowired + DataSource dataSource; + + @Autowired + DefaultDataSourceCreator dataSourceCreator; + + @Autowired + UserService userService; + + @Before + public void setup() { + this.mockMvc = webAppContextSetup(webApplicationContext) + .alwaysDo(new CustomResultHandler()) + .build(); + } + + @Test + public void testSPEL() throws Exception { + DataSourceProperty masterDataSourceProperty = createDataSourceProperty("master"); + DataSourceProperty tenant1_1DataSourceProperty = createDataSourceProperty("tenant1_1"); + DataSourceProperty tenant1_2DataSourceProperty = createDataSourceProperty("tenant1_2"); + DataSourceProperty tenant2_1DataSourceProperty = createDataSourceProperty("tenant2_1"); + DataSourceProperty tenant2_2DataSourceProperty = createDataSourceProperty("tenant2_2"); + DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; + ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty)); + ds.addDataSource(tenant1_1DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant1_1DataSourceProperty)); + ds.addDataSource(tenant1_2DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant1_2DataSourceProperty)); + ds.addDataSource(tenant2_1DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant2_1DataSourceProperty)); + ds.addDataSource(tenant2_2DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant2_2DataSourceProperty)); + assertThat(ds.getDataSources().keySet()).contains("master", "tenant1_1", "tenant1_2", "tenant2_1", "tenant2_2"); + mockMvc.perform(MockMvcRequestBuilders.get("/users/session").characterEncoding(StandardCharsets.UTF_8.name())) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().encoding(StandardCharsets.UTF_8.name())) + .andReturn().getResponse().getContentAsString(); + mockMvc.perform(MockMvcRequestBuilders.get("/users/header").contentType(MediaType.APPLICATION_FORM_URLENCODED) + .header("tenantName", "tenant1") + .characterEncoding(StandardCharsets.UTF_8.name()) + ).andDo(print()) + .andExpect(status().isOk()) + .andExpect(content().encoding(StandardCharsets.UTF_8.name())) + .andReturn().getResponse().getContentAsString(); + assertThat(userService.selectSpelByKey("tenant1")).isEqualTo("tenant1"); + assertThat(userService.selecSpelByTenant(new User("tenant2"))).isEqualTo("tenant2"); + } + + private DataSourceProperty createDataSourceProperty(String poolName) { + DataSourceProperty result = new DataSourceProperty(); + result.setPoolName(poolName); + result.setDriverClassName("org.h2.Driver"); + result.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'"); + result.setUsername("sa"); + result.setPassword(""); + return result; + } +} + +@SpringBootApplication +class SPELApplication { + public static void main(String[] args) { + SpringApplication.run(SPELApplication.class, args); + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/controller/UserController.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/controller/UserController.java new file mode 100644 index 0000000..a5af057 --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/controller/UserController.java @@ -0,0 +1,46 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture.controller; + +import com.baomidou.dynamic.datasource.fixture.service.spel.User; +import com.baomidou.dynamic.datasource.fixture.service.spel.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.util.List; + +@RequestMapping("/users") +@RestController +public class UserController { + + @Autowired + private UserService userService; + + @GetMapping("/session") + public List session(HttpServletRequest request) { + request.getSession().setAttribute("tenantName", "tenant1"); + return userService.selectSpelBySession(); + } + + @GetMapping("/header") + public String header() { + userService.selectSpelByHeader(); + return "success"; + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/SchoolService.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/SchoolService.java new file mode 100644 index 0000000..3608bab --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/SchoolService.java @@ -0,0 +1,37 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture.service.nest; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class SchoolService { + private final TeacherService teacherService; + private final StudentService studentService; + + public SchoolService(TeacherService teacherService, StudentService studentService) { + this.teacherService = teacherService; + this.studentService = studentService; + } + + @Transactional + public int addTeacherAndStudentWithTx() { + int aa = teacherService.addTeacherNoTx("aa", 3); + int bb = studentService.addStudentNoTx("bb", 4); + return aa + bb; + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/Student.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/Student.java new file mode 100644 index 0000000..5a9e20b --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/Student.java @@ -0,0 +1,27 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture.service.nest; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Student { + private Integer id; + private String name; + private Integer age; +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/StudentService.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/StudentService.java new file mode 100644 index 0000000..53c4815 --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/StudentService.java @@ -0,0 +1,75 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture.service.nest; + +import com.baomidou.dynamic.datasource.annotation.DS; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedList; +import java.util.List; + +@SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection"}) +@Service +@DS("student") +public class StudentService { + private final DataSource dataSource; + + public StudentService(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Transactional + public int addStudentWithTx(String name, Integer age) { + try (Connection connection = dataSource.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("insert into student (name,age) values (?,?)")) { + preparedStatement.setString(1, name); + preparedStatement.setInt(2, age); + return preparedStatement.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public int addStudentNoTx(String name, Integer age) { + try (Connection connection = dataSource.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement("insert into student (name,age) values (?,?)")) { + preparedStatement.setString(1, name); + preparedStatement.setInt(2, age); + return preparedStatement.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public List selectStudents() { + List result = new LinkedList<>(); + try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement()) { + ResultSet resultSet = statement.executeQuery("SELECT * FROM student"); + while (resultSet.next()) { + result.add(new Student(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3))); + } + return result; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/Teacher.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/Teacher.java new file mode 100644 index 0000000..ec8b1a7 --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/Teacher.java @@ -0,0 +1,30 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture.service.nest; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class Teacher { + + private Integer id; + + private String name; + + private Integer age; +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/TeacherService.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/TeacherService.java new file mode 100644 index 0000000..dda872f --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/TeacherService.java @@ -0,0 +1,78 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture.service.nest; + +import com.baomidou.dynamic.datasource.annotation.DS; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedList; +import java.util.List; + +@SuppressWarnings({"SqlNoDataSourceInspection", "SqlDialectInspection"}) +@Service +@DS("teacher") +public class TeacherService { + private final DataSource dataSource; + + public TeacherService(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Transactional + public int addTeacherWithTx(String name, Integer age) { + try (Connection connection = dataSource.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name,age) values (?,?)")) { + preparedStatement.setString(1, name); + preparedStatement.setInt(2, age); + return preparedStatement.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + + public int addTeacherNoTx(String name, Integer age) { + try (Connection connection = dataSource.getConnection(); + PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name,age) values (?,?)")) { + preparedStatement.setString(1, name); + preparedStatement.setInt(2, age); + return preparedStatement.executeUpdate(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + public List selectTeachers() { + List result = new LinkedList<>(); + try (Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement()) { + ResultSet resultSet = statement.executeQuery("SELECT * FROM student"); + while (resultSet.next()) { + result.add(new Teacher(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3))); + } + return result; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/CustomResultHandler.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/CustomResultHandler.java new file mode 100644 index 0000000..e707c91 --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/CustomResultHandler.java @@ -0,0 +1,13 @@ +package com.baomidou.dynamic.datasource.fixture.service.spel; + +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.ResultHandler; + +import java.nio.charset.StandardCharsets; + +public class CustomResultHandler implements ResultHandler { + @Override + public void handle(MvcResult result) { + result.getResponse().setCharacterEncoding(StandardCharsets.UTF_8.name()); + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/User.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/User.java new file mode 100644 index 0000000..f42a335 --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/User.java @@ -0,0 +1,39 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture.service.spel; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class User { + + private Integer id; + + private String name; + + private Integer age; + + private String tenantName; + + public User(String tenantName) { + this.id = null; + this.name = null; + this.age = null; + this.tenantName = tenantName; + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/UserService.java b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/UserService.java new file mode 100644 index 0000000..b00d496 --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/spel/UserService.java @@ -0,0 +1,80 @@ +/* + * Copyright © 2018 organization baomidou + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.baomidou.dynamic.datasource.fixture.service.spel; + +import com.baomidou.dynamic.datasource.annotation.DS; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; +import org.springframework.stereotype.Service; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedList; +import java.util.List; + +@SuppressWarnings({"SqlDialectInspection", "SqlNoDataSourceInspection", "UnusedReturnValue", "unused"}) +@Service +@DS("slave") +public class UserService { + + private final DataSource dataSource; + + public UserService(DataSource dataSource) { + this.dataSource = dataSource; + } + + + @DS("#session.tenantName") + public List selectSpelBySession() { + List result = new LinkedList<>(); + try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement()) { + ResultSet resultSet = statement.executeQuery("select * from t_user"); + while (resultSet.next()) { + result.add(new User(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3), resultSet.getString(4))); + } + return result; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @DS("#header.tenantName") + public List selectSpelByHeader() { + List result = new LinkedList<>(); + try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement()) { + ResultSet resultSet = statement.executeQuery("select * from t_user"); + while (resultSet.next()) { + result.add(new User(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3), resultSet.getString(4))); + } + return result; + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @DS("#tenantName") + public String selectSpelByKey(String tenantName) { + return DynamicDataSourceContextHolder.peek(); + + } + + @DS("#user.tenantName") + public String selecSpelByTenant(User user) { + return DynamicDataSourceContextHolder.peek(); + } +} diff --git a/dynamic-datasource-spring-boot-starter/src/test/resources/db/add-remove-datasource.sql b/dynamic-datasource-spring-boot-starter/src/test/resources/db/add-remove-datasource.sql new file mode 100644 index 0000000..97e13ac --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/resources/db/add-remove-datasource.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS TEACHER +( + id BIGINT(20) NOT NULL AUTO_INCREMENT, + name VARCHAR(30) NULL DEFAULT NULL, + age INT(11) NULL DEFAULT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE IF NOT EXISTS STUDENT +( + id BIGINT(20) NOT NULL AUTO_INCREMENT, + name VARCHAR(30) NULL DEFAULT NULL, + age INT(11) NULL DEFAULT NULL, + PRIMARY KEY (id) +); diff --git a/dynamic-datasource-spring-boot-starter/src/test/resources/db/spring-expression-language.sql b/dynamic-datasource-spring-boot-starter/src/test/resources/db/spring-expression-language.sql new file mode 100644 index 0000000..5f426ae --- /dev/null +++ b/dynamic-datasource-spring-boot-starter/src/test/resources/db/spring-expression-language.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS t_user +( + id BIGINT(20) NOT NULL AUTO_INCREMENT, + name VARCHAR(30) NULL DEFAULT NULL, + age INT(11) NULL DEFAULT NULL, + PRIMARY KEY (id) +); diff --git a/dynamic-datasource-spring-boot3-starter/pom.xml b/dynamic-datasource-spring-boot3-starter/pom.xml index 072677c..511d0cf 100644 --- a/dynamic-datasource-spring-boot3-starter/pom.xml +++ b/dynamic-datasource-spring-boot3-starter/pom.xml @@ -33,7 +33,6 @@ com.alibaba druid-spring-boot-3-starter - 1.2.18 true @@ -44,7 +43,6 @@ com.h2database h2 - ${h2.version} test diff --git a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/NestDataSourceTest.java b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/NestDataSourceTest.java index a052ffe..1350ce4 100644 --- a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/NestDataSourceTest.java +++ b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/NestDataSourceTest.java @@ -18,17 +18,18 @@ package com.baomidou.dynamic.datasource.fixture; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.dynamic.datasource.creator.DataSourceProperty; import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator; -import com.baomidou.dynamic.datasource.fixture.service.nest.*; -import org.h2.tools.Server; +import com.baomidou.dynamic.datasource.fixture.service.nest.SchoolService; +import com.baomidou.dynamic.datasource.fixture.service.nest.Student; +import com.baomidou.dynamic.datasource.fixture.service.nest.StudentService; +import com.baomidou.dynamic.datasource.fixture.service.nest.Teacher; +import com.baomidou.dynamic.datasource.fixture.service.nest.TeacherService; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; import javax.sql.DataSource; -import java.sql.SQLException; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -54,24 +55,9 @@ public class NestDataSourceTest { @Test void testNest() { - DataSourceProperty masterDataSourceProperty = new DataSourceProperty(); - masterDataSourceProperty.setPoolName("master"); - masterDataSourceProperty.setDriverClassName("org.h2.Driver"); - masterDataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'"); - masterDataSourceProperty.setUsername("sa"); - masterDataSourceProperty.setPassword(""); - DataSourceProperty teacherDataSourceProperty = new DataSourceProperty(); - teacherDataSourceProperty.setPoolName("teacher"); - teacherDataSourceProperty.setDriverClassName("org.h2.Driver"); - teacherDataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'"); - teacherDataSourceProperty.setUsername("sa"); - teacherDataSourceProperty.setPassword(""); - DataSourceProperty studentDataSourceProperty = new DataSourceProperty(); - studentDataSourceProperty.setPoolName("student"); - studentDataSourceProperty.setDriverClassName("org.h2.Driver"); - studentDataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'"); - studentDataSourceProperty.setUsername("sa"); - studentDataSourceProperty.setPassword(""); + DataSourceProperty masterDataSourceProperty = createDataSourceProperty("master"); + DataSourceProperty teacherDataSourceProperty = createDataSourceProperty("teacher"); + DataSourceProperty studentDataSourceProperty = createDataSourceProperty("student"); DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty)); ds.addDataSource(teacherDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(teacherDataSourceProperty)); @@ -85,6 +71,16 @@ public class NestDataSourceTest { assertThat(teacherService.selectTeachers()).isEqualTo(List.of(new Teacher(1, "tt", 2), new Teacher(2, "bb", 4))); assertThat(studentService.selectStudents()).isEqualTo(List.of(new Student(1, "tt", 2), new Student(2, "bb", 4))); } + + private DataSourceProperty createDataSourceProperty(String poolName) { + DataSourceProperty result = new DataSourceProperty(); + result.setPoolName(poolName); + result.setDriverClassName("org.h2.Driver"); + result.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/add-remove-datasource.sql'"); + result.setUsername("sa"); + result.setPassword(""); + return result; + } } @SpringBootApplication diff --git a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/SPELTest.java b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/SPELTest.java index 490c10a..be067f8 100644 --- a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/SPELTest.java +++ b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/SPELTest.java @@ -63,36 +63,11 @@ public class SPELTest { @Test void testSPEL() { - DataSourceProperty masterDataSourceProperty = new DataSourceProperty(); - masterDataSourceProperty.setPoolName("master"); - masterDataSourceProperty.setDriverClassName("org.h2.Driver"); - masterDataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'"); - masterDataSourceProperty.setUsername("sa"); - masterDataSourceProperty.setPassword(""); - DataSourceProperty tenant1_1DataSourceProperty = new DataSourceProperty(); - tenant1_1DataSourceProperty.setPoolName("tenant1_1"); - tenant1_1DataSourceProperty.setDriverClassName("org.h2.Driver"); - tenant1_1DataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'"); - tenant1_1DataSourceProperty.setUsername("sa"); - tenant1_1DataSourceProperty.setPassword(""); - DataSourceProperty tenant1_2DataSourceProperty = new DataSourceProperty(); - tenant1_2DataSourceProperty.setPoolName("tenant1_2"); - tenant1_2DataSourceProperty.setDriverClassName("org.h2.Driver"); - tenant1_2DataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'"); - tenant1_2DataSourceProperty.setUsername("sa"); - tenant1_2DataSourceProperty.setPassword(""); - DataSourceProperty tenant2_1DataSourceProperty = new DataSourceProperty(); - tenant2_1DataSourceProperty.setPoolName("tenant2_1"); - tenant2_1DataSourceProperty.setDriverClassName("org.h2.Driver"); - tenant2_1DataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'"); - tenant2_1DataSourceProperty.setUsername("sa"); - tenant2_1DataSourceProperty.setPassword(""); - DataSourceProperty tenant2_2DataSourceProperty = new DataSourceProperty(); - tenant2_2DataSourceProperty.setPoolName("tenant2_2"); - tenant2_2DataSourceProperty.setDriverClassName("org.h2.Driver"); - tenant2_2DataSourceProperty.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE"); - tenant2_2DataSourceProperty.setUsername("sa"); - tenant2_2DataSourceProperty.setPassword(""); + DataSourceProperty masterDataSourceProperty = createDataSourceProperty("master"); + DataSourceProperty tenant1_1DataSourceProperty = createDataSourceProperty("tenant1_1"); + DataSourceProperty tenant1_2DataSourceProperty = createDataSourceProperty("tenant1_2"); + DataSourceProperty tenant2_1DataSourceProperty = createDataSourceProperty("tenant2_1"); + DataSourceProperty tenant2_2DataSourceProperty = createDataSourceProperty("tenant2_2"); DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; ds.addDataSource(masterDataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(masterDataSourceProperty)); ds.addDataSource(tenant1_1DataSourceProperty.getPoolName(), dataSourceCreator.createDataSource(tenant1_1DataSourceProperty)); @@ -117,6 +92,16 @@ public class SPELTest { assertThat(userService.selectSpelByKey("tenant1")).isEqualTo("tenant1"); assertThat(userService.selecSpelByTenant(new User("tenant2"))).isEqualTo("tenant2"); } + + private DataSourceProperty createDataSourceProperty(String poolName) { + DataSourceProperty result = new DataSourceProperty(); + result.setPoolName(poolName); + result.setDriverClassName("org.h2.Driver"); + result.setUrl("jdbc:h2:mem:test;MODE=MySQL;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:db/spring-expression-language.sql'"); + result.setUsername("sa"); + result.setPassword(""); + return result; + } } @SpringBootApplication diff --git a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/controller/UserController.java b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/controller/UserController.java index ca87dd6..cf4fe81 100644 --- a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/controller/UserController.java +++ b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/controller/UserController.java @@ -18,7 +18,6 @@ package com.baomidou.dynamic.datasource.fixture.controller; import com.baomidou.dynamic.datasource.fixture.service.spel.User; import com.baomidou.dynamic.datasource.fixture.service.spel.UserService; import jakarta.servlet.http.HttpServletRequest; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -29,8 +28,11 @@ import java.util.List; @RestController public class UserController { - @Autowired - private UserService userService; + private final UserService userService; + + public UserController(UserService userService) { + this.userService = userService; + } @GetMapping("/session") public List session(HttpServletRequest request) { diff --git a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/SchoolService.java b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/SchoolService.java index 3608bab..55c7ea0 100644 --- a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/SchoolService.java +++ b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/SchoolService.java @@ -20,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional; @Service public class SchoolService { + private final TeacherService teacherService; private final StudentService studentService; diff --git a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/StudentService.java b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/StudentService.java index 53c4815..6386a75 100644 --- a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/StudentService.java +++ b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/StudentService.java @@ -32,6 +32,7 @@ import java.util.List; @Service @DS("student") public class StudentService { + private final DataSource dataSource; public StudentService(DataSource dataSource) { diff --git a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/TeacherService.java b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/TeacherService.java index dda872f..bfdc1c4 100644 --- a/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/TeacherService.java +++ b/dynamic-datasource-spring-boot3-starter/src/test/java/com/baomidou/dynamic/datasource/fixture/service/nest/TeacherService.java @@ -32,6 +32,7 @@ import java.util.List; @Service @DS("teacher") public class TeacherService { + private final DataSource dataSource; public TeacherService(DataSource dataSource) { diff --git a/pom.xml b/pom.xml index d588657..fa63d89 100644 --- a/pom.xml +++ b/pom.xml @@ -119,6 +119,16 @@ druid ${druid.version} + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + com.alibaba + druid-spring-boot-3-starter + ${druid.version} + org.springframework.boot spring-boot-starter-jta-atomikos @@ -261,6 +271,24 @@ + + jdk11+ + + [11,) + + + + + + maven-surefire-plugin + + --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED + + + + + + release