SpringBoot basic learning

Posted by olechka on Mon, 17 Jan 2022 06:26:14 +0100


reference resources Crazy God says springboot

Introduction to SpringBoot

Review what Spring is

The lightweight Java development framework is created to solve the complexity of enterprise application development and simplify development.

How does Spring simplify Java development

In order to reduce the complexity of Java development, Spring adopts the following four key strategies:

  1. Lightweight and minimally intrusive programming based on POJO, everything is bean;
  2. Loose coupling is realized through IOC, dependency injection (DI) and interface oriented;
  3. Declarative programming based on AOP and conventions;
  4. Reduce style codes through facets and templates, RedisTemplate and xxtemplate;

What is SpringBoot

Students who have studied javaweb know that developing a web application, starting from the initial contact with Servlet combined with Tomcat and running a Hello Wolrld program, requires a lot of steps; Later, I used the framework Struts, and then spring MVC. Now, with spring boot, other web frameworks will appear in a year or two; Have you ever experienced the continuous evolution of the framework, and then developed your own projects, and all technologies are constantly changing and transforming? Suggestions can be experienced again;

To get back to business, what is SpringBoot? It is a java web development framework, which is similar to spring MVC. Compared with the benefits of other Java Web frameworks, it is officially said that it simplifies development, conventions are greater than configuration, and you can "just run", which can quickly develop web applications and develop an http interface with a few lines of code.

The development of all technical frameworks seems to follow a main line law: a normative framework is derived from a complex application scenario. People only need to make various configurations without realizing it by themselves. At this time, the powerful configuration function becomes an advantage; After a certain degree of development, people have chosen some practical functions and design essence to reconstruct some lightweight frameworks based on actual production and application. Later, in order to improve development efficiency, they disliked that the original configurations were too troublesome, so they began to advocate "agreement is greater than configuration", and then derived some one-stop solutions.

Yes, this is the process of Java enterprise application - > J2EE - > spring - > springboot.

With the continuous development of spring, more and more fields are involved. The project integration development needs to cooperate with a variety of files, which gradually becomes less easy to use and simple, contrary to the original concept, and even called configuration hell. Spring Boot is a development framework abstracted under such a background. The purpose is to make it easier for everyone to use spring and integrate various common middleware and open source software;

Spring Boot is developed based on spring. Spring Boot itself does not provide the core features and extension functions of the spring framework, but is only used to quickly and quickly develop a new generation of applications based on the spring framework. In other words, it is not a solution to replace spring, but a tool closely combined with the spring framework to improve the spring developer experience. Spring Boot takes the core idea that convention is greater than configuration. By default, it helps us make a lot of settings. Most Spring Boot applications only need a few spring configurations. At the same time, it integrates a large number of commonly used third-party library configurations (such as Redis, MongoDB, Jpa, RabbitMQ, Quartz, etc.), which can be used out of the box with almost zero configuration in Spring Boot applications.

Simply put, spring boot is not a new framework. It configures the use of many frameworks by default, just as maven integrates all jar packages and spring boot integrates all frameworks.

Spring Boot was born in a famous family. From the beginning, it stood at a relatively high starting point. After several years of development, the ecology is perfect enough. Spring Boot has become the hottest technology in the Java field.

Main advantages of Spring Boot:

  • Get started faster for all Spring developers
  • Out of the box, various default configurations are provided to simplify project configuration
  • Inline containers simplify Web projects
  • There are no requirements for redundant code generation and XML configuration

Architecture mode

Single application architecture

all in one, all application services of an application are encapsulated in one application, and various functions such as database access and web access are put into one war

  • Advantages: it is convenient for development, testing and deployment. When expansion is needed, you only need to copy multiple copies of war to different servers
  • Disadvantages: if you change a small place, you also need to stop the whole service and repackage and deploy

Microservice architecture

Breaking the all in one mode and separating each functional element is to copy the functional element rather than the whole application. The required functions are dynamically combined

  • Benefits: save calling resources, and each function element is a replaceable and independently upgradeable part

Create project preliminary

preparation

  • java version "1.8.0_181"
  • Maven-3.6.1
  • SpringBoot 2.x latest edition

Create project

Spring officially provides a very convenient tool for us to quickly build applications
Spring Initializr: https://start.spring.io/

Method 1: create a project using the Web page of Spring Initializr

	1. open https://start.spring.io/
	2. Fill in project information
	3. Click Generate Project"Button to generate a project; Download this item
	4. Unzip the project package and use IDEA with Maven Import the project and go to the next step until the project is imported.
	5. If it is used for the first time, the speed may be slow, there are many packages, and you need to wait patiently for everything to be ready.

Method 2: directly create a project using IDEA

	1. Create a new project
	2. choice spring initalizr , You can see that the default is to go to the quick build tool on the official website
	3. Fill in project information
	4. Select the initialized component (check for beginner) Web (OK)
	5. Fill in the project path
	6. Wait for the project to build successfully

Through the above steps, the basic project is created. The following files will be automatically generated.

	Main startup class of the program XXXXAppication Program main entrance
	One application.properties Core profile
	A test class 
	One pom.xml

pom.xml

<!-- Parent dependency, version control and packaging-->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/>
</parent>

<dependencies>
    <!-- web Dependence, tomcat As the default embedded container, dispatcherservlet ,xml.... realization http Interface, including spring mvc->
    <!-- It's a web starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- springboot unit testing  -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
		<!-- springboot All dependencies are spring-boot-starter initial  -->
        <!-- Eliminate dependency -->
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

Build configuration and print jar package
<build>
    <plugins>
        <!-- Package plug-ins -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

First interface

  1. Create a new controller package in the same level directory of the main program. It must be in the same level directory, otherwise it will not be recognized
  2. Create a new HelloController class in the package
	@RestController
	public class HelloController {
	    @RequestMapping("/hello")
	    public String hello() {
	        return "Hello World";
	    }
	}
  1. After writing, start the project from the main program, launch the request from the browser, and see the page return; The console outputs the port number accessed by Tomcat!
  2. package can be packaged in the maven menu bar of the idea sidebar, and the project can be run by directly entering the following code in the command line
	java -jar jar Drag the bag here

Easter egg

  • Change access port number
	application.properties Set in file
	sever.port=8081
  • Change the letters formed by the characters displayed at startup, and create a new banner under the resources directory under the project Txt, and the pattern can be to: https://www.bootschool.net/ascii The website is generated and then copied to a file

principle

Parent dependency

It mainly depends on a parent project, which mainly manages the resource filtering and plug-ins of the project

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

Click in and find another parent dependency. This is the place to really manage all dependent versions in the SpringBoot application. The version control center of SpringBoot;
In the future, we will import dependency. By default, we don't need to write a version; However, if the imported package is not managed in the dependency, you need to manually configure the version

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent>

Launcher spring boot starter

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

Springboot boot starter XXX: the scenario initiator of spring boot

Spring boot starter Web: it helps us import the components that the web module depends on for normal operation;

SpringBoot extracts all functional scenarios and makes them into starters. You only need to introduce these starters into the project, and all related dependencies will be imported. We can import the scenario starters with what functions we want to use; We can also customize the starter ourselves in the future;

Startup class

//@Spring bootapplication to annotate a main program class
//This is a Spring Boot application
@SpringBootApplication
public class SpringbootApplication {

   public static void main(String[] args) {
     //Start the springboot application
      SpringApplication.run(SpringbootApplication.class, args);
   }
}

Important notes

@SpringBootApplication

Function: mark a class to indicate that this class is the main configuration class of SpringBoot. SpringBoot should run the main method of this class to start the SpringBoot application;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

Enter this annotation: you can see that there are many other annotations above!

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {
    // ......
}

@ComponentScan

This annotation is important in Spring and corresponds to the elements in the XML configuration.

Function: automatically scan and load qualified components or beans, and load the bean definition into the IOC container

@SpringBootConfiguration

Function: the configuration class of SpringBoot is marked on a class to indicate that it is a SpringBoot configuration class;
Let's move on to this annotation

// Click @ Configuration to get the following @ Component
@Configuration
public @interface SpringBootConfiguration {}

@Component
public @interface Configuration {}

The @ Configuration here indicates that this is a Configuration class, which is the xml Configuration file corresponding to Spring;

The @ Component inside shows that the startup class itself is just a Component in Spring and is responsible for starting the application!

Let's go back to the spring boot application annotation and continue.

@EnableAutoConfiguration

Turn on the auto configuration function. We used to configure things ourselves, but now SpringBoot can automatically configure them for us@ EnableAutoConfiguration tells SpringBoot to enable the auto configuration function so that the auto configuration can take effect;

Click in the annotation to continue viewing:

@AutoConfigurationPackage

Auto configuration package

@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}

@import : Spring Underlying annotation@import , Import a component into the container
Registrar.class Function: scan all components in the package of the main startup class and all sub packages below the package to Spring Containers;
@Import({AutoConfigurationImportSelector.class})

Import components to the container, AutoConfigurationImportSelector: automatically configure the import selector

AutoConfigurationImportSelector.class

// Obtain candidate configurations
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    //The getSpringFactoriesLoaderFactoryClass () method here
    //The returned annotation class is the annotation class that we first saw to start the automatic import configuration file; EnableAutoConfiguration
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}
Method called SpringFactoriesLoader.loadFactoryNames()

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    //Here it calls the loadSpringFactories method again
    return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
Method called loadSpringFactories(classLoader).getOrDefault()

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    //After obtaining the classLoader, we can see that what we get here is the class itself marked with EnableAutoConfiguration
    MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
    if (result != null) {
        return result;
    } else {
        try {
            //Go to get a resource "META-INF/spring.factories"
            Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
            LinkedMultiValueMap result = new LinkedMultiValueMap();

            //Traverse the read resources and encapsulate them into a property
            while(urls.hasMoreElements()) {
                URL url = (URL)urls.nextElement();
                UrlResource resource = new UrlResource(url);
                Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                Iterator var6 = properties.entrySet().iterator();

                while(var6.hasNext()) {
                    Entry<?, ?> entry = (Entry)var6.next();
                    String factoryClassName = ((String)entry.getKey()).trim();
                    String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                    int var10 = var9.length;

                    for(int var11 = 0; var11 < var10; ++var11) {
                        String factoryName = var9[var11];
                        result.add(factoryClassName, factoryName.trim());
                    }
                }
            }

            cache.put(classLoader, result);
            return result;
        } catch (IOException var13) {
            throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13);
        }
    }
}

Found a multiple occurrence file: spring Factories, search it globally

spring.factories

The root of automatic configuration is at org springframework. boot. autoconfigure. Package

Let's open any one of the automatic configuration classes above, such as webmvcoautoconfiguration

You can see that these are JavaConfig configuration classes one by one, and some beans are injected

The real implementation of automatic Configuration is to search for all meta-inf / spring from the classpath Factories Configuration file, and the corresponding org. Org springframework. Boot: the Configuration items under the spring boot autoconfigure package are instantiated into IOC container Configuration classes in the form of JavaConfig marked with @ Configuration through reflection, and then these are summarized into an instance and loaded into the IOC container

conclusion

  • SpringBoot starts from meta-inf / spring. Inf in the classpath Get the class specified by EnableAutoConfiguration from factories
  • Import these classes into the container as automatic configuration classes, and the automatic configuration classes will take effect to help us with automatic configuration
  • The overall solution and automatic configuration of the whole J2EE are at org springframework. Boot: in the jar package of spring boot autoconfigure
  • It will import many automatic configuration classes (xxxAutoConfiguration) into the container, that is, import all the components required for this scenario into the container and configure these components
  • With the automatic configuration class, it eliminates the work of manually writing configuration injection function components

main method of SpringBoot

In fact, it is not only running a main method, but also starting a service

@SpringBootApplication
public class SpringbootApplication {
    public static void main(String[] args) {
        //The run method is actually an instantiation of springApplication. The second is the execution of the run method
        SpringApplication.run(SpringbootApplication.class, args);
    }
}

SpringApplication

This class mainly does the following four things:

  1. Infer whether the type of application is a normal project or a Web project
  2. Find and load all available initializers and set them in the initializers property
  3. Find all application listeners and set them to the listeners property
  4. Infer and set the definition class of the main method, and find the main class to run
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    // ......
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.setInitializers(this.getSpringFactoriesInstances();
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

yaml syntax configuration

YAML is a recursive abbreviation for "YAML Ain't a Markup Language". When developing this language, YAML actually means "Yet Another Markup Language"

Application is not officially recommended Properties file. Application. Is recommended YML configuration mode

  • application.properties
    Syntax structure: key=value
  • application.yml
    Syntax structure: key: space value
tradition xml to configure
	<server>
	    <port>8081<port>
	</server>
	
yaml to configure
	server: 
	  prot: 8080

yaml basic syntax

  1. Spaces cannot be omitted
  2. The hierarchical relationship is controlled by indentation. As long as a column of data aligned on the left is at the same level
  3. Attributes and values are case sensitive
  4. Literal: normal value [number, Boolean, string]
  5. The literal quantity can be written directly after the string. By default, double quotation marks or single quotation marks are not added to the string

be careful:

  • "" double quotation marks will not escape the special characters in the string. The special characters will be used as the meaning they want to express
    For example: name: "kuang \n shen" output: kuang newline shen
  • '' single quotation mark will escape special characters, and the special characters will eventually be output as ordinary characters
    For example: name: 'kuang \n shen' output: kuang \n shen
 # Object, Map key value pair format
	 k: 
	 	v1:
	 	v2:
 
 # object
	 student:
	 	name: zhangsan
	 	age: 3

	student: {name: zhangsan,age: 3}	Inline writing

#array
	pets:
		- cat
		- dog
	
	pets: [cat,dog]		Inline writing
modify springboot Default port number for
	server:
		port: 8082

Legacy injection profile

yaml file is more powerful because it can directly inject matching values into our entity classes!

  1. Create a new file application. In the resources directory of the springboot project yml

  2. Write an entity class Dog and use @ Value to inject attribute values into the bean as before

    package com.kuang.springboot.pojo;
    
    @Component  //Register bean s into the container
    public class Dog {
     	@Value("Ah Huang")
        private String name;
        @Value("11")
        private Integer age;
        
        //Parameterless construction, get, set method, toString() method  
    }
    
  3. Inject and output the dog under the test class of SpringBoot;

    @SpringBootTest
    class DemoApplicationTests {
    
        @Autowired //Inject the dog automatically
        Dog dog;
    
        @Test
        public void contextLoads() {
            System.out.println(dog); //Print and look at the dog object
        }
    }
    

yaml injection profile

  1. Write a more complex entity class: Person class. Note that it can't be injected without get and set methods

    @Component //Register bean s into the container
    public class Person {
        private String name;
        private Integer age;
        private Boolean happy;
        private Date birth;
        private Map<String,Object> maps;
        private List<Object> lists;
        private Dog dog;
        
        //Parameterless construction, get, set method, toString() method  
    }
    
  2. Use yaml configuration for injection. When you write, pay attention to the differences and advantages. We write a yaml configuration

    # Strings in yaml can be parsed automatically without double quotes
    
    person:
      name: qinjiang
      age: 3
      happy: false
      birth: 2000/01/01
      maps: {k1: v1,k2: v2}
      lists:
       - code
       - girl
       - music
      dog:
        name: Wangcai
        age: 1
    
  3. Inject into our class

    /*
    @ConfigurationProperties effect:
    Map the value of each attribute configured in the configuration file to this component;
    Tell SpringBoot to bind all properties in this class to the relevant configuration in the configuration file
     Parameter prefix = "person": match all attributes under person in the configuration file one by one
    */
    @Component //Register bean
    @ConfigurationProperties(prefix = "person")
    public class Person {
        private String name;
        private Integer age;
        private Boolean happy;
        private Date birth;
        private Map<String,Object> maps;
        private List<Object> lists;
        private Dog dog;
    }
    
  4. IDEA prompts that the spring boot configuration annotation processor is not found. Let's look at the document. We can look at the document and find a dependency

    <!-- After importing the configuration file processor, you will be prompted to restart the configuration file binding -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
    </dependency>
    
  5. After confirming that the above configurations are OK, let's test them in the test class

    @SpringBootTest
    class DemoApplicationTests {
    
        @Autowired
        Person person; //Inject person automatically
    
        @Test
        public void contextLoads() {
            System.out.println(person); //Print person information
        }
    }
    

Custom profile file name

  1. Let's create a new person in the resources directory Properties file

  2. Then specify in our code to load person Properties file

    @PropertySource : Load the specified configuration file;
    @configurationProperties: Get the value from the global configuration file by default;
    
    @PropertySource(value = "classpath:person.properties")
    @Component //Register bean
    public class Person {
    
        @Value("${name}")
        private String name;
        ......  
    }
    

Placeholders for yaml configuration files

person:
    name: qinjiang${random.uuid} # Random uuid
    age: ${random.int}  # Random int
    happy: false
    birth: 2000/01/01
    maps: {k1: v1,k2: v2}
    lists: [code,girl,music]
    dog:
      name: ${person.hello:other}_Wangcai	If person of hello If the property is empty, the other,output other_Wangcai, otherwise output hello Corresponding attribute value_Wangcai
      age: 1

Traditional properties injection configuration file

When writing the properties configuration file in Chinese, there will be garbled codes. We need to set settings in IDEA – > configure the encoding format in fileencodings as UTF-8

  1. Create a new entity class User

    @Component //Register bean
    public class User {
        private String name;
        private int age;
        private String sex;
    }
    
  2. Edit profile user properties

    user1.name=kuangshen
    user1.age=18
    user1.sex=male
    
  3. Use @ Value on the User class for injection

    @Component //Register bean
    @PropertySource(value = "classpath:user.properties")
    public class User {
        //Use @ value directly
        @Value("${user.name}") //Take value from configuration file
        private String name;
        @Value("#{9*2}")  // #{SPEL} Spring expression
        private int age;
        @Value("male")  // Literal 
        private String sex;
    }
    

yaml and properties comparison

  1. @ConfigurationProperties only needs to be written once, @ Value needs to be added to each field
  2. Loose binding: what does that mean? For example, the last name written in my yml is the same as lastName, and the letters followed by - are capitalized by default. This is loose binding
  3. JSR303 data verification, that is, we can add a layer of filter verification in the field to ensure the legitimacy of the data
  4. Complex type encapsulation. Objects can be encapsulated in yml, but value is not supported

Summary:

  • If we only need to obtain a value in the configuration file in a business, we can use @ value;
  • If we have specially written a JavaBean to map one by one with the configuration file, we can directly @ configurationProperties. Don't hesitate

JSR303 data verification and multi environment switching

JSR303 data verification

In Springboot, @ validated can be used to verify the data. If the data is abnormal, exceptions will be thrown uniformly to facilitate the unified processing of the exception center. Let's write a comment here so that our name can only support Email format

@Component //Register bean
@ConfigurationProperties(prefix = "person")
@Validated  //data verification 
public class Person {

    @Email(message="Mailbox format error") //name must be in mailbox format
    private String name;
}
Common parameters: note and @Validate use

@NotNull(message="Name cannot be empty")
private String userName;
@Max(value=120,message="The oldest can't check 120")
private int age;
@Email(message="Mailbox format error")
private String email;

Empty check
@Null       Verify that the object is null
@NotNull    Verify that the object is not null, Cannot check string with length 0
@NotBlank   Check whether the constraint string is Null And by Trim Is the length greater than 0,String only,And the front and back spaces will be removed.
@NotEmpty   Check whether the constraint element is NULL Or EMPTY.
    
Booelan inspect
@AssertTrue     verification Boolean Whether the object is true  
@AssertFalse    verification Boolean Whether the object is false  
    
Length check
@Size(min=, max=) Validation object( Array,Collection,Map,String)Is the length within the given range  
@Length(min=, max=) String length is between min and max included.

Date check
@Past       verification Date and Calendar Is the object before the current time  
@Future     verification Date and Calendar Is the object after the current time  
@Pattern    verification String Whether the object conforms to the rules of regular expressions

.......wait
 In addition, we can also customize some data verification rules

Multi profile

properties multi file configuration

When we write the main configuration file, the file name can be application - {profile} Properties / YML, used to specify multiple environment versions

application-test.properties Represents the test environment configuration
application-dev.properties Represents the development environment configuration

However, Springboot does not start these configuration files directly. It uses application. Com by default Properties master configuration file;

We need to select the environment to be activated through a configuration

#For example, if the dev environment is specified in the configuration file, we can test by setting different port numbers;
#When we start SpringBoot, we can see that the configuration has been switched to dev;
spring.profiles.active=dev

yaml multi document block configuration

It is the same as in the properties configuration file, but it is more convenient to use yml to implement it without creating multiple configuration files

If both yml and properties are configured with ports and no other environment is activated, the properties configuration file will be used by default

server:
  port: 8081
#Select the environment block to activate
spring:
  profiles:
    active: prod

---
server:
  port: 8083
spring:
  profiles: dev #Name of the configuration environment


---

server:
  port: 8084
spring:
  profiles: prod  #Name of the configuration environment

Load location of configuration file

springboot startup will scan the application at the following location Properties or application The YML file is used as the default configuration file for Spring boot

The priority is from high to bottom, and the high priority configuration will overwrite the low priority configuration

Priority 1: under the project path config Folder profile
 Priority 2: configuration file under project path
 Priority 3: resource path resources Lower config Folder profile
 Priority 4: resource path resources Next profile

Automatic configuration principle

xxxxAutoConfiguration

We take Http encoding autoconfiguration (Http encoding autoconfiguration) as an example to explain the principle of autoconfiguration

//Indicates that this is a configuration class. Like the previously written configuration file, you can also add components to the container;
@Configuration 

//Start the ConfigurationProperties function of the specified class;
  //Enter the HttpProperties view and bind the corresponding values in the configuration file with HttpProperties;
  //And add HttpProperties to the ioc container
@EnableConfigurationProperties({HttpProperties.class}) 

//Spring underlying @ Conditional annotation
  //According to different conditions, if the specified conditions are met, the configuration in the whole configuration class will take effect;
  //This means to judge whether the current application is a web application. If so, the current configuration class will take effect
@ConditionalOnWebApplication(
    type = Type.SERVLET
)

//Judge whether the current project has this class CharacterEncodingFilter; Filter for garbled code resolution in spring MVC;
@ConditionalOnClass({CharacterEncodingFilter.class})

//Determine whether a configuration exists in the configuration file: spring http. encoding. enabled;
  //If it does not exist, the judgment is also valid
  //Even if we don't configure spring in our configuration file http. encoding. Enabled = true, which is also effective by default;
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)

public class HttpEncodingAutoConfiguration {
    //He has mapped to the SpringBoot configuration file
    private final Encoding properties;
    //When there is only one constructor with parameters, the value of the parameter will be taken from the container
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }
    
    //Add a component to the container. Some values of this component need to be obtained from properties
    @Bean
    @ConditionalOnMissingBean //Determine that the container does not have this component?
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }
    //. . . . . . . 
}

One sentence summary: determine whether this configuration class is effective according to different current conditions!

  • Once this configuration class takes effect; This configuration class will add various components to the container
  • The properties of these components are obtained from the corresponding properties classes, and each property in these classes is bound to the configuration file
  • All properties that can be configured in the configuration file are encapsulated in the xxproperties class
  • The attribute class corresponding to a function can be referenced for what can be configured in the configuration file
//Get the specified value from the configuration file and bind it with the properties of the bean
@ConfigurationProperties(prefix = "spring.http") 
public class HttpProperties {
    // .....
}

Try the prefix in the configuration file
)

Summary:

  1. SpringBoot boot will load a large number of auto configuration classes
  2. See if the functions we need are in the auto configuration class written by SpringBoot by default
  3. Let's see which components are configured in this auto configuration class; (as long as the component we want to use exists in it, we don't need to configure it manually)
  4. When adding components to the automatic configuration class in the container, some properties will be obtained from the properties class. We only need to specify the values of these attributes in the configuration file
  • Xxxautoconfiguration: automatically configure classes and add components to containers
  • Xxxproperties: encapsulates the related properties in the configuration file

What exactly did springboot configure for me?

  • xxxAutoConfiguration: automatically configure components into containers
  • xxxProperties: automatic configuration class, custom content in assembly coordination file

@Conditional

The automatic configuration class can only take effect under certain conditions, @ Conditional function: only when the conditions specified by @ Conditional are true can components be added to the container, and all contents in the configuration can take effect
So many auto configuration classes can only take effect under certain conditions; In other words, we loaded so many configuration classes, but not all of them took effect

You can enable the debug=true attribute; To let the console print the automatic configuration report, so that we can easily know which automatic configuration classes are effective

#Open the debugging class of springboot
debug=true

Positive matches:(Auto configuration class enabled: positive match)
Negative matches:(No startup, no matching successful automatic configuration class: negative matching)
Unconditional classes: ((class without condition)

Static resources in SpringBoot

How to access static resources

The essence of Webjars is to introduce our static resources in the form of jar package. We used to import a static resource file directly

  • Find the dependency injection pom file on the webjars website (in the dependency package): localhost: 8080 / webjars / jQuery / 3.6.0 / jQuery js

  • public, static, / * *, resources (under the project path): localhost: 8080 / love html


Source code analysis

WebMvcAutoConfiguration. Source code analysis in class file

public void addResourceHandlers(ResourceHandlerRegistry registry) {
	//If the configuration file has its own configuration, the static resources are stored in the user-defined path, and the default configuration is invalid
    if (!this.resourceProperties.isAddMappings()) {
         logger.debug("Default resource handling disabled");
     } else {
     //Add static resources to / META-INF/resources/webjars / * * folder
         this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
         this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
            //getStaticPathPattern obtains the static resource path and clicks into resourceProperties
           registration.addResourceLocations(this.resourceProperties.getStaticLocations());
             if (this.servletContext != null) {
                 ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
                 //Add static resources to the resource object configuration folder
                 registration.addResourceLocations(new Resource[]{resource});
             }

         });
     }
}
Point entry resourceProperties,It is WebMvcAutoConfiguration Class WebMvcAutoConfigurationAdapter()Method, continue to click in, yes WebProperties A static inner class of
public static class Resources {
		//The following code is the specified static resource storage path
		//Priority: Resources > static (default) > public
        private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
       ......

        public Resources() {
            this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
            ......
        }

Summary: the static resources stored in the following four directories can be identified by us, such as our access http://localhost:8080/1.js Then he will go to these folders to find the corresponding static resource files

"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"

Custom static resource path

We can also specify which folders we need to put static resource files through the configuration file. In application Configuration in properties

Once you define the path of the static folder, the original automatic configuration will become invalid

spring.resources.static-locations=classpath:/coding/,classpath:/kuang/

Thymeleaf template engine

template engine

The page given to us by the front end is an html page. If we developed them before, we need to turn them into JSP pages. The advantage of JSP is that when we find out that some data is forwarded to JSP pages, we can easily realize data display and interaction with JSP.

jsp supports very powerful functions, including the ability to write Java code. However, in our current situation, the SpringBoot project first uses jar instead of war. Second, we still use embedded Tomcat. Therefore, it does not support jsp by default.

It does not support jsp. If we directly use pure static pages, it will bring us great trouble in development. What should we do?

SpringBoot recommends that you use the template engine:

In fact, we have heard a lot about template engines. In fact, jsp is a template engine, and freemaker, which is widely used, including Thymeleaf recommended by SpringBoot. There are many template engines, but no matter how many template engines, their ideas are the same. What kind of ideas? Let's take a look at this figure:

The function of the template engine is that we write a page template. For example, some values are dynamic. We write some expressions. Where do these values come from? We encapsulate some data in the background. Then give the template and the data to our template engine. The template engine will help you parse and fill the expression to the position we specify according to our data, and then finally generate a content we want to write to us. This is our template engine, whether jsp or other template engines.

The Thymeleaf template engine recommended by SpringBoot is a high-level language template engine with simpler syntax. And it's more powerful.

Introduction of Thymeleaf

Thymeleaf official website: https://www.thymeleaf.org/

Thymeleaf's home page at Github: https://github.com/thymeleaf/thymeleaf

Spring official documentation: find our corresponding version

https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter

To the corresponding pom dependency: you can click the source code to see the original package!

<!--thymeleaf-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Thymeleaf analysis

@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    //Just put our html page under the templates under the classpath, and thymeleaf can help us render automatically
    //Static resource file prefix
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    //Static resource file suffix
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";
    private Charset encoding;
}

test

  1. Write a TestController
@Controller
public class TestController {
    
    @RequestMapping("/t1")
    public String test1(){
        //classpath:/templates/test.html
        return "test";
    }
}
  1. Write a test page test Html is placed in the templates directory
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>Test page</h1>

</body>
</html>

Thymeleaf grammar learning

Thymeleaf official website: https://www.thymeleaf.org/

  1. Modify the test request and add data transmission
@RequestMapping("/t1")
public String test1(Model model){
    //Store data
    model.addAttribute("msg","Hello,Thymeleaf");
    //classpath:/templates/test.html
    return "test";
}
  1. Write the next front page
<!DOCTYPE html>
// Import namespace constraints to facilitate prompt
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Madness theory</title>
</head>
<body>
<h1>Test page</h1>

<!--th:text Is to div The content in is set to the value it specifies, and the previous learning Vue equally-->
<div th:text="${msg}"></div>
</body>
</html>
  1. Start test

Common syntax:

expression:

Simple expressions:(Expression syntax)
Variable Expressions: ${...}: Obtain variable value; OGNL;
    1),Get the properties and call methods of the object
    2),Use built-in base objects:#18
         #ctx : the context object.
         #vars: the context variables.
         #locale : the context locale.
         #request : (only in Web Contexts) the HttpServletRequest object.
         #response : (only in Web Contexts) the HttpServletResponse object.
         #session : (only in Web Contexts) the HttpSession object.
         #servletContext : (only in Web Contexts) the ServletContext object.

    3),Some built-in tool objects:
      #execInfo : information about the template being processed.
      #uris : methods for escaping parts of URLs/URIs
      #conversions : methods for executing the configured conversion service (if any).
      #dates : methods for java.util.Date objects: formatting, component extraction, etc.
      #calendars : analogous to #dates , but for java.util.Calendar objects.
      #numbers : methods for formatting numeric objects.
      #strings : methods for String objects: contains, startsWith, prepending/appending, etc.
      #objects : methods for objects in general.
      #bools : methods for boolean evaluation.
      #arrays : methods for arrays.
      #lists : methods for lists.
      #sets : methods for sets.
      #maps : methods for maps.
      #aggregates : methods for creating aggregates on arrays or collections.
==================================================================================

  Selection Variable Expressions: *{...}: Select expressions: and ${}It is the same in function;
  Message Expressions: #{...}:  Get international content
  Link URL Expressions: @{...}: definition URL;
  Fragment Expressions: ~{...}: Fragment reference expression

Literals((literal)
      Text literals: 'one text' , 'Another one!' ,...
      Number literals: 0 , 34 , 3.0 , 12.3 ,...
      Boolean literals: true , false
      Null literal: null
      Literal tokens: one , sometext , main ,...
      
Text operations:((text operation)
    String concatenation: +
    Literal substitutions: |The name is ${name}|
    
Arithmetic operations:(Mathematical operation)
    Binary operators: + , - , * , / , %
    Minus sign (unary operator): -
    
Boolean operations:(Boolean operation)
    Binary operators: and , or
    Boolean negation (unary operator): ! , not
    
Comparisons and equality:(Comparison operation)
    Comparators: > , < , >= , <= ( gt , lt , ge , le )
    Equality operators: == , != ( eq , ne )
    
Conditional operators:Conditional operation (ternary operator)
    If-then: (if) ? (then)
    If-then-else: (if) ? (then) : (else)
    Default: (value) ?: (defaultvalue)
    
Special tokens:
    No-Operation: _

Test:

  1. Write a Controller and put some data
@RequestMapping("/t2")
public String test2(Map<String,Object> map){
    //Store data
    map.put("msg","<h1>Hello</h1>");
    map.put("users", Arrays.asList("qinjiang","kuangshen"));
    //classpath:/templates/test.html
    return "test";
}
  1. Fetch data from html page
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Madness theory</title>
</head>
<body>
<h1>Test page</h1>

<div th:text="${msg}"></div>
<!--No escape-->
<div th:utext="${msg}"></div>

<!--Traversal data-->
<!--th:each Each traversal will generate the current tag: official website#9-->
<h4 th:each="user :${users}" th:text="${user}"></h4>

<h4>
    <!--In line writing: Official Website#12-->
    <span th:each="user:${users}">[[${user}]]</span>
</h4>

</body>
</html>

SpringBoot: MVC auto configuration principle

We also need to know what configuration SpringBoot has made for our spring MVC, including how to extend and customize it

Official documents: https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#boot-features-spring-mvc-auto-configuration

Spring MVC Auto-configuration

// Spring Boot provides automatic configuration for Spring MVC, which works well with most applications.
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
// Auto configuration adds the following functions based on Spring default settings:
The auto-configuration adds the following features on top of Spring's defaults:
// Include view parser
Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
// Support the path of static resource folder and webjars
Support for serving static resources, including support for WebJars 
// Automatically registered Converter:
// Converter, which is what we automatically encapsulate the data submitted by the web page into objects in the background, such as automatically converting the "1" string to int type
// Formatter: [formatter, for example, the page gives us a 2019-8-10, which will automatically format it as a Date object]
Automatic registration of Converter, GenericConverter, and Formatter beans.
// HttpMessageConverters
// Spring MVC is used to convert Http requests and responses. For example, if we want to convert a User object into a JSON string, you can see the official website document explanation;
Support for HttpMessageConverters (covered later in this document).
// To define error code generation rules
Automatic registration of MessageCodesResolver (covered later in this document).
// Home page customization
Static index.html support.
// icons customizing
Custom Favicon support (covered later in this document).
// Initialize the data binder: help us bind the request data to the JavaBean!
Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document).

/*
If you want to keep the Spring Boot MVC functionality and want to add other MVC configurations (interceptors, formatters, view controllers, and other features), you can add your own
 The @ configuration class of is webmvcconfigurer, but @ EnableWebMvc is not added. If you want to provide
RequestMappingHandlerMapping,RequestMappingHandlerAdapter Or ExceptionHandlerExceptionResolver
 Instance, you can declare a webmvcreationadapter instance to provide such components.
*/
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration 
(interceptors, formatters, view controllers, and other features), you can add your own 
@Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide 
custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or 
ExceptionHandlerExceptionResolver, you can declare a WebMvcRegistrationsAdapter instance to provide such components.

// If you want to fully control Spring MVC, you can add your own @ Configuration and annotate it with @ EnableWebMvc.
If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc

ContentNegotiatingViewResolver content negotiation view resolver

The ViewResolver is automatically configured, which is the view parser of spring MVC we learned earlier;

That is, the View object is obtained according to the return value of the method, and then the View object determines how to render (forward, redirect).

Let's take a look at the source code here: we find webmvca autoconfiguration and search for content negotiatingviewresolver. Find the following methods

@Bean
@ConditionalOnBean(ViewResolver.class)
@ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
    ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
    resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
    // Content negotiatingviewresolver uses all other view parsers to locate views, so it should have higher priority
    resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return resolver;
}
@Nullable // Note: @ Nullable means that the parameter can be null
public View resolveViewName(String viewName, Locale locale) throws Exception {
    RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
    Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
    List<MediaType> requestedMediaTypes = this.getMediaTypes(((ServletRequestAttributes)attrs).getRequest());
    if (requestedMediaTypes != null) {
        // Get candidate view objects
        List<View> candidateViews = this.getCandidateViews(viewName, locale, requestedMediaTypes);
        // Select the most appropriate view object, and then return this object
        View bestView = this.getBestView(candidateViews, requestedMediaTypes, attrs);
        if (bestView != null) {
            return bestView;
        }
    }
    // .....
}

Click getCandidateViews to see that it brings all view parsers, performs a while loop, and parses them one by one

Iterator var5 = this.viewResolvers.iterator();

Conclusion: the content negotiating view resolver is used to combine all view resolvers

Study his combinatorial logic, see that there is an attribute viewResolvers, and see where it is assigned

protected void initServletContext(ServletContext servletContext) {
    // Here it is the parser that gets all the views in the container from the beanFactory tool
    // ViewRescolver.class combines all the view parsers
    Collection<ViewResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.obtainApplicationContext(), ViewResolver.class).values();
    ViewResolver viewResolver;
    if (this.viewResolvers == null) {
        this.viewResolvers = new ArrayList(matchingBeans.size());
    }
    // ...............
}

Customize a view parser

  1. Custom view parser
@Bean //Put in bean
public ViewResolver myViewResolver(){
    return new MyViewResolver();
}

//When we write a static inner class, the view parser needs to implement the ViewResolver interface
private static class MyViewResolver implements ViewResolver{
    @Override
    public View resolveViewName(String s, Locale locale) throws Exception {
        return null;
    }
}
  1. Does the view parser work
    Add a breakpoint to the doDispatch method in the dispatcher servlet for debugging, because all requests will go to this method
  2. We start our project, then visit a page casually, look at the Debug information and find the view parser. We see that our own definition is here

Format converter

Format converter

@Bean
@Override
public FormattingConversionService mvcConversionService() {
    // Get the formatting rules in the configuration file
    WebConversionService conversionService = 
        new WebConversionService(this.mvcProperties.getDateFormat());
    addFormatters(conversionService);
    return conversionService;
}

Click the getDateFormat method

public String getDateFormat() {
    return this.dateFormat;
}

/**
* Date format to use. For instance, `dd/MM/yyyy`. default
 */
private String dateFormat;

You can see that in our Properties file, we can automatically configure it!

If you configure your own formatting method, it will be registered in the Bean and take effect. We can configure the date formatting rules in the configuration file

SpringBoot extension

When spring boot automatically configures many components, first check whether there are user configured components in the container (if the user configures @ bean s), if so, use user configured components, and if not, use automatically configured components

If there are multiple components, such as our view parser, you can combine the user configured with your own default

springboot Expand official documents

If you want to keep Spring Boot MVC features and you want to add additional MVC configuration 
(interceptors, formatters, view controllers, and other features), you can add your
 own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of 
 RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, 
 you can declare a WebMvcRegistrationsAdapter instance to provide such components.

All we need to do is write a @ Configuration annotation class, and the type should be WebMvcConfigurer (implement WebMvcConfigurer), and the @ EnableWebMvc annotation cannot be marked

Let's write one by ourselves; We create a new package called config and write a class MyMvcConfig

//The expected type requires WebMvcConfigurer, so we implement its interface
//You can use custom classes to extend the functionality of MVC
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // When the browser sends / test, it will jump to the test page;
        registry.addViewController("/test").setViewName("test");
    }
}

Extension principle

  • Webmvcoautoconfiguration is the automatic configuration class of spring MVC, which has a class webmvcoautoconfigurationadapter

  • There is an annotation on this class, which will be imported during other automatic configuration: @ Import(EnableWebMvcConfiguration.class)

  • Let's click EnableWebMvcConfiguration to see that it inherits a parent class: delegatingwebmvccconfiguration

    public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
        private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
        
      // Get all webmvcconfigurers from the container
        @Autowired(required = false)
        public void setConfigurers(List<WebMvcConfigurer> configurers) {
            if (!CollectionUtils.isEmpty(configurers)) {
                this.configurers.addWebMvcConfigurers(configurers);
            }
        }
    }
    
    In this class, we can find the one we just set viewController As a reference, it is found that it calls a
    protected void addViewControllers(ViewControllerRegistry registry) {
        this.configurers.addViewControllers(registry);
    }
    
    Click in addViewControllers
    public void addViewControllers(ViewControllerRegistry registry) {
        Iterator var2 = this.delegates.iterator();
    
        while(var2.hasNext()) {
            // Call all WebMvcConfigurer related configurations together! Including those configured by ourselves and those configured by Spring
            WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();
            delegate.addViewControllers(registry);
        }
    
    }
    

Conclusion: all WebMvcConfiguration will be used. Not only Spring's own configuration class, but also our own configuration class will be called

Full takeover

That is, spring boot does not need to automatically configure spring MVC. We configure everything ourselves

If you want to take complete control of Spring MVC
you can add your own @Configuration annotated with @EnableWebMvc.


To fully take over, we only need to add one in our configuration class@EnableWebMvc
 That is, just add@EnableWebMvc Annotation, automatic configuration failure

analysis:

It is found that it imports a class. We can continue to look at it
@Import({DelegatingWebMvcConfiguration.class})public @interface EnableWebMvc {}

It inherits a parent class WebMvcConfigurationSupport
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {  // ......}

Look back Webmvc Auto configuration class
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
// This annotation means that the autoconfiguration class takes effect only when there is no component in the container
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
    ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
    
}

Summary: @ EnableWebMvc imported the WebMvcConfigurationSupport component; The imported WebMvcConfigurationSupport is only the most basic function of spring MVC

Page internationalization

Sometimes, our website will involve the switching between Chinese and English or even multiple languages. At this time, we need to learn internationalization

prepare

First, uniformly set the encoding of properties in the IDEA

Configuration file writing

Write an internationalization configuration file and extract the internationalization page messages that need to be displayed on the page. We can go to the login page to see what we need to write international configurations

  1. We create a new i18n directory under the resources resource file to store the internationalization configuration files
  2. Create a login Properties file and a login_zh_CN.properties; It is found that IDEA automatically identifies the internationalization operation we want to do; The folder has changed
  3. You can create a new file and add an English configuration file
  4. Next, let's write the configuration. We can see another view under the idea. Click the + sign to add attributes directly; Let's create a new login Tip, you can see that there are three file boxes on the side for input




login.properties default
	login.btn=Sign in
	login.password=password
	login.remember=Remember me
	login.tip=Please login
	login.username=user name

english
	login.btn=Sign in
	login.password=Password
	login.remember=Remember me
	login.tip=Please sign in
	login.username=Username

chinese
	login.btn=Sign in
	login.password=password
	login.remember=Remember me
	login.tip=Please login
	login.username=user name

principle

Let's take a look at SpringBoot's automatic configuration of internationalization! Another class is involved here: MessageSourceAutoConfiguration

There is a method. It is found that SpringBoot has automatically configured the component ResourceBundleMessageSource that manages our internationalization resource files

// Get the value passed from properties to judge
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    if (StringUtils.hasText(properties.getBasename())) {
        // Set the basic name of the internationalization file (excluding the language country code)
        messageSource.setBasenames(
            StringUtils.commaDelimitedListToStringArray(
                                       StringUtils.trimAllWhitespace(properties.getBasename())));
    }
    if (properties.getEncoding() != null) {
        messageSource.setDefaultEncoding(properties.getEncoding().name());
    }
    messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
    Duration cacheDuration = properties.getCacheDuration();
    if (cacheDuration != null) {
        messageSource.setCacheMillis(cacheDuration.toMillis());
    }
    messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
    messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
    return messageSource;
}

Our real situation is that it is placed in the i18n directory, so we need to configure the path of messages

spring.messages.basename=i18n.login

Configure page internationalization values

Go to the page to get the internationalization value, check the Thymeleaf document, and find the message value. The operation is: #{...}. Let's go to the page test

Configure internationalization resolution

There is an international Locale (region information object) in Spring; There is a parser called LocaleResolver (get area information object)!

Let's go to our webmvc automatic configuration file and look for it! See the spring boot default configuration

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
    // If there is no self configuration in the container, use the user configuration
    if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
        return new FixedLocaleResolver(this.mvcProperties.getLocale());
    }
    // Receiver header internationalization decomposition
    AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
    localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
    return localeResolver;
}

There is a method in the AcceptHeaderLocaleResolver class

public Locale resolveLocale(HttpServletRequest request) {
    Locale defaultLocale = this.getDefaultLocale();
    // By default, the Locale is obtained according to the region information brought by the request header for internationalization
    if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
        return defaultLocale;
    } else {
        Locale requestLocale = request.getLocale();
        List<Locale> supportedLocales = this.getSupportedLocales();
        if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) {
            Locale supportedLocale = this.findSupportedLocale(request, supportedLocales);
            if (supportedLocale != null) {
                return supportedLocale;
            } else {
                return defaultLocale != null ? defaultLocale : requestLocale;
            }
        } else {
            return requestLocale;
        }
    }
}

If we want to click the link to make our international resources effective now, we need to make our own Locale effective!

We write our own LocaleResolver, which can carry regional information on the link!

Modify the jump connection of the front page:

<!-- The parameter passed in here does not need to be used? Use( key=value)-->
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">chinese</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>

Write a processing component

//You can carry area information on the link
public class MyLocaleResolver implements LocaleResolver {

    //Parse request
    @Override
    public Locale resolveLocale(HttpServletRequest request) {

        String language = request.getParameter("l");
        Locale locale = Locale.getDefault(); // If it is not obtained, the system default is used
        //If the request link is not empty
        if (!StringUtils.isEmpty(language)){
            //Split request parameters
            String[] split = language.split("_");
            //Country, region
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

    }
}

In order for our regionalization information to take effect, we need to configure this component again! Add bean s under our own mvcconfig

@Bean
public LocaleResolver localeResolver(){    return new MyLocaleResolver();}

Spring boot integrates JDBC

Introduction to spring data

For the data access layer, whether SQL (relational database) or NoSQL (non relational database), the bottom layer of Spring Boot adopts the way of Spring Data for unified processing.

The bottom layer of Spring Boot uses Spring Data to uniformly process various databases. Spring Data is also a well-known project in spring as well as Spring Boot and Spring Cloud.

Spin data official website: https://spring.io/projects/spring-data

For database related initiators, please refer to the official documents: https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/htmlsingle/#using-boot-starter

Create test project test data source

Create a new test project: springboot data JDBC; Introduce corresponding modules! Basic module
After the project was completed, we found that the following initiators were automatically imported for us

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

Write yaml configuration file to connect to database

spring:
  datasource:
    username: root
    password: 123456
    #? serverTimezone=UTC resolves the error in the time zone
    url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver

After configuring these things, we can use them directly, because SpringBoot has automatically configured them for us by default; Go to the test class and test it

@SpringBootTest
class SpringbootDataJdbcApplicationTests {

    //DI injection data source
    @Autowired
    DataSource dataSource;

    @Test
    public void contextLoads() throws SQLException {
        //Take a look at the default data source
        System.out.println(dataSource.getClass());
        //Get connection
        Connection connection =   dataSource.getConnection();
        System.out.println(connection);
        //Close connection
        connection.close();
    }
}

We can see that the default data source configured for us is: class com zaxxer. hikari. Hikaridatasource, we did not configure it manually

Let's search globally and find that all automatic configurations of the data source are in the DataSourceAutoConfiguration file

@Import(
    {Hikari.class, Tomcat.class, Dbcp2.class, Generic.class, DataSourceJmxConfiguration.class}
)
protected static class PooledDataSourceConfiguration {
    protected PooledDataSourceConfiguration() {
    }
}

The classes imported here are under the DataSourceConfiguration configuration class. It can be seen that the HikariDataSource data source is used by default for Spring Boot 2.2.5, while org. Is used by default for previous versions, such as Spring Boot 1.5 apache. tomcat. jdbc. pool. Datasource as the data source;

HikariDataSource is known as the fastest data source of Java WEB, which is better than traditional connection pools such as C3P0, DBCP and Tomcat jdbc;

You can use spring datasource. Type specifies the custom data source type, and the value is the fully qualified name of the connection pool implementation to be used

JDBCTemplate

With the data source (com.zaxxer.hikari.HikariDataSource), you can get the database connection (java.sql.Connection). With the connection, you can use the native JDBC statement to operate the database;

Even without using a third-party database operation framework, such as MyBatis, Spring itself makes a lightweight encapsulation of the native JDBC, that is, JdbcTemplate.

All CRUD methods for database operations are in the JdbcTemplate.

Spring Boot not only provides the default data source, but also the configured JdbcTemplate is placed in the container by default. Programmers only need to inject it themselves

The automatic configuration of JdbcTemplate depends on org springframework. boot. autoconfigure. JdbcTemplateConfiguration class under JDBC package

JdbcTemplate mainly provides the following methods:

  • Execute method: can be used to execute any SQL statement, generally used to execute DDL statements
  • Update method and batchUpdate method: the update method is used to execute new, modify, delete and other statements; The batchUpdate method is used to execute batch related statements
  • Query method and queryForXXX method: used to execute query related statements
  • call method: used to execute stored procedures, functions and related statements

test

Write a Controller, inject JDBC template, and write test methods for access testing

@RestController
@RequestMapping("/jdbc")
public class JdbcController {

    /**
     * Spring Boot The data source is provided by default, and org.org is provided by default springframework. jdbc. core. JdbcTemplate
     * JdbcTemplate Data sources are injected into the database to simplify JDBC operations
     * It can also avoid some common errors, and you don't have to close the database connection yourself
     */
    @Autowired
    JdbcTemplate jdbcTemplate;

    //Query all data in the employee table
    //One Map in the List corresponds to one row of data in the database
    //The key in the Map corresponds to the field name of the database, and the value corresponds to the field value of the database
    @GetMapping("/list")
    public List<Map<String, Object>> userList(){
        String sql = "select * from employee";
        List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
        return maps;
    }
    
    //Add a new user
    @GetMapping("/add")
    public String addUser(){
        //Insert statement, pay attention to time
        String sql = "insert into employee(last_name, email,gender,department,birth)" +
                " values ('Madness theory','24736743@qq.com',1,101,'"+ new Date().toLocaleString() +"')";
        jdbcTemplate.update(sql);
        //query
        return "addOk";
    }

    //Modify user information
    @GetMapping("/update/{id}")
    public String updateUser(@PathVariable("id") int id){
        //Insert statement
        String sql = "update employee set last_name=?,email=? where id="+id;
        //data
        Object[] objects = new Object[2];
        objects[0] = "Qin Jiang";
        objects[1] = "24736743@sina.com";
        jdbcTemplate.update(sql,objects);
        //query
        return "updateOk";
    }

    //delete user
    @GetMapping("/delete/{id}")
    public String delUser(@PathVariable("id") int id){
        //Insert statement
        String sql = "delete from employee where id=?";
        jdbcTemplate.update(sql,id);
        //query
        return "deleteOk";
    }
    
}

Principle analysis

org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration data source configuration class function: add a data source after logical judgment

SpringBoot supports the following data sources by default:

  • com.zaxxer.hikari.HikariDataSource (Spring Boot 2.0 or above, this data source is used by default)
  • org.apache.tomcat.jdbc.pool.DataSource
  • org.apache.commons.dbcp2.BasicDataSource

You can use spring datasource. Type specifies the custom data source type, and the value is the fully qualified name of the connection pool implementation to be used. By default, it is automatically detected from the classpath.

    @Configuration
    @ConditionalOnMissingBean({DataSource.class})
    @ConditionalOnProperty(
        name = {"spring.datasource.type"}
    )
    static class Generic {
        Generic() {
        }

        @Bean
        public DataSource dataSource(DataSourceProperties properties) {
            return properties.initializeDataSourceBuilder().build();
        }
    }

Spring boot integrates Druid

Introduction to Druid

A large part of Java programs need to operate the database. In order to improve the performance, they have to use the database connection pool when operating the database

Druid combines the advantages of DB pools such as C3P0 and DBCP, and adds log monitoring. It can well monitor the connection of DB pool and the execution of SQL. Druid is born for monitoring

com.alibaba.druid.pool.DruidDataSource common configuration parameters

to configure					  Default value				explain
name								The significance of configuring this attribute is that if there are multiple data sources, they can be distinguished by name during monitoring. If it is not configured, a name will be generated. The format is:"DataSource-" + System.identityHashCode(this). In addition, configure this property at least 1.0.5 It doesn't work in the version. It's set by force name Will go wrong
url									Connecting to the database url,Different databases are different. For example: mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto
username							User name to connect to the database
password							Password to connect to the database. If you don't want the password written directly in the configuration file, you can use ConfigFilter. 
driverClassName	 	according to url automatic recognition 	This item can be configured or not. If it is not configured druid Will be based on url automatic recognition  dbType,Then select the appropriate driverClassName
initialSize		   		0			The number of physical connections established during initialization. Initialization occurs in the display call init Method, or the first time getConnection Time
maxActive				8			Maximum number of connection pools
minIdle								Minimum number of connection pools
maxWait								Maximum wait time to get a connection, in milliseconds. Configured maxWait After that, the fair lock is enabled by default, and the concurrency efficiency will be reduced. If necessary, it can be configured useUnfairLock Attribute is true Use unfair locks.
poolPreparedStatements	false		Cache preparedStatement,that is PSCache. PSCache Great performance improvement for databases that support cursors, for example oracle. stay mysql Next, it is recommended to close.

Configure data sources

  1. Add Druid data source dependency on

    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.12</version>
    </dependency>
    
  2. Switch data sources; As mentioned earlier, com.com is used by default for Spring Boot 2.0 and above zaxxer. hikari. Hikaridatasource data source, but it can be accessed through spring datasource. Type specifies the data source

    spring:
      datasource:
        username: root
        password: 123456
        url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
        driver-class-name: com.mysql.cj.jdbc.Driver
         # Custom data source
        type: com.alibaba.druid.pool.DruidDataSource
    
  3. After data source switching, inject DataSource into the test class, obtain it, and output to see whether the switching is successful

  4. Switching succeeded! Now that the switch is successful, you can set the initialization size, maximum number of connections, waiting time, minimum number of connections and other settings of the data source connection; You can view the source code

    spring:
      datasource:
        username: root
        password: 123456
        #? serverTimezone=UTC resolves the error in the time zone
        url: jdbc:mysql://localhost:3306/springboot?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource
    
        #Spring Boot does not inject these attribute values by default and needs to bind itself
        #druid data source proprietary configuration
        initialSize: 5
        minIdle: 5
        maxActive: 20
        maxWait: 60000
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: SELECT 1 FROM DUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
    
        #Configure filters for monitoring statistics interception, stat: monitoring statistics, log4j: logging, wall: defending sql injection
        #If allowed, an error occurs in Java lang.ClassNotFoundException: org. apache. log4j. Priority
        #Then import the log4j dependency. Maven address: https://mvnrepository.com/artifact/log4j/log4j
        filters: stat,wall,log4j
        maxPoolPreparedStatementPerConnectionSize: 20
        useGlobalDataSourceStat: true
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
    
  5. Import Log4j dependencies

    	 <!-- https://mvnrepository.com/artifact/log4j/log4j -->
    	 <dependency>
    	     <groupId>log4j</groupId>
    	     <artifactId>log4j</artifactId>
    	     <version>1.2.17</version>
    	 </dependency>
    
  6. Now programmers need to bind the parameters in the global configuration file for DruidDataSource and add them to the container instead of using the automatic generation of Spring Boot; We need to add the DruidDataSource component to the container and bind the properties

    @Configuration
    public class DruidConfig {
    
        /*
           @Configuration Add the custom Druid data source to the container and no longer let Spring Boot create it automatically
           Bind the Druid data source attribute in the global configuration file to com alibaba. druid. pool. Druiddatasource to make them effective
           @ConfigurationProperties(prefix = "spring.datasource"): The function is to add the global configuration file
           		The prefix is spring The attribute value of datasource is injected into com alibaba. druid. pool. Druiddatasource is in a parameter with the same name
         */
        @ConfigurationProperties(prefix = "spring.datasource")
        @Bean
        public DataSource druidDataSource() {
            return new DruidDataSource();
        }
    
    }
    
  7. Test in the test class; See if it works

    @SpringBootTest
    class SpringbootDataJdbcApplicationTests {
    
        //DI injection data source
        @Autowired
        DataSource dataSource;
    
        @Test
        public void contextLoads() throws SQLException {
            //Take a look at the default data source
            System.out.println(dataSource.getClass());
            //Get connection
            Connection connection =   dataSource.getConnection();
            System.out.println(connection);
    
            DruidDataSource druidDataSource = (DruidDataSource) dataSource;
            System.out.println("druidDataSource Maximum connections to data source:" + druidDataSource.getMaxActive());
            System.out.println("druidDataSource Number of data source initialization connections:" + druidDataSource.getInitialSize());
    
            //Close connection
            connection.close();
        }
    }
    

Configure Druid data source monitoring

Druid data source has the function of monitoring and provides a web interface for users to view. Similarly, when installing a router, people also provide a default web page

  1. Set Druid's background management page, such as login account, password, etc; Configure background management

    //Configure the Servlet of Druid monitoring management background;
    //There is no web when the Servlet container is built in XML file, so the Servlet registration method of Spring Boot is used
    @Bean
    public ServletRegistrationBean statViewServlet() {
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
    
        // These parameters can be found on COM alibaba. druid. support. http. StatViewServlet 
        // Parent class of com alibaba. druid. support. http. Found in resourceservlet
        Map<String, String> initParams = new HashMap<>();
        //loginUsername and other parameters are fixed and cannot be changed
        initParams.put("loginUsername", "admin"); //Login account of background management interface
        initParams.put("loginPassword", "123456"); //Login password of background management interface
    
        //Who is allowed to access in the background
        //initParams.put("allow", "localhost"): indicates that only the local machine can access it
        //initParams.put("allow", ""): when it is empty or null, it means that all access is allowed
        initParams.put("allow", "");
        //deny: Druid, who is denied access in the background
        //initParams.put("deny", "192.168.1.20"); Indicates that this ip access is prohibited
    
        //Set initialization parameters
        bean.setInitParameters(initParams);
        return bean;
    }
    
  2. After configuration, we can choose to access: http://localhost:8080/druid/login.html

Configure Druid web monitoring filter

In normal work, it can be configured as required, which is mainly used for monitoring

//Configure the filter of web monitoring for Druid monitoring
//WebStatFilter: used to configure management association monitoring statistics between Web and Druid data sources
@Bean
public FilterRegistrationBean webStatFilter() {
    FilterRegistrationBean bean = new FilterRegistrationBean();
    bean.setFilter(new WebStatFilter());

    //exclusions: sets which requests are filtered and excluded so that statistics are not performed
    Map<String, String> initParams = new HashMap<>();
    initParams.put("exclusions", "*.js,*.css,/druid/*,/jdbc/*");
    bean.setInitParameters(initParams);

    //"/ *" means to filter all requests
    bean.setUrlPatterns(Arrays.asList("/*"));
    return bean;
}

Spring boot integrates mybatis

  1. When creating a project, check spring web, MySQL driver, and import the dependencies required by mybatis

    <!-- introduce myBatis,This is MyBatis Officially provided adapter Spring Boot Yes, not Spring Boot own-->
       <dependency>
           <groupId>org.mybatis.spring.boot</groupId>
           <artifactId>mybatis-spring-boot-starter</artifactId>
           <version>2.1.0</version>
       </dependency>
    
  2. Configure database connection information

    spring.datasource.username=root
    spring.datasource.password=123456
    spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    
  3. We use the default data source here; First test whether the connection is successful

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringbootDemoMybatisApplicationTests {
    
        @Autowired
        DataSource dataSource;
    
        @Test
        public void contextLoads() throws SQLException {
    
            System.out.println("data source>>>>>>" + dataSource.getClass());
            Connection connection = dataSource.getConnection();
            System.out.println("connect>>>>>>>>>" + connection);
            System.out.println("Connection address>>>>>" + connection.getMetaData().getURL());
            connection.close();
    
        }
    
    }
    
  4. Create entity class

    package com.kuang.mybatis.pojo;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
    
        private int id;
        private String name;
        private String pwd;
    
  5. The corresponding Mapper mapping file, UserMapper, is placed in resources/mybatis/mapper

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.kuang.mybatis.pojo.mapper.UserMapper">
    
        <select id="selectUser" resultType="User">
      		  select * from user
        </select>
    
        <select id="selectUserById" resultType="User">
       		   select * from user where id = #{id}
    	</select>
    
        <insert id="addUser" parameterType="User">
    		   insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
    	</insert>
    
        <update id="updateUser" parameterType="User">
      		  update user set name=#{name},pwd=#{pwd} where id = #{id}
    	</update>
    
        <delete id="deleteUser" parameterType="int">
    		    delete from user where id = #{id}
    	</delete>
    </mapper>
    
  6. Previously, when mybatis was not integrated with spring, the configuration data source, transaction, account and password connecting to the database were all carried out in the mybatis core configuration file. After mybatis was integrated with spring, the configuration data source, transaction, account and password connecting to the database were managed by spring. Therefore, here we are completely ok even if we do not use the mybatis configuration file!

Now that you have provided the mapping configuration files for myBatis, it is natural to tell spring boot where these files are located

It has been said that the official spring boot does not provide the starter of myBaits. It is the development package officially provided by myBatis to adapt the spring boot from POM It can also be seen from the dependent package name in the XML file that it does not start with spring boot;

Similarly, the two lines of configuration in the global configuration file above also start with mybatis instead of spring, which fully shows that these are officially provided by mybatis

spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

#Specify the core configuration file and Mapper mapping file for myBatis
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
	
Note: the path of the corresponding entity class
mybatis.type-aliases-package=com.kuang.mybatis.pojo
  1. Write controller

    @RestController
    public class UserController {
    
        @Autowired
        private UserMapper userMapper;
    
        //Select all users
        @GetMapping("/selectUser")
        public String selectUser(){
            List<User> users = userMapper.selectUser();
            for (User user : users) {
                System.out.println(user);
            }
    
            return "ok";
        }
        //Select user by id
        @GetMapping("/selectUserById")
        public String selectUserById(){
            User user = userMapper.selectUserById(1);
            System.out.println(user);
            return "ok";
        }
        //Add a user
        @GetMapping("/addUser")
        public String addUser(){
            userMapper.addUser(new User(5,"A Mao","456789"));
            return "ok";
        }
        //Modify a user
        @GetMapping("/updateUser")
        public String updateUser(){
            userMapper.updateUser(new User(5,"A Mao","421319"));
            return "ok";
        }
        //Delete user by id
        @GetMapping("/deleteUser")
        public String deleteUser(){
            userMapper.deleteUser(5);
            return "ok";
        }
    
    }
    

SpringBoot integrates with SpringSecurity

If the security problem is only considered in the later stage of application development, it may fall into a dilemma: on the one hand, there are serious security vulnerabilities in the application, which can not meet the requirements of users, and may cause users' private data to be stolen by attackers; On the other hand, the basic architecture of the application has been determined. To repair security vulnerabilities, it may be necessary to make major adjustments to the system architecture, so it requires more development time and affects the release process of the application. Therefore, security related factors should be taken into account from the first day of application development, and in the whole application development process.

There are well-known in the market: Shiro, Spring Security

Spring Security is a powerful and highly customizable authentication and access control framework. It is actually the standard for protecting spring based applications.

Spring Security is a framework that focuses on providing authentication and authorization for Java applications. Like all spring projects, the real strength of Spring Security is that it can be easily extended to meet customization requirements

You can know from the introduction of the official website that this is a permission framework. I think we didn't use the framework in our previous projects. How do we control permissions? Permissions are generally subdivided into function permissions, access permissions, and menu permissions. The code will be very cumbersome and redundant.

How to solve the cumbersome and redundant problem of writing permission code before, some mainstream frameworks came into being, and spring security is one of them

Based on the Spring framework, Spring Security provides a complete solution for Web application security. Generally speaking, the security of Web applications includes two parts: user Authentication and user Authorization. User Authentication refers to verifying whether a user is a legal subject in the system, that is, whether the user can access the system. User Authentication generally requires users to provide user name and password. The system completes the Authentication process by verifying the user name and password. User Authorization refers to verifying whether a user has permission to perform an operation. In a system, different users have different permissions. For example, for a file, some users can only read it, while others can modify it. Generally speaking, the system assigns different roles to different users, and each role corresponds to a series of permissions.

Meet spring security

Spring Security is the security framework for the spring project and the default technology selection of the Spring Boot underlying security module. It can realize powerful Web security control. For security control, we only need to introduce the Spring Boot starter security module and configure a small amount to realize powerful security management

Remember several classes:

  • WebSecurityConfigurerAdapter: custom Security policy
  • AuthenticationManagerBuilder: custom authentication policy
  • @Enable WebSecurity: enable WebSecurity mode

The two main goals of Spring Security are "authentication" and "authorization" (access control)

Authentication

  • Authentication is about verifying your credentials, such as user name / user ID and password, to verify your identity.
  • Authentication is usually done by user name and password, sometimes in combination with authentication factors.

Authorization

  • Authorization occurs after the system successfully verifies your identity, and will eventually grant you full access to resources (such as information, files, databases, funds, locations, almost anything)

test

Establishment of experimental environment

  1. Create an initial springboot project web module, thymeleaf module

  2. Import static resources

    welcome.html
    |views
    	|level1
    		1.html
    		2.html
    		3.html
    	|level2
    		1.html
    		2.html
    		3.html
    	|level3
    		1.html
    		2.html
    		3.html
    Login.html
    
  3. controller jump

    @Controller
    public class RouterController {
    
       @RequestMapping({"/","/index"})
       public String index(){
           return "index";
      }
    
       @RequestMapping("/toLogin")
       public String toLogin(){
           return "views/login";
      }
    
       @RequestMapping("/level1/{id}")
       public String level1(@PathVariable("id") int id){
           return "views/level1/"+id;
      }
    
       @RequestMapping("/level2/{id}")
       public String level2(@PathVariable("id") int id){
           return "views/level2/"+id;
      }
    
       @RequestMapping("/level3/{id}")
       public String level3(@PathVariable("id") int id){
           return "views/level3/"+id;
      }
    
    }
    

Certification and authorization

Everyone can access our test environment. We use Spring Security to add authentication and authorization functions

  1. Introducing Spring Security module

    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    
  2. Writing Spring Security configuration classes
    Refer to the official website: https://spring.io/projects/spring-security
    Check the version in our own project and find the corresponding help document:
    https://docs.spring.io/spring-security/site/docs/5.3.0.RELEASE/reference/html5 #servlet-applications 8.16.4

  3. Write basic configuration class

    @EnableWebSecurity // Enable WebSecurity mode
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
       @Override
       protected void configure(HttpSecurity http) throws Exception {
           
      }
    }
    
  4. Authorization rules for custom requests

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       // Authorization rules for custom requests
       // The home page is accessible to everyone
       http.authorizeRequests().antMatchers("/").permitAll()
      .antMatchers("/level1/**").hasRole("vip1")
      .antMatchers("/level2/**").hasRole("vip2")
      .antMatchers("/level3/**").hasRole("vip3");
    }
    
  5. Test: I found that I can't get in except the home page! Because we don't have a login role at present, because the request requires that the login role has the corresponding permission!

  6. Add the following configuration in the configure() method to enable the login function of automatic configuration

    // Turn on the auto configured login function
    // /The login request comes to the login page
    // /login?error redirection here indicates login failure
    http.formLogin();
    
  7. Test it: if you don't have permission, you will jump to the login page

  8. We can define authentication rules and override the configure(AuthenticationManagerBuilder auth) method

    //Define authentication rules
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       
       //Defined in memory, you can also get it in jdbc
       auth.inMemoryAuthentication()
              .withUser("kuangshen").password("123456").roles("vip2","vip3")
              .and()
              .withUser("root").password("123456").roles("vip1","vip2","vip3")
              .and()
              .withUser("guest").password("123456").roles("vip1","vip2");
    }
    
  9. Test, we can use these accounts to log in and test! An error will be reported if found

  10. The reason is that we need to encrypt the password transmitted from the front end in some way, otherwise we can't log in and modify the code

    //Define authentication rules
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       //Defined in memory, you can also get it in jdbc
       //Spring security 5.0 adds a variety of encryption methods and changes the password format.
       //If we want our project to log in normally, we need to modify the code in configure. We need to encrypt the password transmitted from the front end in some way
       //bcrypt encryption is officially recommended by spring security.
       
       auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
              .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
              .and()
              .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
              .and()
              .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
    }
    
  11. After testing, it is found that the login is successful, and each role can only access the rules under its own authentication! Done

Permission control and logoff

  1. Enable auto configured logoff

    //Authorization rules for custom requests
    @Override
    protected void configure(HttpSecurity http) throws Exception {
       //....
       //Enable auto configured logoff
          // /Logout logout request
       http.logout();
    }
    
  2. In the front end, we add a logout button, index HTML navigation bar

    <a class="item" th:href="@{/logout}">
       <i class="address card icon"></i> cancellation
    </a>
    
  3. We can test it. After the login is successful, click logout. If we find that the logout is completed, we will jump to the login page! However, we want him to log off successfully and still jump to the home page. What should we do

    // .logoutSuccessUrl("/");  Log out successfully and come to the home page
    http.logout().logoutSuccessUrl("/");
    
  4. Test. After logging out, find that you can jump to the home page. OK
    When the user does not log in, only the login button is displayed on the navigation bar. After the user logs in, the login user information and logout button can be displayed on the navigation bar! Also, for example, kuangshen has only vip2 and vip3 functions, so only these two functions are displayed when logging in, but the function menu of vip1 is not displayed! This is the real website! What should I do?
    We need to combine some functions in thymeleaf. sec: authorize = "isAuthenticated()": whether to authenticate login! To display different pages

    <!-- https://mvnrepository.com/artifact/org.thymeleaf.extras/thymeleaf-extras-springsecurity4 -->
    <dependency>
       <groupId>org.thymeleaf.extras</groupId>
       <artifactId>thymeleaf-extras-springsecurity5</artifactId>
       <version>3.0.4.RELEASE</version>
    </dependency>
    
  5. Modify our front page

    Import namespace
     xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"
    
    Modify the navigation bar and add authentication judgment
     <!--Login and logout-->
     <div class="right menu">
     
        <!--If you are not logged in-->
        <div sec:authorize="!isAuthenticated()">
            <a class="item" th:href="@{/login}">
                <i class="address card icon"></i> Sign in
            </a>
        </div>
     
        <!--If logged in-->
        <div sec:authorize="isAuthenticated()">
            <a class="item">
                <i class="address card icon"></i>
               user name:<span sec:authentication="principal.username"></span>
               Role:<span sec:authentication="principal.authorities"></span>
            </a>
        </div>
     
        <div sec:authorize="isAuthenticated()">
            <a class="item" th:href="@{/logout}">
                <i class="address card icon"></i> cancellation
            </a>
        </div>
     </div>
    
  6. Restart the test. We can log in and try. After successful login, the page we want is displayed; If you log off 404, it is because it prevents CSRF Cross Site Request Forgery by default, because it will cause security problems. We can change the request to post form submission, or turn off the CSRF function in spring security; Let's try adding HTTP to the configuration csrf(). disable()

    http.csrf().disable();//Turn off csrf function: Cross Site Request Forgery. By default, logout requests can only be submitted through post
    http.logout().logoutSuccessUrl("/");
    
  7. We continue to complete the following role function block authentication

    <!-- sec:authorize="hasRole('vip1')" -->
    <div class="column" sec:authorize="hasRole('vip1')">
       <div class="ui raised segment">
           <div class="ui">
               <div class="content">
                   <h5 class="content">Level 1</h5>
                   <hr>
                   <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div>
                   <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div>
                   <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div>
               </div>
           </div>
       </div>
    </div>
    
    <div class="column" sec:authorize="hasRole('vip2')">
       <div class="ui raised segment">
           <div class="ui">
               <div class="content">
                   <h5 class="content">Level 2</h5>
                   <hr>
                   <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div>
                   <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div>
                   <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div>
               </div>
           </div>
       </div>
    </div>
    
    <div class="column" sec:authorize="hasRole('vip3')">
       <div class="ui raised segment">
           <div class="ui">
               <div class="content">
                   <h5 class="content">Level 3</h5>
                   <hr>
                   <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div>
                   <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div>
                   <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div>
               </div>
           </div>
       </div>
    </div>
    

Remember me

As long as we log in, close the browser and log in again, we will log in again. However, in many websites, there is a function of remembering passwords. How can we achieve this? It's simple

After successful login, send the cookie to the browser for saving. After login, bring the cookie. As long as you pass the check, you can avoid login. If you click log off, the cookie will be deleted

  1. Enable remember me function

    //Authorization rules for custom requests
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    //. . . . . . . . . . . 
       //Remember me
       http.rememberMe();
    }
    
  2. We started the project again and found that the login page had an additional remember me function. After we logged in, we closed the browser, and then reopened the browser to access. We found that the user still exists!
    Thinking: how to achieve it? It's actually very simple
    We can view the browser's cookie s

  3. When we click log off, we can find that spring security automatically deletes this cookie for us

Custom landing page

Now this Login page is the default of spring security. How can we use the Login interface written by ourselves

  1. Specify loginpage after the login page configuration just now

    http.formLogin().loginPage("/toLogin");
    
  2. Then the front end also needs to point to the login request defined by ourselves

    <a class="item" th:href="@{/toLogin}">
       <i class="address card icon"></i> Sign in
    </a>
    
  3. When we log in, we also need to configure where to send these information. Login HTML configure the submission request and method. The method must be post

    <form th:action="@{/login}" method="post">
       <div class="field">
           <label>Username</label>
           <div class="ui left icon input">
               <input type="text" placeholder="Username" name="username">
               <i class="user icon"></i>
           </div>
       </div>
       <div class="field">
           <label>Password</label>
           <div class="ui left icon input">
               <input type="password" name="password">
               <i class="lock icon"></i>
           </div>
       </div>
       <input type="submit" class="ui blue submit button"/>
    </form>
    
  4. When this request is submitted, we still need to verify it. What should we do? We can check the source code of formLogin() method! We configure the parameters to receive the login user name and password

    http.formLogin()
      .usernameParameter("username")
      .passwordParameter("password")
      .loginPage("/toLogin")
      .loginProcessingUrl("/login"); // Login form submission request
    
  5. Add the remember me multi selection box on the login page

    <input type="checkbox" name="remember"> Remember me
    
  6. Backend authentication processing

    //Customize and remember my parameters!
    http.rememberMe().rememberMeParameter("remember");
    

Full configuration code

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   //Authorization rules for custom requests
   @Override
   protected void configure(HttpSecurity http) throws Exception {

       http.authorizeRequests().antMatchers("/").permitAll()
      .antMatchers("/level1/**").hasRole("vip1")
      .antMatchers("/level2/**").hasRole("vip2")
      .antMatchers("/level3/**").hasRole("vip3");


       //Enable the auto configured login function: if you do not have permission, you will jump to the login page!
           // /The login request comes to the login page
           // /login?error redirection here indicates login failure
       http.formLogin()
          .usernameParameter("username")
          .passwordParameter("password")
          .loginPage("/toLogin")
          .loginProcessingUrl("/login"); // Login form submission request

       //Enable auto configured logoff
           // /Logout logout request
           // .logoutSuccessUrl("/");  Log out successfully and come to the home page

       http.csrf().disable();//Turn off csrf function: Cross Site Request Forgery. By default, logout requests can only be submitted through post
       http.logout().logoutSuccessUrl("/");

       //Remember me
       http.rememberMe().rememberMeParameter("remember");
  }

   //Define authentication rules
   @Override
   protected void configure(AuthenticationManagerBuilder auth) throws Exception {
       //Defined in memory, you can also get it in jdbc
       //Spring security 5.0 adds a variety of encryption methods and changes the password format.
       //If we want our project to log in normally, we need to modify the code in configure. We need to encrypt the password transmitted from the front end in some way
       //bcrypt encryption is officially recommended by spring security.

       auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
              .withUser("kuangshen").password(new BCryptPasswordEncoder().encode("123456")).roles("vip2","vip3")
              .and()
              .withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3")
              .and()
              .withUser("guest").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2");
  }
}

Interview questions

  • What is the core of SpringBoot? Talk about your understanding
	1. Automatic assembly. Principle: important
	2. Tell run()method
		a. Infer whether the type of application is an ordinary project or Web project
		b. Find and load all available initializers, set to initializers Attribute
		c. Find all application listeners and set to listeners Attribute
		d. Infer and set main Method to find the main class to run

Topics: Java Spring Programmer