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:
- Lightweight and minimally intrusive programming based on POJO, everything is bean;
- Loose coupling is realized through IOC, dependency injection (DI) and interface oriented;
- Declarative programming based on AOP and conventions;
- 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
- 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
- Create a new HelloController class in the package
@RestController public class HelloController { @RequestMapping("/hello") public String hello() { return "Hello World"; } }
- 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!
- 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:
- Infer whether the type of application is a normal project or a Web project
- Find and load all available initializers and set them in the initializers property
- Find all application listeners and set them to the listeners property
- 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
- Spaces cannot be omitted
- The hierarchical relationship is controlled by indentation. As long as a column of data aligned on the left is at the same level
- Attributes and values are case sensitive
- Literal: normal value [number, Boolean, string]
- 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!
-
Create a new file application. In the resources directory of the springboot project yml
-
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 }
-
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
-
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 }
-
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
-
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; }
-
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>
-
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
-
Let's create a new person in the resources directory Properties file
-
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
-
Create a new entity class User
@Component //Register bean public class User { private String name; private int age; private String sex; }
-
Edit profile user properties
user1.name=kuangshen user1.age=18 user1.sex=male
-
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
- @ConfigurationProperties only needs to be written once, @ Value needs to be added to each field
- 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
- JSR303 data verification, that is, we can add a layer of filter verification in the field to ensure the legitimacy of the data
- 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:
- SpringBoot boot will load a large number of auto configuration classes
- See if the functions we need are in the auto configuration class written by SpringBoot by default
- 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)
- 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
- Write a TestController
@Controller public class TestController { @RequestMapping("/t1") public String test1(){ //classpath:/templates/test.html return "test"; } }
- 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/
- 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"; }
- 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>
- 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:
- 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"; }
- 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
- 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; } }
- 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
- 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
- We create a new i18n directory under the resources resource file to store the internationalization configuration files
- 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
- You can create a new file and add an English configuration file
- 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
-
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>
-
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
-
After data source switching, inject DataSource into the test class, obtain it, and output to see whether the switching is successful
-
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
-
Import Log4j dependencies
<!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency>
-
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(); } }
-
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
-
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; }
-
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
-
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>
-
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
-
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(); } }
-
Create entity class
package com.kuang.mybatis.pojo; @Data @NoArgsConstructor @AllArgsConstructor public class User { private int id; private String name; private String pwd;
-
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>
-
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
-
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
-
Create an initial springboot project web module, thymeleaf module
-
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
-
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
-
Introducing Spring Security module
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
-
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 -
Write basic configuration class
@EnableWebSecurity // Enable WebSecurity mode public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { } }
-
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"); }
-
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!
-
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();
-
Test it: if you don't have permission, you will jump to the login page
-
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"); }
-
Test, we can use these accounts to log in and test! An error will be reported if found
-
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"); }
-
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
-
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(); }
-
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>
-
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("/");
-
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>
-
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>
-
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("/");
-
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
-
Enable remember me function
//Authorization rules for custom requests @Override protected void configure(HttpSecurity http) throws Exception { //. . . . . . . . . . . //Remember me http.rememberMe(); }
-
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
-
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
-
Specify loginpage after the login page configuration just now
http.formLogin().loginPage("/toLogin");
-
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>
-
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>
-
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
-
Add the remember me multi selection box on the login page
<input type="checkbox" name="remember"> Remember me
-
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