2021/07/26 SpringBoot2 data access quick start

Posted by FredFredrickson2 on Wed, 12 Jan 2022 08:04:36 +0100

  • Environment: JDK13, IDEA, springboot2 5.3,maven3. eight point one

catalogue

1, Automatic configuration of data sources

1. Import jdbc scene

Analysis auto configuration

2. Using Druid data sources

Configure the Druid data source in custom mode

Configure Druid data source monitoring page function

Configure the Druid data source in the official starter mode [recommended]

First introduce the starter

Analysis auto configuration

Configuration example

2, Integrate Mybatis operations

1. Configuration mode

2. Mixed mode

3, Junit5

1. JUnit 5 changes

2. Common notes

3. assertions

① Simple assertion

②. Array assertion

③ Combination assertion

④ . exception assertion

⑤ . timeout assertion

⑥ . quick failure

4. Preconditions

5. Nested test

6. Parametric test

1, Automatic configuration of data sources

1. Import jdbc scene

Import initiator

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>

In addition, you should import the database driver according to the database type you use. This article uses the MySQL 8 version database without selecting the version. springboot has version arbitration for this

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

Analysis auto configuration

1. Automatically configured classes

  • DataSourceAutoConfiguration: automatic configuration of data sources
  • Modify the configuration related to the data source: spring datasource
  • The configuration of database connection pool is automatically configured only when there is no DataSource in its own container
  • The bottom configured connection pool is HikariDataSource
	@Configuration(proxyBeanMethods = false)
	@Conditional(PooledDataSourceCondition.class)
	@ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
	@Import({ DataSourceConfiguration.Hikari.class, DataSourceConfiguration.Tomcat.class,
			DataSourceConfiguration.Dbcp2.class, DataSourceConfiguration.OracleUcp.class,
			DataSourceConfiguration.Generic.class, DataSourceJmxConfiguration.class })
	protected static class PooledDataSourceConfiguration

  • DataSourceTransactionManagerAutoConfiguration: automatic configuration of the transaction manager
  • JdbcTemplateAutoConfiguration: the automatic configuration of JdbcTemplate, which can be used to crud the database
  • You can modify the configuration item @ ConfigurationProperties(prefix = "spring.jdbc") to modify the JdbcTemplate
  • @ Bean@Primary JdbcTemplate; There is this component in the container
  • JndiDataSourceAutoConfiguration: automatic configuration of jndi
  • XADataSourceAutoConfiguration: distributed transaction related

Test:

@Slf4j
@SpringBootTest
class Boot05WebAdminApplicationTests {

    @Autowired
    JdbcTemplate jdbcTemplate;


    @Test
    void contextLoads() {

//        jdbcTemplate.queryForObject("select * from account_tbl")
//        jdbcTemplate.queryForList("select * from account_tbl",)
        Long aLong = jdbcTemplate.queryForObject("select count(*) from account_tbl", Long.class);
        log.info("Total records:{}",aLong);
    }

}

2. Using Druid data sources

Configure the Druid data source in custom mode

1. Create a configuration file class and introduce application Configuration of database information in yaml file

@Configuration
public class MyDataSource {

    /**
     * Configure Druid data sources
     * @return
     */
    @ConfigurationProperties("spring.datasource")
    @Bean
    public DataSource dataSource() throws SQLException {
        DruidDataSource druidDataSource = new DruidDataSource();
        //Turn on the monitoring function of the monitoring page
        druidDataSource.setFilters("stat");
        return druidDataSource;
    }
}

2. Testing

package com.young;

import com.alibaba.druid.pool.DruidDataSource;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@SpringBootTest
@Slf4j
class BootWeb05ApplicationTests {
//    @Autowired
//    JdbcTemplate jdbcTemplate;
    @Autowired
    DataSource dataSource;
    @Test
    void contextLoads() {
        log.info("The data source is====>"+dataSource.getClass());
    }

}

result

Configure Druid data source monitoring page function

Note: when using the monitoring page, if you want to use the monitoring function, you need to turn on the monitoring function when configuring the data source

    /**
     * Configure monitoring page function
     * @return
     */
    @Bean
    public ServletRegistrationBean<StatViewServlet> statViewServlet(){
        StatViewServlet statViewServlet = new StatViewServlet();
        return new ServletRegistrationBean<StatViewServlet>(statViewServlet,"/druid/*");
    }

Configure the Druid data source in the official starter mode [recommended]

First introduce the starter

<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.3</version>
</dependency>
 

Analysis auto configuration

  • Extension configuration item spring datasource. druid
  • DruidSpringAopConfiguration.class to monitor the of SpringBean; Configuration item: spring datasource. druid. aop-patterns
  • DruidStatViewServletConfiguration.class, monitoring page configuration: spring datasource. druid. stat-view-servlet; Default on
  • DruidWebStatFilterConfiguration.class, web monitoring configuration; spring.datasource.druid.web-stat-filter; Default on
  • DruidFilterConfiguration.class}) configuration of all Druid filter s
    private static final String FILTER_STAT_PREFIX = "spring.datasource.druid.filter.stat";
    private static final String FILTER_CONFIG_PREFIX = "spring.datasource.druid.filter.config";
    private static final String FILTER_ENCODING_PREFIX = "spring.datasource.druid.filter.encoding";
    private static final String FILTER_SLF4J_PREFIX = "spring.datasource.druid.filter.slf4j";
    private static final String FILTER_LOG4J_PREFIX = "spring.datasource.druid.filter.log4j";
    private static final String FILTER_LOG4J2_PREFIX = "spring.datasource.druid.filter.log4j2";
    private static final String FILTER_COMMONS_LOG_PREFIX = "spring.datasource.druid.filter.commons-log";
    private static final String FILTER_WALL_PREFIX = "spring.datasource.druid.filter.wall";

Configuration example

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/db_account
    username: root
    password: 123456
    driver-class-name: com.mysql.jdbc.Driver

    druid:
      aop-patterns: com.atguigu.admin.*  #Monitoring springbeans
      filters: stat,wall     # Bottom open function, stat (sql monitoring), wall (firewall)

      stat-view-servlet:   # Configure monitoring page function
        enabled: true
        login-username: admin
        login-password: admin
        resetEnable: false

      web-stat-filter:  # Monitoring web
        enabled: true
        urlPattern: /*
        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'


      filter:
        stat:    # Detailed configuration of stat in the above filters
          slow-sql-millis: 1000
          logSlowSql: true
          enabled: true
        wall:
          enabled: true
          config:
            drop-table-allow: false

2, Integrate Mybatis operations

Export dependency

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

1. Configuration mode

  • Global profile
  • SqlSessionFactory: Auto configured
  • SqlSession: SqlSessionTemplate is automatically configured and SqlSession is combined
  • @Import(AutoConfiguredMapperScannerRegistrar.class);
  • Mapper: as long as the interface of MyBatis is marked with @ mapper, it will be automatically scanned
@EnableConfigurationProperties(MybatisProperties.class) :  MyBatis Configuration item binding class.
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class })
public class MybatisAutoConfiguration{}

@ConfigurationProperties(prefix = "mybatis")
public class MybatisProperties

You can modify all the settings in the configuration file that start with mybatis;

# Configure mybatis rules
mybatis:
  config-location: classpath:mybatis/mybatis-config.xml  #Global profile location
  mapper-locations: classpath:mybatis/mapper/*.xml  #sql mapping file location
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.young.mapper.StudentMapper">
    <select id="queryUsers" resultType="student">
        select * from student
    </select>
</mapper>

Instead of using the mybatis configuration file, you can configure it all in the yaml file

mybatis:
#  config-location: classpath:mybatis/mybatis-config.xml  #Global profile location
  mapper-locations: classpath:mybatis/mapper/*.xml  #sql mapping file location
  configuration:
    map-underscore-to-camel-case: true  #Map underscores to hump naming
  type-aliases-package: com.young      #Yes, com Open the alias of the class under the young package

This method needs to disable the location of the global configuration file

2. Mixed mode

@Mapper
public interface CityMapper {

    @Select("select * from city where id=#{id}")
    public City getById(Long id);

    public void insert(City city);

}

Best practice:

  • Introducing mybatis starter
  • Configure application In yaml, specify the mapper location
  • Write Mapper interface and annotate @ Mapper annotation
  • Simple method direct annotation method
  • Write mapper with complex method XML binding mapping
  • @MapperScan("com.atguigu.admin.mapper") is simplified, and other interfaces do not need to be annotated with @ mapper annotation

3, Junit5

1. JUnit 5 changes

Spring boot version 2.2.0 began to introduce JUnit 5 as the default library for unit testing

As the latest version of JUnit framework, JUnit 5 is very different from the previous version of JUnit framework. It consists of several different modules of three different subprojects.

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

JUnit Platform: Junit Platform is the basis for starting the test framework on the JVM. It supports not only Junit's self-made test engine, but also other test engines.

JUnit Jupiter: JUnit Jupiter provides a new programming model of JUnit 5 and is the core of JUnit 5's new features. A test engine is included internally to run on the Junit Platform.

JUnit Vintage: since JUint has developed for many years, in order to take care of old projects, JUnit Vintage provides JUnit 4.0 compatible services x,Junit3. X test engine.

be careful:

Springboot versions above 2.4 remove the default dependency on Vintage. If you need to be compatible with junit4, you need to introduce it yourself (you can't use the function @ Test of junit4)

JUnit 5's vintage engine removed from spring boot starter test. If you need to continue to be compatible with junit4, you need to introduce vintage by yourself

<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

2. Common notes

junit user manual https://junit.org/junit5/docs/current/user-guide/

  • @Test: indicates that the method is a test method. However, unlike JUnit4's @ test, it has a very single responsibility and cannot declare any attributes. Jupiter will provide additional tests for expanded tests
  • @ParameterizedTest: indicates that the method is parameterized test, which will be described in detail below
  • @RepeatedTest: indicates that the method can be executed repeatedly, which will be described in detail below
    @DisplayName("test@RepeatedTest")
    @RepeatedTest(5)
    @Test
    public void RepeatedTest(){
        System.out.println("666");
    }

  • @DisplayName: set the display name for the test class or test method
  • @DisplayName("junit5 Functional test class")
    public class Junit5Test {
    
        @DisplayName("test@DisplayName annotation")
        @Test
        public void testDisplayName(){
            System.out.println("1");
        }
    }

  • @Before each: indicates to execute before each unit test

    @BeforeEach
    void beforeEach(){
        System.out.println("beforeEach It's running...");
    }

  • @After each: means to execute after each unit test

Use the same method as @ BeforeEach

  • @Before all: indicates to execute before all unit tests
  • @After all: means to execute after all unit tests

Integration test for @ BeforeEach @AfterEach @BeforeAll @AfterAll

        

package com.young;

import org.junit.jupiter.api.*;

@DisplayName("junit5 Functional test class")
public class Junit5Test {

    @DisplayName("test@DisplayName Note 1")
    @Test
    public void testDisplayName(){
        System.out.println("1");
    }
    @DisplayName("test@DisplayName Note 2")
    @Test
    public void testDisplayName1(){
        System.out.println("2");
    }

    @BeforeEach
    void beforeEach(){
        System.out.println("beforeEach It's running...");
    }

    @AfterEach
    void afterEach(){
        System.out.println("afterEach It's running...");
    }

    @BeforeAll
    static void beforeAll(){
        System.out.println("All methods are about to start running...");
    }

    @AfterAll
    static void AfterAll(){
        System.out.println("All the methods are over...");
    }


}

  • @Tag: indicates the unit test category, similar to @ Categories in JUnit4
  • @Disabled: indicates that the test class or test method is not executed, similar to @ Ignore in JUnit 4
  • @Timeout: indicates that the test method will return an error if it exceeds the specified time
  • @ExtendWith: provides an extension class reference for a test class or test method
  • @SpringBootTest: after marking on the test class, the test class can use the Spring container function
import org.junit.jupiter.api.Test; //Note that the Test annotation of jupiter is used here!!

3. assertions

Assertions are the core part of the test method, which is used to verify the conditions that the test needs to meet. These assertion methods are org junit. jupiter. api. Static method for assertions. The built-in assertions in JUnit 5 can be divided into the following categories:

Check whether the data returned by the business logic is reasonable.

After all test runs are completed, there will be a detailed test report;

① Simple assertion

Used for simple validation of a single value. For example:

method

explain

assertEquals

Determines whether two objects or two primitive types are equal

assertNotEquals

Determines whether two objects or two primitive types are not equal

assertSame

Judge whether two object references point to the same object

assertNotSame

Judge whether two object references point to different objects

assertTrue

Determines whether the given Boolean value is true

assertFalse

Determines whether the given Boolean value is false

assertNull

Determines whether the given object reference is null

assertNotNull

Determines whether the given object reference is not null

Test simply as follows:

    @Test
    @DisplayName("Test simple assertions")
    public void testAssert(){
        int cal = cal(2, 3);
        assertEquals(6,cal,"The calculation is wrong...");
    }

    int cal(int i,int j){
        return i + j;
    }

②. Array assertion

Use the assertArrayEquals method to determine whether two objects or arrays of the original type are equal

@Test
@DisplayName("array assertion")
public void array() {
 assertArrayEquals(new int[]{1, 2}, new int[] {1, 2});
}

③ Combination assertion

The assertAll method accepts multiple org junit. jupiter. api. As the assertions to be verified, the instance of the executable functional interface can easily provide these assertions through lambda expressions

@Test
@DisplayName("assert all")
public void all() {
 assertAll("Math",
    () -> assertEquals(2, 1 + 1),
    () -> assertTrue(1 > 0)
 );
}

④ . exception assertion

In JUnit 4, when you want to test the exception of a method, the ExpectedException variable annotated with @ Rule is still troublesome. JUnit 5 provides a new assertion method, assertions Assertthrows() can be used in conjunction with functional programming.

@Test
@DisplayName("Abnormal test")
public void exceptionTest() {
    ArithmeticException exception = Assertions.assertThrows(
           //Throw assertion exception
            ArithmeticException.class, () -> System.out.println(1 % 0));

}

⑤ . timeout assertion

Junit5 also provides assertions Asserttimeout() sets a timeout for the test method

@Test
@DisplayName("Timeout tests ")
public void timeoutTest() {
    //If the test method takes more than 1s, it will be abnormal
    Assertions.assertTimeout(Duration.ofMillis(1000), () -> Thread.sleep(500));
}

⑥ . quick failure

Make the test fail directly through the fail method

@Test
@DisplayName("fail")
public void shouldFail() {
 fail("This should fail");
}

4. Preconditions

Preconditions in JUnit 5 are similar to assertions. The difference is that unsatisfied assertions will fail the test method, while unsatisfied preconditions will only terminate the execution of the test method. Preconditions can be regarded as the premise of test method execution. When the premise is not met, there is no need to continue execution.

@DisplayName("Preconditions")
public class AssumptionsTest {
 private final String environment = "DEV";
 
 @Test
 @DisplayName("simple")
 public void simpleAssume() {
    assumeTrue(Objects.equals(this.environment, "DEV"));
    assumeFalse(() -> Objects.equals(this.environment, "PROD"));
 }
 
 @Test
 @DisplayName("assume then do")
 public void assumeThenDo() {
    assumingThat(
       Objects.equals(this.environment, "DEV"),
       () -> System.out.println("In DEV")
    );
 }
}

assumeTrue and assumFalse ensure that the given condition is true or false. If the condition is not met, the test execution will be terminated. The parameter assemingthat is the Boolean value representing the condition and the implementation object of the corresponding Executable interface. The Executable object will be executed only when the conditions are met; When the conditions are not met, the test execution does not terminate.

5. Nested test

JUnit 5 can implement Nested tests through internal classes and @ Nested annotations in Java, so as to better organize relevant test methods together. You can use @ BeforeEach and @ AfterEach annotations in internal classes, and there is no limit to the nesting level.

@DisplayName("A stack")
class TestingAStackDemo {

    Stack<Object> stack;

    @Test
    @DisplayName("is instantiated with new Stack()")
    void isInstantiatedWithNew() {
        new Stack<>();
    }

    @Nested
    @DisplayName("when new")
    class WhenNew {

        @BeforeEach
        void createNewStack() {
            stack = new Stack<>();
        }

        @Test
        @DisplayName("is empty")
        void isEmpty() {
            assertTrue(stack.isEmpty());
        }

        @Test
        @DisplayName("throws EmptyStackException when popped")
        void throwsExceptionWhenPopped() {
            assertThrows(EmptyStackException.class, stack::pop);
        }

        @Test
        @DisplayName("throws EmptyStackException when peeked")
        void throwsExceptionWhenPeeked() {
            assertThrows(EmptyStackException.class, stack::peek);
        }

        @Nested
        @DisplayName("after pushing an element")
        class AfterPushing {

            String anElement = "an element";

            @BeforeEach
            void pushAnElement() {
                stack.push(anElement);
            }

            @Test
            @DisplayName("it is no longer empty")
            void isNotEmpty() {
                assertFalse(stack.isEmpty());
            }

            @Test
            @DisplayName("returns the element when popped and is empty")
            void returnElementWhenPopped() {
                assertEquals(anElement, stack.pop());
                assertTrue(stack.isEmpty());
            }

            @Test
            @DisplayName("returns the element when peeked but remains not empty")
            void returnElementWhenPeeked() {
                assertEquals(anElement, stack.peek());
                assertFalse(stack.isEmpty());
            }
        }
    }
}

6. Parametric test

Parametric testing is a very important new feature of JUnit 5. It makes it possible to run tests multiple times with different parameters, and also brings a lot of convenience to our unit testing.

Using @ ValueSource and other annotations to specify input parameters, we can use different parameters for multiple unit tests without adding a unit test every time a parameter is added, saving a lot of redundant code.

@ValueSource: Specifies the input parameter source for parametric testing. It supports eight basic classes, String type and Class type

@NullSource: indicates that a null input parameter is provided for the parameterized test

@EnumSource: indicates that an enumeration input parameter is provided for the parameterized test

@CsvFileSource: read the contents of the specified CSV file as the parametric test input parameter

@MethodSource: means to read the return value of the specified method as the parameterized test input parameter (note that the method return needs to be a stream)

Of course, if the parametric test can only specify ordinary input parameters, it can not reach the point that makes me feel amazing. What makes me really feel his strength is that he can support all kinds of external participation. For example, CSV,YML,JSON files and even the return value of methods can also be used as input parameters. You only need to implement the ArgumentsProvider interface, and any external file can be used as its input parameter.

@ParameterizedTest
@ValueSource(strings = {"one", "two", "three"})
@DisplayName("Parametric test 1")
public void parameterizedTest1(String string) {
    System.out.println(string);
    Assertions.assertTrue(StringUtils.isNotBlank(string));
}


@ParameterizedTest
@MethodSource("method")    //Specify method name
@DisplayName("Method source parameters")
public void testWithExplicitLocalMethodSource(String name) {
    System.out.println(name);
    Assertions.assertNotNull(name);
}

static Stream<String> method() {
    return Stream.of("apple", "banana");
}

Topics: Mybatis java web SpringBoot2