In this article

  • Why SpringBoot
  • What kind of environment
  • The development environment
  • Import the quick start project
  • Preparations for Integration
  • Integrated Mybatis
  • Integrated Swagger2
  • Multi-environment Configuration
  • Log configuration in multiple environments
  • Commonly used configuration

Why SpringBoot

The advantage of SpringBoot over traditional SSM frameworks is that it provides default boilerplate configuration and simplifies the initial setup process of Spring applications. If you don’t want to be bothered by a lot of XML configuration files, you can consider using SpringBoot instead

What kind of environment

This article will integrate Mybatis and Swagger2 frameworks based on the official fast start project template provided by Spring, and explain the configuration method of Mybatis Generator one-click code generation plug-in, Logback, one-click document generation and multi-environment. Finally, I’ll cover custom configured annotation fetching, global exception handling, and more.

The development environment

I use IDEA as a development tool. The quick start project integrated with SpringBoot by default can be directly created when DOWNLOADING IDEA. If you use Eclipse, you can consider installing the SpringBoot plug-in or directly configure and download the SpringBoot quick start project from here. It should be noted that this environment is built with the fast startup framework of SpringBoot2.0, which requires JDK version 1.8 or above.

Import the quick start project

Whether the template project is imported by IDEA or downloaded in real life, it is necessary to initialize the configuration of the quick start project. If IDEA is used, choose Spring Initializr when creating a project. The main configuration is shown in the following figure




IDEA Creating a SpringBoot project – Enter the project/package name




IDEA Create a SpringBoot project – Select a dependency package


Click Next and finish. IDEA shows that the template project is being downloaded. After downloading, the template project is created successfully according to the pom. XML download package




Direct download of SpringBoot Quick start project – Project configuration







Fast start project – Project structure


Preparations for Integration

Change. Properties to.yml

Compared with properties, YML is more simplified and many official demos are the configuration form of YML. Here, we use the form of YML to replace properties. Compared with properties, there are mainly the following two differences

  1. The description of the key is separated from the original “.” into a tree shape
  2. All keys must be followed by a space, otherwise the startup project will report a configuration resolution error
Spring. Datasource. Name = mysql spring. Datasource jdbc:mysql://localhost:3306/db?characterEncoding=utf-8 spring.datasource.username = root spring.datasource.password = 123 # yml spring type syntax descriptions: the datasource: name: mysql url: JDBC: mysql: / / localhost: 3306 / db? CharacterEncoding = utf-8 username: root password: 123Copy the code
Configure required dependencies

After the quick start project was successfully created, we observed the dependencies in the pem. XML file as shown below, including the Web, Mybatis and Mysql we selected

<! -- spring web mvc --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <! -- mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> < artifactId > mybatis - spring - the boot - starter < / artifactId > < version > 1.3.1 < / version > < / dependency > <! -- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <! -- test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>Copy the code

In this case, I chose Ali’s Druid and PageHelper as the pagination plugin. In addition, we also need to integrate Swagger2 document automation framework, so we added the following four dependencies

<! <dependency> <groupId>com.github. Pagehelper </groupId> < artifactId > pagehelper - spring - the boot - starter < / artifactId > < version > 1.2.3 < / version > < / dependency > <! > <dependency> <groupId>com.alibaba</groupId> < artifactId > druid - spring - the boot - starter < / artifactId > < version > 1.1.1 < / version > < / dependency > <! Alibaba </groupId> <artifactId>fastjson</artifactId> The < version > 1.2.31 < / version > < / dependency > <! <dependency> <groupId> IO. Springfox </groupId> <artifactId> Springfox-swagger2 </artifactId> The < version > 2.5.0 < / version > < / dependency >Copy the code

Integrated Mybatis

Mybatis includes druID database connection pool, PageHelper pagination plug-in, Mybatis – Generator code reverse generation plug-in, Mapper, POJO scanning configuration

Configure the Druid database connection pool

Add the following configuration to the application.yml file

Spring: a datasource: # if there are multiple data sources, monitoring can distinguish by name when the name: # mysql to connect to the database url url: JDBC: mysql: / / localhost: 3306 / db? Password: 123 # druid characterEncoding= utF-8 # characterEncoding= utF-8 # characterEncoding= utF-8 # characterEncoding= utF-8 # Com. Alibaba. Druid. Pool. # # DruidDataSource extensions monitoring statistics with the filter: stat logging with the filter: log4j defense SQL injection filter: wall filters: Stat # Maximum number of connection pools maxActive: 20 # Number of physical connections established during initialization. InitialSize: 1 # Maximum wait time to obtain a connection in milliseconds maxWait: 60000 # Minimum pool number of connections minIdle: Hold free 1 timeBetweenEvictionRunsMillis: 60000 # connection without the ousted the longest minEvictableIdleTimeMillis: SQL > select * from validationQuery where validationQuery is null TestOnBorrow, testOnReturn, and testWhileIdle will not function. ValidationQuery: Select count (1) the from 'table' # test application connection, if free time is more than timeBetweenEvictionRunsMillis, perform effective testWhileIdle validationQuery detects whether connection: TestOnBorrow: True # Execute validationQuery when applying for a connection to check whether the connection is valid. False # Execute validationQuery to check whether the connection is valid when returning the connection. This configuration will reduce performance testOnReturn: Preparedstatements PSCache poolPreparedStatements False # to enable PSCache, you must configure greater than zero, when greater than zero, poolPreparedStatements trigger automatically modified to true maxOpenPreparedStatements: 1Copy the code
Configure the PageHelper paging plug-in
# pageHelper pagerocdialect: Mysql > select * from pageNum where pageNum < 1 where pageNum > pages = 'reasonable: true'Copy the code
Code reverse generation plug-in mybatis-generator configuration and operation

There are three main steps to use mybatis- Generator plug-in

  1. Add mybatis- Generator plug-in to POM.xml
<build> <plugins> <! <plugin> <groupId>org.springframework. Boot </groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <! Mybatis generator plugin -- <plugin> <groupId>org.mybatis. Generator </groupId> < artifactId > mybatis generator - maven plugin - < / artifactId > < version > 1.3.2 < / version > < configuration > <! Generatorconfig. XML configuration in resources/ Generator directory --> <configurationFile> ${basedir}/src/main/resources/generator/generatorConfig.xml </configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> </plugin> </plugins> </build>Copy the code

2. Create the reverse code generation configuration file generatorconfig.xml

Create a Generator folder in the Resources directory, following the scan location in the pom.xml plug-in configuration. Create a GeneratorConfig.xml configuration file in the newly created folder with the following configuration details

<? The XML version = "1.0" encoding = "utf-8"? > <! DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <! Mybatis -generator: generate-e --> <! - database driven: choose your local hard disk database driven above package - > < properties resource = "generator/generator. The properties" / > < classPathEntry location="${classPathEntry}"/> <context id="DB2Tables" targetRuntime="MyBatis3"> <! Database link URL, User name and password - > < jdbcConnection driverClass = ". Com. Mysql. JDBC Driver "connectionURL =" JDBC: mysql: / / localhost: 3306 / ${db}? characterEncoding=utf-8" userId="${userId}" password="${password}"> </jdbcConnection> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <javaModelGenerator targetPackage="${pojoTargetPackage}" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <! <sqlMapGenerator targetPackage="${mapperTargetPackage}" targetProject=" SRC /main/resources"  name="enableSubPackages" value="true"/> </sqlMapGenerator> <! <javaClientGenerator type="XMLMAPPER" targetPackage="${daoTargetPackage}" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <! --> <table tableName="%" schema="${db}"/> </context> </generatorConfiguration>Copy the code

To templatethe GeneratorConfig.xml configuration, here the more volatile configuration items are isolated as a generatorConfig.xml configuration file, and the configuration of this file is read using the properties tag. The advantage of doing this is that you only need to focus on a few configuration items when you need to reuse this XML in multiple places. Create the generatorconfig. XML file at the same level as generatorConfig. XML. Configure the generator.properties file as follows

Select the database driver package classPathEntry = on your local hard drive D:/CJH/maven-repository/mysql/mysql-connector-java/5.1.30/mysql-connector-java-5.1.30.jar = root password = 123 # generate pojo package name position In the SRC/main/Java directory pojoTargetPackage = com. Spring. The demo. Springbootexample. Mybatis. Po # Generate the DAO package name In the SRC/main/Java directory daoTargetPackage = com. Spring. Demo. Springbootexample. Mybatis. Mapper # generate mapper package name position MapperTargetPackage = mapper in SRC /main/resourcesCopy the code
  1. Run mybatis- Generator to generate Dao, Model and Mapping
Run MVN mybatis-generator:generate -eCopy the code
Mybatis scan pack configuration

The entity and mapping class corresponding to the specified database have been generated so far, but they cannot be used directly. Only after configuring mybatis to scan the address can they be called normally

  1. Configure mapper. XML and poJO package addresses in application.yml
Mybatis: # mybatis: # mybatis: # mybatis: # mybatis: # mybatis: # mybatis: # mybatis: # mybatis: # mybatis: # com.spring.demo.springbootexample.mybatis.poCopy the code
  1. In SpringBootExampleApplication. Open Mapper scanning annotations in Java
@SpringBootApplication @MapperScan("com.spring.demo.springbootexample.mybatis.mapper") public class SpringBootExampleApplication { public static void main(String[] args) { SpringApplication.run(SpringBootExampleApplication.class, args); }}Copy the code
Test the effectiveness of mapper
@controller public class TestController {// replace with Autowired UserMapper UserMapper; @ RequestMapping ("/test ") @ ResponseBody public Object test () {/ / query the table all the data return userMapper. SelectByExample (null); }}Copy the code

Start SpringBootExampleApplication. Java main function, if not in the application. The yml specially configured for server port springboot would run using the default port 8080, operation success will print log as follows

Tomcat started on port(s): 8080 (http) with context path ''
Copy the code

Enter the address in the browser. If all data in the table is returned, mybatis integration is successful

http://localhost:8080/test
Copy the code

Integrated Swagger2

Swagger2 is a quick document construction tool, which can automatically generate a Restful JSON interface document through annotations, and can generate HTML web interface document through tools such as Swagger-UI. The integration of Swagger2 is relatively simple, so you need to be familiar with it. Integration, annotations, and usage are divided into four steps

  1. Build the SwaggerConfig file
@configuration Public Class SwaggerConfig {private Final String Version = "1.0"; Private final String title = "SpringBoot example project "; Private final String description = "API document automatically generated example "; // Service Description URL Private Final String termsOfServiceUrl = "http://www.kingeid.com"; // licence private final String license = "MIT"; // licnce url private final String licenseUrl = "https://mit-license.org/"; / / interface author Contact private final Contact Contact = new Contact (" calebman ", "https://github.com/calebman", "[email protected]"); @Bean public Docket buildDocket() { return new Docket(DocumentationType.SWAGGER_2).apiInfo(buildApiInf()) .select().build(); } private ApiInfo buildApiInf() { return new ApiInfoBuilder().title(title).termsOfServiceUrl(termsOfServiceUrl).description(description) .version(version).license(license).licenseUrl(licenseUrl).contact(contact).build(); }}Copy the code
  1. In SpringBootExampleApplication. In Java enabled Swagger2 annotation

Add the @enablesWagger2 annotation under the @SpringBootApplication annotation

  1. Examples of common annotations
@controller@requestMapping ("/v1/product") @api (value = "DocController", Tags = {"restful apis "}) public Class DocController extends BaseController {@requestMapping (value = "/{id}", @apiOperation (value = "modify specified product ", httpMethod = "PUT", Produces = "application/json") // @apiimplicitParams @APIIMPLICITParam ({@APIIMPLICITParam (name = "ID", value =" product ID", Required = true, paramType = "path")}) public WebResult update(@PathVariable("id") Integer id, @modelAttribute Product Product) {logger.debug(" modify the specified Product to receive Product ID and Product information =>%d,{}", id, Product); If (id = = null | | "" equals (id)) {logger. The debug (" product id can't be empty"); return WebResult.error(ERRORDetail.RC_0101001); } return WebResult.success(); }} // an example of an annotation in Model @apiModel (Value = "Product information ") public class Product {// Indicate changes to model attributes or data operations @APIModelProperty (Required = true, Name = "name", value = "product name", dataType = "query") private String name; @APIModelProperty (name = "type", value = "product type", dataType = "query") private String type; }Copy the code
  1. Generate a JSON document

After the integration is successful, the project console prints logs at the INFO level. The intercept part is as follows, indicating that you can access the v2/ apI-docs interface of the application to obtain the JSON data of the document API. You can enter the specified address in the browser to verify whether the integration is successful

 Mapped "{[/v2/api-docs],methods=[GET],produces=[application/json || application/hal+json]}" 
 http://localhost:8080/v2/api-docs
Copy the code

Multi-environment Configuration

Application research and development process of multiple environments is inevitable, assuming that we now have development, presentation, production three different environment configuration is also different, if every time in the packaging link to configure the inevitable error, SpringBoot support by command to start different environments, However, the configuration file must meet the format of application-{profile}. Properties. Profile indicates the id of the corresponding environment.

Properties: application-dev. Properties: application-test. Properties: application-prod.properties: Production environment # Run the demo environment command Java -jar spring-boot-example-0.0.1 -snapshot --spring.profiles.active=testCopy the code

Yml, application-test. Yml and application-prod. Yml. Put the unchanging public configuration, such as most of druid, the PageHelper paging plug-in, and the Mybatis package scanning configuration, into application.yml, and configure the default development environment in application.yml. If you do not start the application with –spring.profiles.active, the application will start in the development environment by default

Spring: Profiles: # Uses the development environment active: dev by defaultCopy the code

Configuration here our project directory structure looks like the figure below




SRC /main/ Java directory structure




SRC /main/resources directory structure

So far we have completed the integration of Mybatis, Swagger2 and multi-environment respectively. Next we configure logger in multi-environment. For logger we always hope that in the process of project research and development, the more the better, can give enough information to locate the bug, the project is in a state of presentation or online to keep log printed affect application performance we only need a warning or error log, and need to write to the file, then the next based on logback logging configuration to realize more environment

Log configuration in multiple environments

Create logback-spring. XML in the same directory as application.yml. For Springboot, it is recommended to use logback-spring. XML instead of logback. XML

<? The XML version = "1.0" encoding = "utf-8"? > <configuration scan="true" scanPeriod="60 seconds" debug="false"> <! -- Brief description Log format => %d{HH:mm: ss.sss}(time) [%-5level](log level) % Logger {36}(Maximum 36 characters in logger name, - % MSG %n(specific log information and newline) Development environment => ${basepackage} package console print DEBUG level and above, other package console print INFO level and above demo (test) environment => ${basepackage} Console for package printing at INFO level or higher, console for other packages and file printing at WARN level or higher in production environments => Console and file printing at ERROR level or higher Log files are generated as follows: File generation directory => ${logdir} Log file name of the current day => ${appName}. Log Log file name of other times => ${AppName}.%d{YYYY-MM-DD}. Maximum reserved => ${maxdays} days --> <! -- Custom parameters --> <! <property name="maxsize" value="30MB" /> <! <property name=" maxDays "value="90" /> <! --application. Yml pass parameters --> <! <springProperty scope="context" name="logdir" source="resources. Logdir "/> <! <springProperty scope="context" name=" appName "source=" resources.appName "/> <! <springProperty scope="context" name="basepackage" source="resources. Basepackage "/> <! - the output to the console ConsoleAppender - > < appender name = "consoleLog" class = "ch. Qos. Logback. Core. ConsoleAppender" > <! - display format layout - > < layout class = "ch. Qos. Logback. Classic. PatternLayout" > < pattern > < pattern > % d {HH: mm: ss. SSS} [% 5 level] %logger{36} - %msg%n</pattern> </pattern> </layout> </appender> <! - the output to a file FileAppender - > < appender name = "fileLog" class = "ch. Qos. Logback. Core. Rolling. RollingFileAppender" > <! If there is both <File> and <FileNamePattern>, then the current log is <File>, and tomorrow it will automatically rename today's log to today's date. That is, the logs in <File> are from the current day. --> <File>${logdir}/${appname}.log</File> <! - rolling strategy, according to the time rolling TimeBasedRollingPolicy -- > < rollingPolicy class = "ch. Qos. Logback. Core. Rolling. TimeBasedRollingPolicy" > <! File path, which defines how to split logs -- archive logs for each day into a file to prevent logs from filling the disk space --> <FileNamePattern>${logdir}/${appname}.%d{yyyy-MM-dd}.log</FileNamePattern> <maxHistory>${maxdays}</maxHistory> <totalSizeCap>${maxsize}</totalSizeCap> </rollingPolicy> <! <encoder> <charset>UTF-8</charset> <pattern>%d{HH:mm: ss.sss} [%-5level] % Logger {36} - % MSG %n</pattern> </encoder> </appender> <! <springProfile name="dev"> <root level="INFO"> <appender-ref ref="consoleLog"/> </root> <! Additivity is the flag bit of whether the child Logger inherits the parent Logger's output source (appender). Additivity is set to false to print the child looger if there are INFO level logs in ${basepackage} > <logger name="${basepackage}" level="DEBUG" additivity="false"> <appender-ref ref="consoleLog"/> </logger> </springProfile> <! --> <springProfile name="test"> <root level="WARN"> <appender-ref ref="consoleLog"/> <appender-ref ref="fileLog"/> </root> <logger name="${basepackage}" level="INFO" additivity="false"> <appender-ref ref="consoleLog"/> <appender-ref ref="fileLog"/> </logger> </springProfile> <! -- Production environment --> <springProfile name="prod"> <root level="ERROR"> <appender-ref ref="consoleLog"/> <appender-ref ref="fileLog"/> </root> </springProfile> </configuration>Copy the code

Yml consists of logdir, AppName, and basepackage. Logdir is the address for writing log files and can be passed to a relative path. Appname is the application name. Basepackage is a packet filtering configuration. For example, in the development environment, logs of higher debug level need to be printed, but if you want to prevent the debug from being printed except for the logger I wrote, you can filter the package name of this project and print the debug. In addition, the package name is printed at the INFO level. Create these three configurations in application.yml and configure different properties in different environments

# appname: spring-boot-example # basepackage: com.spring.demo.springbootexampleCopy the code

Use different environments to test whether the Logger configuration takes effect. In the development environment, four logger records at DEBUG level or higher are printed, in the demo environment, three logger records at INFO level or higher are printed and written to the file, and in the production environment, only one logger record at ERROR level or higher is printed and written to the file

@requestMapping ("/logger") @responseBody public WebResult Logger () {logger.trace(" log output {}", "trace"); Logger. debug(" log output {}", "debug"); Logger. info(" log output {}", "info"); Logger. warn(" log output {}", "warn"); Logger. error(" log output {}", "error"); return "00"; }Copy the code

Commonly used configuration

Load a custom configuration
@Component @PropertySource(value = {"classpath:application.yml"}, encoding = "utf-8") public class Config { @Value("${resources.midpHost}") private String midpHost; public String getMidpHost() { return midpHost; }}Copy the code
Global exception handler
@ControllerAdvice public class GlobalExceptionResolver { Logger logger = LoggerFactory.getLogger(GlobalExceptionResolver.class); @ExceptionHandler(value = Exception.class) @ResponseBody public WebResult exceptionHandle(HttpServletRequest req, Exception ex) { ex.printStackTrace(); Logger. error(" unknown exception ", ex); return WebResult.error(ERRORDetail.RC_0401001); }}Copy the code

Example project open source address

github