This project, I intend to be a seed project, as a seed project, must be “out of the box”, must contain most of the web development related functions, all the later Spring Boot projects are to take this project, simple modification of the configuration, can be quickly developed.

The source code

Github

1.0.0 Creating a project

The IDE I use is IDEA

Create a project

Select Spring Initializr, maybe if Next keeps going around in circlesstart.spring.io/In foreign countries, access is slower. You can go scientific or you can use customstart.spring.io/

Change the organization name, project name and project description

When I created the project, the latest stable release of Spring Boot was 2.1.9. Use the latest!! Dependence is not checked first, later a plus

Project folder name and location

Adding a Maven Image

Add Maven images to speed up dependency downloads

<repository> <name> Maven Repository </name> <id> Huawei </ ID > <url>https://mirrors.huaweicloud.com/repository/maven/</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <name> <id> Huawei_plugin </id> <url>https://mirrors.huaweicloud.com/repository/maven/</url> </pluginRepository> </pluginRepositories>Copy the code

Pom file

The entire.pom file contains the following contents

<? The XML version = "1.0" encoding = "utf-8"? > < project XMLNS = "http://maven.apache.org/POM/4.0.0" XMLNS: xsi = "http://www.w3.org/2001/XMLSchema-instance" Xsi: schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion > 4.0.0 < / modelVersion > < the parent > < groupId > org. Springframework. Boot < / groupId > The < artifactId > spring - the boot - starter - parent < / artifactId > < version > 2.1.9. RELEASE < / version > < relativePath / > < / parent > < the groupId > com. WQLM < / groupId > < artifactId > boot < / artifactId > < version > 0.0.1 - the SNAPSHOT < / version > < name > boot < / name > <description>Spring Boot Demo</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> < name > maven huawei warehouse < / name > < id > huawei < id > < url > https://mirrors.huaweicloud.com/repository/maven/ < / url > < / repository > </ repository > <pluginRepository> <name> huawei maven pluginRepository </name> <id>huawei_plugin</id> <url>https://mirrors.huaweicloud.com/repository/maven/</url> </pluginRepository> </pluginRepositories> </project>Copy the code

Dependent structure diagram

One day

Spring-boot-starter and spring-boot-starter-test do not specify the version. How do they determine the version?

Why can maven dependencies not specify versions

1.1.0 Adding a Web Module

Add a Web module to the POM file

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
Copy the code

Due to thespring-boot-starter-webcontainsspring-boot-starter

You are advised to delete the following spring-boot-starter dependencies to ensure their cleanliness

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
Copy the code

role

With the introduction of spring-boot-starter-Web, we can

  • Writing web applications
  • You do not need to configure containers to run web applications
  • Verify the request parameters
  • Returns the business result object converted to joSN

Dependent structure diagram

We can see from the picturespring-boot-starter-webSeveral key dependencies are introduced

  • spring-boot-starter
  • Spring-boot-starter-tomcat: Spring boot can be started without Tomcat because of it
  • spring-webmvc
  • spring-web
  • spring-boot-starter-jsonWith it, you can use @responseBody to return JSON data
    • Jackson: Spring Boot’s default JSON parsing tool
  • hibernate-validator: provides annotations for parameter verification, such as@ Range, @ Length
    • Javax. validation: annotations that provide validation of parameters, such as @notblank, @notnull, or @pattern

For parameter verification, see Parameter Verification Hibernate-Validator

1.2.0 integration mysql

Spring Boot integration with mysql requires a JDBC driver and mysql driver

Introduction of depend on

<! --JDBC--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <! --mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>Copy the code

The version number is optional. Spring Boot has a default version number. For example, spring Boot 2.1.9.RELEASE corresponds to mysql-connector-Java version 8.0.17

Configure the mysql

The configuration varies slightly depending on the mysql-connector-Java version

# mysql connector - Java 6.0 x version configuration under spring. The datasource. The driverClassName = com. Mysql.. JDBC Driver spring.datasource.url=jdbc:mysql://localhost:3306/boot? useUnicode=true&characterEncoding=utf-8&useSSL=false spring.datasource.username=root spring.datasource.password=123456Copy the code
# mysql connector - Java 6.0 x and above version configuration spring. The datasource. The driverClassName = com. Mysql. Cj). The JDBC Driver spring.datasource.url=jdbc:mysql://localhost:3306/boot? useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=123456Copy the code

The following figure,Spring boot 2.1.9. RELEASEThe correspondingmysql-connector-javaVersion for 8.0.17

See MySQL JDBC Connection for more information

Create sample databases and tables

CREATE DATABASE IF NOT EXISTS boot DEFAULT CHARSET UTf8 COLLATE UTf8_bin; -- Select boot database USE boot; SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` INT ( 11 ) NOT NULL AUTO_INCREMENT, `user_name` VARCHAR ( 255 ) COLLATE utf8_bin NOT NULL, `pasword` VARCHAR ( 255 ) COLLATE utf8_bin NOT NULL, `salt` VARCHAR ( 255 ) COLLATE utf8_bin NOT NULL, PRIMARY KEY ( `id` ) ) ENGINE = INNODB DEFAULT CHARSET = utf8 COLLATE = utf8_bin; SET FOREIGN_KEY_CHECKS = 1;Copy the code

1.3.0 Multi-environment Configuration

Refer to Spring Profile and Maven Profile multi-environment management for details

Spring multi-environment configuration

Configure a DEV environment

createapplication-dev.propertiesFile and migrate the mysql related configuration

Using the Dev environment

Specify the environment to use in application-dev.properties

spring.profiles.active=dev
Copy the code

You can create test and prod environments in the same way, but the general public Settings will be placed in application.properties, and only non-public Settings will be placed in their respective environments

Maven multi-environment configuration

Spring Boot multi-environment configuration has two disadvantages

  1. Manually change the environment each timespring.profiles.activeThe value of the
  2. When packaging, manually delete configuration files of other environments, otherwise sensitive information of other environments will be packaged

Maven’s profile addresses both of these issues

First question

“Change the environment manually every time you switchspring.profiles.activeThe value of the”

This problem can be solved by configuring profiles to be added under the root node of the POM

<profiles> <profile> <id>dev</id> <activation> <! -- If activeByDefault is true, the profile with id dev is activated by default --> <activeByDefault>true</activeByDefault> </activation> <! <properties> <! The value of this node can be referenced elsewhere in Maven, <env>dev</env> </properties> </profile> <profile> <id>test</id> <properties> <env> </properties> </profile> <profile> <id>prod</id> <properties> <env>prod</env> </properties> </profile> </profiles>Copy the code

As shown above, three sets of environments are defined, where dev is the default environment and a “variable” called env is defined.

If you are using the IDEA editor, the Maven control window should have an additional Profiles, where the default value is the dev configured above

With minimal Profiles already configured, you can quickly switch maven’s profile environment by checking Profiles in the figure above.

Maven Profiles can now quickly switch environments by checking Profiles in the image above

Spring profiles also have to manually modify the value of spring.profiles.active to cut the environment

The question now is how to match the Maven profile environment to the Spring Profile environment so that when the Maven profile environment is switched, the Spring Profile environment is also switched

Remember the env “variables” defined in the Maven profile

spring.profiles.active=dev
Copy the code

to

spring.profiles.active=@env@
Copy the code

The Maven profile is associated with the Spring Profile environment

When a Maven profile is set to test, the profile environment defined in the POM with the id of test will be activated. In this environment, env is set to test. The Maven plugin will replace @env@ with test. This changes the environment of the Spring Profile. As you can see from the above, the value of the custom “variable “env should not be scribbled, but should correspond to the Spring Profile environment.

conclusion

  • Step one, inpomConfigure profiles in the file
  • Step two, inapplication.propertiesAdded to the configuration filespring.profiles.active=@env@

Second question

When packaging, manually delete configuration files of other environments, otherwise sensitive information of other environments will be packaged

To resolve this problem, you need to configure build information under the POM root node

<build> <resources> <resource> <directory>src/main/resources</directory> <excludes> <! --> <exclude> Application *. Yml </exclude> </excludes> </resource> < Resource > <directory>src/main/resources</directory> <! -- Filtering needs to be set to true, so that when included, The maven variable @env@ in the configuration file is replaced with the corresponding value of the current environment --> <filtering>true</filtering> <includes> <! Yml </include> <include> Application -${env}. Yml </include> </includes> </resource> </resources> </build>Copy the code
  • Directory: indicates the directory where the resource file resides
  • Includes: list of files to be included
  • Excludes: List of files to exclude

As above, is configured with two < resource >, first to exclude the SRC/main/resources directory all application configuration file is in the beginning, the second in the first added on the basis of the required configuration file. Note that application-${env}. Yml is a dynamic value that changes with the current environment. If the current environment is a profile named dev, then env is dev.

After this configuration, Maven will first exclude the specified configuration file during build, and then add the required configuration file based on the current environment.

Pom file

<? The XML version = "1.0" encoding = "utf-8"? > < project XMLNS = "http://maven.apache.org/POM/4.0.0" XMLNS: xsi = "http://www.w3.org/2001/XMLSchema-instance" Xsi: schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion > 4.0.0 < / modelVersion > < the parent > < groupId > org. Springframework. Boot < / groupId > The < artifactId > spring - the boot - starter - parent < / artifactId > < version > 2.1.9. RELEASE < / version > < relativePath / > < / parent > < the groupId > com. WQLM < / groupId > < artifactId > boot < / artifactId > < version > 0.0.1 - the SNAPSHOT < / version > < name > boot < / name > <description>Spring Boot Demo</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> < project. Reporting. OutputEncoding > utf-8 < / project. Reporting. OutputEncoding > < Java version > 1.8 < / Java version > </properties> <! -- Maven Multi-environment --> <profiles> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> <! -- True indicates that the profile is activated by default --> </activation> <properties> <! <env>dev</env> <! The value of this node can be referenced elsewhere in Maven, </properties> </profile> <profile> <id>test</id> <properties> </env> </profile> <profile> <id>prod</id> <properties> <env>prod</env> </properties> </profile> </profiles> <dependencies> <! --web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <! --mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <! --mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> < artifactId > mybatis - spring - the boot - starter < / artifactId > < version > 2.1.0 < / version > < / dependency > <! --test--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <resources> <resource> <directory>src/main/resources</directory> <excludes> <! --> <exclude> Application *. Yml </exclude> </excludes> </resource> < Resource > <directory>src/main/resources</directory> <! The maven variable @env@ will be replaced with the current value in the include file --> <filtering>true</filtering> <includes> <! Yml </include> <include> Application -${env}. Yml </include> </includes> </resource> </resources> </build> <repository> <name> Huawei Maven </name> <id> Huawei </id> <url>https://mirrors.huaweicloud.com/repository/maven/</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <name> <id> Huawei_plugin </id> <url>https://mirrors.huaweicloud.com/repository/maven/</url> </pluginRepository> </pluginRepositories> </project>Copy the code

1.4.0 Multi-Module Configuration

Larger projects tend to be managed in a multi-module format. Upgrading a large project to a multi-module format usually requires two steps

  1. Breaking up existing projects
  2. Configure multiple Maven modules

For details on how to split existing projects and Maven multi-module configuration, see Maven Multi-module Configuration, Management

Breaking up existing projects

I split the project by function, but since the project itself is not large, I simply split it into the User module and the Common module

Create two new modules under Boot

Pom for submodules

At this point, the content of the parent module’s POM is also changed, adding the following three lines

Create the Common module again, the same process, I will not demonstrate, after the creation of the poM is as follows

The overall project structure is as follows

The next step is to migrate the contents under the original SRC directory to the appropriate submodules

Here I put in the user module, pay attention to the path and naming conventions during the migration process, the process is not shown, after the migration, the structure is as follows.

Multi-module Configuration

The multi-module configuration complies with the following principles

  • Common and generic configurations must be configured in the parent POM
  • The version number is centrally managed by the parent POM

As shown below, elements with a blue background will all inherit from the quilt project

At present, only the user module uses the following dependencies, and the common module does not need these dependencies. Therefore, copy the dependencies to the user module and delete the dependencies

buildThe configuration is only used by the user module, also copied to the user module, later deleted

Now that the parent project is configured, configure the User module as follows

The common module is configured when used

Multi-module Management

Multi-module environment managementWe configured the Maven multienvironment in the parent POM, and the submodules inherit these configurations. After that, we just need to switch the maven environment in the Maven plugin, and all the sub-modules’ Maven environment will be switched

Multi-module build managementIn the Maven plugin, all submodules are compiled, tested, packaged, cleaned…

1.5.0 integration mybatis

Integrating Mybatis generally requires 5 steps

  1. Introduction of depend on
  2. Create the PO layer to hold our data persistence objects
  3. Create DAO layer to store the add, delete, change and check methods of the database
  4. Create mapper. XML layer corresponding to add, delete, change and query statements
  5. Configure @Mapperscan on the startup class
  6. The other. For example, MyBatis Generator is configured to help us generate PO, DAO and mapper.xml

Add the dependent

There are a few things to note when adding dependencies to a multi-module project

  • Do not add a dependency directly to the parent POM, so that all child modules inherit the dependency
  • Multiple modules reference the same dependency. It is best to ensure that the version of the dependency is the same

Maven dependencyManagement is an easy way to manage multi-module dependencies

For maven dependencyManagement, see maven dependency version management

I’m not going to explain it, I’m going to apply it

  1. Define the mybatis-spring-boot-starter version variable in properties

    < mybatis - spring - the boot - starter. Version > 2.1.0 < / mybatis - spring - the boot - starter. Version >Copy the code

  2. Declare the Mybatis dependency at the root of the parent POM

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis-spring-boot-starter.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    Copy the code

  3. Introduce the MyBatis dependency in the POM file of the User module

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    Copy the code
  4. Because mybatis-spring-boot-starter contains spring-boot-starter- JDBC, delete the spring-boot-starter- JDBC dependency to ensure that the dependency is clean

Dependent structure diagram

Create the corresponding folder

As shown in figure

com.wqlm.boot

  • Controller: indicates the control layer
  • Po: Stores Java objects corresponding to tables in the database
  • Dto: Stores data transfer objects, such as registration, registration information can be received with a DTO object
  • Dao: Interface for storing operation database
  • Service: indicates the service layer
  • Vo: stores the service result object
  • Qo: encapsulates query parameters

resources

  • Mapper: stores the mapper. XML file

Configure mybatis

Mybatis needs to know which classes are mapper! There are two ways to tell Mybatis.

The first kind of

Configure @Mapperscan on the startup class

Dao = MapperScan("com.wqlm.boot.user.dao")Copy the code

The second,Add to the interface@MapperNotes, as follows

If I had to choose, I’d choose the first configuration once and for all

Also tell Mybatis, where is your mapper. XML file

Mybatis. Mapper-locations =classpath*:mapper/*.xmlCopy the code

Since the configuration here is environment-independent, it should be configured inapplication.properties

1.5.1 Configuring MyBatis Generator

MyBatis Generator is a code generation tool provided by MyBatis. It can help us generate persistent objects (Po) for tables, interfaces to manipulate databases (DAO), XML for CRUD SQL (Mapper).

The usage method is divided into three steps

  1. Introduce and configure the MyBatis Generator plug-in
  2. Configure the MyBatis Generator Config file
  3. Use the MyBatis Generator plug-in

For details, see MyBatis Generator HyperDetailed Configuration

Only one final configuration is given here

Introduce and configure the MyBatis Generator plug-in

Add the following configuration under the root node of the USER project poM file

<build> <plugins> <plugin> <groupId>org.mybatis.generator</groupId> < artifactId > mybatis generator - maven plugin - < / artifactId > < version > 1.3.7 < / version > < configuration > <! - mybatis code generator configuration file - > < configurationFile > SRC/main/resources/mybatis generator - config. XML < / configurationFile > <! -- Allow overwriting generated files --> <overwrite>true</overwrite> <! Add the current POM dependencies to the generator's classpath --> <! --<includeCompileDependencies>true</includeCompileDependencies>--> </configuration> <dependencies> <! -- Mybatis -Generator plugin dependencies --> <! --<dependency>--> <! --<groupId>org.mybatis.generator</groupId>--> <! --<artifactId>mybatis-generator-core</artifactId>--> <! - < version > 1.3.7 < / version > -- > <! --</dependency>--> <! <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency> </dependencies> </plugin> </plugins> <build>Copy the code

Configure the MyBatis Generator Config file

In the Resources directory of the User project, create mybatis-generator-config.xml as follows

<? The XML version = "1.0" encoding = "utf-8"? > <! Mybatis code generator configuration --> <! DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <! --> <properties resource="application-dev.properties"/> <! A database has a context, and the children of the context must be in the order they are given. Property *,plugin*,commentGenerator? ,jdbcConnection,javaTypeResolver? , javaModelGenerator,sqlMapGenerator? ,javaClientGenerator? ,table+ --> <context id="myContext" targetRuntime="MyBatis3" defaultModelType="flat"> <! -- This plugin adds equals and hashCode methods to generated Java model objects --> <! --<plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"/>--> <! -- Comments --> <commentGenerator> <! <property name="suppressAllComments" value="true"/> <! -- Do not want generated comments to contain timestamps --> <! --<property name="suppressDate" value="true"/>--> <! Add comments for db table fields only if suppressAllComments is false --> <! --<property name="addRemarkComments" value="true"/>--> </commentGenerator> <! - a JDBC connection - > < jdbcConnection driverClass = "${spring. The datasource. DriverClassName}" connectionURL="${spring.datasource.url}" userId="${spring.datasource.username}" password="${spring.datasource.password}"> <! NullCatalogMeansCurrent =true--> <property name="nullCatalogMeansCurrent" value="true"/>  </jdbcConnection> <! --> <javaTypeResolver> <! -- Whether to use bigDecimal, default is false. False, resolves the JDBC DECIMAL and NUMERIC types to Integer true, Parse JDBC DECIMAL and NUMERIC types to java.math.BigDecimal--> <property name="forceBigDecimals" value="true"/> <! -- Default false false, parse all JDBC time types to java.util.Date true, DATE -> java.time.LocalDate time -> java.time.LocalTime TIMESTAMP -> java.time.LocalDateTime TIME_WITH_TIMEZONE -> java.time.OffsetTime TIMESTAMP_WITH_TIMEZONE -> java.time.OffsetDateTime --> <! --<property name="useJSR310Types" value="false"/>--> </javaTypeResolver> <! <javaModelGenerator targetPackage="com.wqlm.boot.user. Po "targetProject=" SRC /main/ Java "> <! -- Whether to use schema as package suffix. Default is false --> <! --<property name="enableSubPackages" value="false"/>--> <! <property name="trimStrings" value="true"/> </javaModelGenerator> <! <sqlMapGenerator targetPackage=" Mapper "targetProject=" SRC /main/resources"> <! --<property name="enableSubPackages" value="false"/>--> </sqlMapGenerator> <! <javaClientGenerator targetPackage="com.wqlm.boot.user.dao" targetProject=" SRC /main/ Java" type="XMLMAPPER"> <! --<property name="enableSubPackages" value="false"/>--> </javaClientGenerator> <! -- Schema indicates the name of the database. Oracle needs to be configured, but mysql does not. TableName specifies the name of the corresponding database table. DomainObjectName specifies the name of the entity class to be generated. By default, the PASCAL naming method converts the tableName to the class name. True generates an Example helper class to help you with conditional queries, --> <table schema="" tableName="user" domainObjectName=" user" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false" selectByExampleQueryId="false"> <! -- Whether to use actual column names, default is false--> <! --<property name="useActualColumnNames" value="false" />--> </table> </context> </generatorConfiguration>Copy the code

Application – dev. The properties of the configuration

The external configuration file referenced by MyBatis Generator Config is as follows

# mysql spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/boot? useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=123456Copy the code

Use the MyBatis Generator plug-in

Once configured, double-click MyBatis Generator in Maven to run it

1.5.2 Integration of Tk.Mybatis (Universal Mapper)

In the previous section, MyBatis Generator generated some common methods for manipulating databases. This can also be done by integrating tk.mybatis (universal mapper), which will provide more common methods that do not require mapper.xml configuration.

Springboot integration with Tk.mybatis (general mapper) generally requires 3 steps

  1. Introduction of depend on
  2. Configure the Mybatis Generator plug-in for Tk.mybatis
  3. The DAO path configured to scan on the startup class
  4. Configure the universal Mapper

Tk. Mybatis dead simple

Introduction of depend on

As usual, configure the tk.mybatis version in the parent POM and declare the tk.mybatis dependency

. < the properties > < tk. Mybatis mapper - spring - the boot - starter. Version > 2.1.5 < / tk, mybatis mapper - spring - the boot - starter. Version > </properties> <! <dependencyManagement> <dependencies> <! Tk.mybatis mapper--> <dependency> <groupId> Tk.mybatis </groupId> <artifactId> <version>${tk.mybatis.mapper-spring-boot-starter.version}</version> </dependency> </dependencies> </dependencyManagement>Copy the code

Dependencies are then introduced into the POM of the User module

<dependencies> <! Tk.mybatis mapper--> <dependency> <groupId> Tk.mybatis </groupId> <artifactId> </dependency> </dependencies>Copy the code

Configure the Mybatis Generator plug-in for Tk.mybatis

Tk.mybatis has developed a plugin for Mybatis Generator to change the original generation strategy of MyBatis Generator. Once configured, the generated files are more concise and the comments are more meaningful.

The entire configuration process consists of two steps

  1. Introducing plug-in dependencies
  2. Modify MyBatis Generator Config

Introducing plug-in dependencies

In the original MyBatis Generator plugindependenciesAdd the following dependencies

<! Mybatis </groupId> <artifactId>mapper</artifactId> <version>4.1.5</version> </dependency>Copy the code

Modify MyBatis Generator Config

There are a few major changes

The first istargetRuntimeTo change the value ofMyBatis3Simple.defaultModelTypeSet toflat

iftargetRuntime="MyBatis3"The resulting mapper.xml will have an extra piece of useless code like this

Then add the tk.mybatis plug-in

<plugin type="tk.mybatis.mapper.generator.MapperPlugin"> <! - the dao to inherit the interface - > < property name = "mappers" value = "tk.mybatis.mapper.com mon. Mapper" / > <! <property name="caseSensitive" value="true"/> </plugin>Copy the code

Nothing else needs to be changed. Once configured, run the MyBatis Generator plugin to generate the following file

po As you can see, the annotations generated by tk.mybatis are much simpler and easier to understand than those generated by MyBatis Generator. In addition, it has a few additional notes

  • @table (name = “user”) : indicates that the Po corresponds to the user Table of the database
  • @id: indicates the primary key of the user table
  • @column (name = “user_name”) : indicates that the attribute corresponds to the user_name field of the user table

dao MyBatis Generator has fewer interfaces than the code generated by MyBatis Generator, but inherits one more class that you configure in the tk.mybatis pluginAs you might guess, the missing interfaces are all inherited from this onetk.mybatis.mapper.common.MapperIn the class shown below, userMapper inherits so many methods that they can be used directly

mapper.xml Much less code than MyBatis Generator

The DAO path configured to scan on the startup class

This step was already configured when we integrated MyBatis

However, after integrating tk.mybatis, you need to use the tk.mybatis package@MapperScan, so it needs to be modified@MapperScanThe package path

import tk.mybatis.spring.annotation.MapperScan;
Copy the code

Configure the universal Mapper

Mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity = mysql.identity Mapper. not-empty=trueCopy the code

Tk.mybatis is now fully integrated

1.5.3 Integrate the PageHelper paging plug-in

Paging query is a very common function in Web development, although Mybatis can also achieve paging, but that is based on memory paging, that is, to find out all the data at one time, and then put in memory for several times to return.

The PageHelper paging plug-in is physical paging and is implemented by SQL keywords. For example, limit in mysql, Rownum in Oracle, etc.

The PageHelper page plugin and tk.mybatis are all addresses of the PageHelper project written by the same author

Integrating PageHelper requires two steps

  • Introduce the PageHelper dependency
  • Configuration pagehelper

Introduce the PageHelper dependency

As usual, the parent POM defines the dependency version and declares the dependency

< the properties > < pagehelper - spring - the boot - starter. Version > 1.2.12 < / pagehelper - spring - the boot - starter. Version > < / properties >Copy the code
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>${pagehelper-spring-boot-starter.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>
Copy the code

Submodules introduce dependencies

<dependencies>
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
    </dependency>
</dependencies>
Copy the code

Configuration pagehelper

Mysql > select * from pagehelperdialect where pagehelperdialect =mysql > select * from pagehelperdialect where pagehelperdialect =mysql > select * from pagehelperdialect where pageNum<1 If pageNum>pages does not support pagerhelper (' pagerhelper ', 'pagerhelper'). Reasonable =true # The default false. # pagehelper supportMethodsArguments = true pagehelper. Params = count = countSqlCopy the code

For more configurations, please refer to the official website

1.6.0 Introduces lombok

Lombok is a plug-in for simplifying code that generates get, set, toString, hash… Methods.

Integrating Lombok is simple

  1. Introduce lombok dependencies
  2. Install the Lombok plug-in for the IDE

See this article for the Lombok plugin to use Lombok

Introduce lombok dependencies

Since the Lombok dependency is already declared in spring-boot-starter-parent, we just need to introduce it in the submodule

<! --lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>Copy the code

Install the Lombok plug-in for the IDE

I’m using IDEA, so take IDEA as an example

1.7.0 integrate redis

As the most commonly used NOSQL database, Spring Boot has excellent support for Redis and is easy to integrate in just four steps

  1. Introduction of depend on
  2. Configure redis
  3. Custom RedisTemplate (recommended)
  4. Custom Redis action classes (recommended)

Detailed integration steps I have written a separate article, address below

Spring Boot 2.0 integrates with Redis

1.7.1 Integrating Spring Cache

Spring Cache is a Spring solution for caching scenarios. Use @cacheput, @cacheevict, and @cacheable annotations to store, query, and delete the cache

Since we have introduced Redis, spring Cache can be used with a simple configuration

I wrote a separate article detailing the integration steps as follows (in the Spring Cache section)

Spring Boot 2.0 integrates with Redis

Of course, you can choose not to integrate

1.8.0 Develop user module

Different systems correspond to different user designs. Nuggets user system and Taobao user system are certainly different. Therefore, although this project is a seed project, it is difficult to give a general user module design.

So INSTEAD of going for a generic user module, I went for a module that incorporated all of the technologies.

In this way, in the future use of one of the above technologies, also have a reference.

The users table

Build predicative sentences inConfigure the mysqlThe chapter

Add controller, Service, and DTO

Create controller, Service, and DTO directories first

Start with the registered interface

Note that the verification parameter must be added@Validannotations

Among them@DataThe Lombok plug-in was used

The data store is a salty hash of the password, meaning that even we can’t see the user’s password

1.8.1 Customizing the Global Status Code and Service Result Classes

While there’s nothing wrong with returning success or failure, it’s not very elegant because other interfaces may not return simple strings.

In fact, we can customize a business result class, all the interfaces, return the business result object, this business result class, in addition to business results, business execution status, business messages, etc.

In addition to the business result class, I also suggest creating a global status code class. Just like the API interface of Ant Financial, a status code will be returned if the call fails, which is convenient for error detection

Custom global status code

Create an enums directory

Create the ApplicationEnum global status code class. I’ve only written a few here so you can add them later

Create the business result class

As follows, create the result directory under the VO directory and create the business result class in it

Create a SuccessResult and a FailResult for ease of use

Modify registration interface

1.8.2 Unified Exception Handling

It is a common requirement for all Web projects to deal with all kinds of exceptions that may occur during business execution. Spring provides @RestControllerAdvice, @ExceptionHandler annotations to help us handle exceptions.

There is no unified standard on how to design specific exception handling. Here is my design for reference only.

What I do is define a custom exception class, throw it when the business fails, and then handle it in a custom exception handling class.

For more information, see Unified Spring-based exception handling

Custom exception classes

Each exception applies to an ApplicationEnum

Custom exception handling classes

If an Exception can match more than one @ExceptionHandler, select the Exception with the least depth of matching (that is, the Exception that best matches).

Use custom exceptions

1.8.3 Parameter verification and exception handling

Parameter calibration

First append to the object to be verified@validannotations

Then use the appropriate annotations in the object you want to validate

Please refer to the details

Hibernate-Validator Spring parameter verification

Exception handling

If the parameter binding is unsuccessful or the validation fails, an exception will be thrown! But the exception thrown by default contains a lot of sensitive information, such as:Therefore, common exceptions should be captured and then encapsulated.

Extends ResponseEntityExceptionHandler is to rewrite a few common anomalies are handled by default. Of course, you can also directly through the @ ExceptionHandler intercept (), instead of extends ResponseEntityExceptionHandler

Handling these three exceptions generally covers most scenarios that require manual handling of parameter exceptions

  • org.springframework.validation.BindException
  • org.springframework.web.bind.MethodArgumentNotValidException
  • javax.validation.ConstraintViolationException

Please refer to the details

Exception handling of Spring parameter verification

1.8.4 Adding interfaces for logging in, changing passwords, and obtaining user information

Mainly some business logic, no what refers to say, specific code reference project source code! The only thing that refers to lifting a mouth is use@Value("${}")Annotations get attributes in the configuration file

1.8.5 Adding an Authentication Interceptor

Some interfaces we want to be accessible only to logged-in users, and the general solution is to add a logged-in interceptor.

The method is also very simple, mainly divided into 3 steps

  • Define which interfaces require authentication (login to access) or which do not
  • The customHandlerInterceptorTo intercept the interface before accessing it
  • The customWebMvcConfigurerTo define which interfaces need to be intercepted

1. Determine the authentication exempt URL

2. CustomHandlerInterceptorTo verify the token validity of intercepted requests

3. The customWebMvcConfigurerBlock all requests except the list of authentication-exempt urls

1.8.6 Unified Mapping User-defined configuration

Where did we need to use it beforepropertiesThat’s where the configuration is used@Value("${}")In order to get. The following

We can also create a custom configuration class that will allpropertiesAll the custom attributes are mapped to the corresponding attributes, as follows

Then when used, access the class directly

1.9.0 Configuring Logs

Spring Boot already has the logging system configured by default, but further configuration is required if you want to display SQL or export logs to files.

Please refer to the details

Logging framework in the Java ecosystem Java Logging implementation framework Logback Logback Configuration example Spring Boot Logging

According to the SQL

Configure it in application.properties

# the dao (com) WQLM) boot. User. Dao) to display the SQL logging.level.com.wqlm.boot.user.dao=debug layer set the debug levelCopy the code

Output logs to files

Configure it in application.properties

Loging.file.name =logs/user/user.log # Maximum number of days to keep logs logging.file.max-history=30 # Maximum size of a single log file logging.file.max-size=10MBCopy the code

Fine configuration

There is only a limited amount of configuration that can be done in application.properties, and if you want to go further, you need to use the corresponding logging framework configuration file!

Spring Boot uses Logback as the logging implementation framework, and it is recommended that logback-spring. XML be used as the name of the configuration file.

The following is a reference configuration example


      

<! -- scan: enable "hot update" scanPeriod: enable "hot update" scan period: 60 seconds -->
<configuration scan="true" scanPeriod="300 seconds">

    <! -- Add color converter -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>

    <! Source: which attribute to use defaultValue: defaultValue if not found -->
    <springProperty name="env" scope="context" source="spring.profiles.active" defaultValue="env"/>

    <! -- Application name -->
    <property name="APP_NAME" value="user"/>

    <! -- Custom variable used to configure the log output format, which is as close as possible to the spring Boot default output style %date: Date, default format YYYY-MM-DD HHH: MM: SS,SSS default to use the local time zone, defined by % D {YYYY-MM-DD HHH: MM: SS,SSS} %-5level: Log levels with five placeholders, such as "info" and "error" % Thread: log output thread %class: fully qualified name of the log output class, inefficient %method: method name of the log output %line: line number of the log output, inefficient % MSG: Log message content %n: newline -->
    <property name="LOG_PATTERN" value="%date %-5level ${PID:- } --- [%thread] %class.%method/%line : %msg%n"/>

    <! -- Color log format -->
    <property name="LOG_PATTERN_COLOUR"
              value="${env} %date %clr(%-5level) %magenta(${PID:- }) --- [%thread] %cyan(%class.%method/%line) : %msg%n"/>


    <! - log output. Ch. Qos. Logback. Core. The ConsoleAppender: output to the console - >
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <! -- Configure log output format -->
            <pattern>${LOG_PATTERN_COLOUR}</pattern>
            <! Character set -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>

    <! -- Log output. Ch. Qos. Logback. Core. Rolling. The RollingFileAppender: rolling output to file - >
    <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <! Active log file names (absolute and relative paths supported) -->
        <file>logs/${APP_NAME}/${APP_NAME}.log</file>
        <! - rolling strategy. Ch. Qos. Logback. Core. Rolling. SizeAndTimeBasedRollingPolicy: according to the size and time rolling -- >
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <! When to trigger scrolling, how to scroll, and the naming format of the scrolling file %d: date, default format YYYY-MM-DD, custom format %d{YYYY-MM-dd HHH: MM :ss} % I: indicates the sequence number of the log file within a single scrolling period. Zip: compresses the log file into a ZIP. Logs /app1/backup will be stored in a zip package named app1_%d_% I.ZIP --> after the first log request after 0 o 'clock every day.
            <fileNamePattern>logs/${APP_NAME}/backup/${APP_NAME}_%d{yyyy-MM-dd}_%i.zip</fileNamePattern>

            <! Maximum size of a single log file -->
            <maxFileSize>10MB</maxFileSize>

            <! Delete log files from n scroll cycles (at most, keep history of the first n scroll cycles)-->
            <maxHistory>30</maxHistory>
            <! MaxHistory limits the total size of all log files, and deletes them from the oldest log file.
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <! -- Log output format -->
            <pattern>${LOG_PATTERN}</pattern>
            <! Character set -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>


    <! -- Use the following configuration for non-PROD environments -->
    <springProfile name=! "" prod">
        <! -- logger name: package name or class name, level: start log level, additivity: whether to append the appender of the parent class -->
        <logger name="com.wqlm.boot.dao" level="debug" additivity="false">
            <appender-ref ref="STDOUT"/>
            <appender-ref ref="ROLLING"/>
        </logger>
    </springProfile>


    <! -- root logger -->
    <root level="info">
        <! -- STDOUT, ROLLING --
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="ROLLING"/>
    </root>
</configuration>
Copy the code

Relative path position