1.Spring Framework system architecture
- Core Container: core container (Beans, Core, Context, SpEL)
- Data Access/Integration: Data Access/Data Integration (JDBC, ORM, OXM, JMS, Transactions)
- Web: web development (WebSocket, Servlet, Web, Portlet)
- Instrumentation: tool support and class loader implementation
- Messaging: support for messaging architectures and protocols
- AOP: Aspect Oriented Programming
- Aspects: AOP Thought Realization
- Test: unit test and integration test
2.IOC (Inversion of Control) Inversion of Control
-
When using an object, the object generated by active new is transferred to the object provided by the outside. During this process, the control of object creation is transferred from the program to the outside.
-
Spring technology realizes the idea of IOC
-
Spring provides a container, which becomes the IOC container, which is used to act as the "external" in the idea of IOC
-
The IOC container is responsible for a series of tasks such as object creation and initialization. The created or managed objects are collectively referred to as Bean s in the IOC container.
-
-
Goal: full decoupling
-
Managed Bean s Using IOC Containers (IOC)
-
Relational binding (DI) of beans with dependencies in the IOC container
-
-
final effect
- When using an object, not only can it be obtained directly from the IOC container, but also the obtained Bean has bound all dependencies
3.Bean life cycle
-
Initialize the container
- create object (memory allocation)
- Execute the constructor
- Perform attribute injection (set operation)
- Execute the Bean initialization method
-
use beans
perform business operations
-
close/destroy container
Execute the Bean destruction method
-
Trigger the destruction of the Bean before the container is closed
-
To close the container:
- Close the container manually
ConfigurableApplicationContext interface close() operation
-
Register the shutdown hook, close the container before the virtual machine exits and then exit the virtual machine
ConfigurableApplicationContext interface registerShutdownHook() operation
4. Rely on autowiring
-
The process of the IOC container automatically finding and injecting into the Bean in the container according to the resources that the Bean depends on is called automatic assembly
-
Automatic assembly method
- By type (commonly used)
- by name
- by constructor
- Do not enable autowiring
-
Autowiring is used for reference type dependency injection and cannot operate on simple types
-
When using type assembly (byType), the Bean of the same type in the container must be guaranteed to be unique, and it is recommended to use
-
When using assembly by name (byName), it is mandatory to ensure that the Bean with the specified name in the container is coupled with the variable name and configuration, which is not recommended.
-
The priority of automatic assembly is lower than that of setter injection and constructor injection, and the automatic assembly configuration fails when it occurs at the same time
5. Annotation Development Definition Bean
- Spring provides three derivative annotations of @Component annotation
- @Controller: used for presentation layer Bean definition
- @Service: for business layer Bean definition
- @Repository: used for data layer Bean definition
6. Pure annotation development
- Spring 3.0 opens the pure annotation development mode, uses Java classes instead of configuration files, and opens the Spring rapid development track
- Java classes instead of Spring core configuration files
- The @Configuration annotation is used to set the current class as a configuration class
- The @ComponentScan annotation is used to set the scanning path. This annotation can only be added once, and multiple data uses an array format
7. Bean scope and life cycle
-
Use @Scope to define the scope of the Bean
- @Scope("singleton") singleton mode
- @Scope("prototype") multiple instance pattern
-
Use @PostConstruct, @PreDestory to define the Bean life cycle
@PostConstruct public void init(){ System.out.println("Bean init...") } @PreDestory public void destory(){ System.out.println("Bean destory...") }
8. Annotation Development Dependency Injection
dependency injection
-
Use the @Autowired annotation to turn on the automatic wiring mode (by type)
-
Note: Autowiring creates objects based on reflection design and violently reflects corresponding properties to initialize data for private properties without providing a setter method
-
Note: Autowiring recommends using a no-argument construction method to create objects (default), if no corresponding construction method is provided, a unique construction method is required
-
Use the @Qualifier annotation to open the specified name assembly Bean
-
Note: The @Qualifier annotation cannot be used alone, it must be used in conjunction with the @Autowired annotation
-
Simple type injection using @Value
Load the properties file
- Load properties file using @PropertySource annotation
- Note: The path only supports a single configuration, multiple files need to be configured in an array format, and wildcards are not allowed*
Third-Party Bean Management
-
Configure third-party beans using @Bean
-
Add independent configuration classes to core configuration
-
Method 1: import
public class JdbcConfig{ @Bean public DataSource dataSource(){ DruidDataSource ds = new DruidDataSource(); //related configuration return ds; } }
-
Use the @Import annotation to manually add the configuration class to the core configuration. This annotation can only be added once, and multiple data use the array format
@Configuration @Import(JdbcConfig.class) public class SpringConfig{ }
-
Method 2: Scanning
@Configuration public class JdbcConfig{ @Bean public DataSource dataSource(){ DruiaDataSource ds = new DuridDataSource(); //related configuration return ds; } }
-
Use the @ComponentScan annotation to scan the package where the configuration class is located, and load the corresponding configuration class information
@Configuration @ComponentScan({"com.tomy.config","com.tomy.service","com.tomy.dao"}) public class SpringConfig{ }
-
Reference Type Dependency Injection
@Configuration public class JdbcConfig{ @Bean public DataSource dataSource(UserService service){ DruiaDataSource ds = new DuridDataSource(); //related configuration return ds; } }
-
Reference type injection only needs to set the formal parameters for the Bean definition method, and the container will automatically assemble the object according to the type
-
9.AOP
-
AOP (Aspect Oriented Programming) Aspect Oriented Programming, a programming paradigm that guides developers to organize program structures
- OOP (Object Oriented Programming) object-oriented programming
-
Role: To enhance the function without disturbing the original design
-
Spring Philosophy: No Intrusion/No Intrusion
AOP core concept
-
JoinPoint: Any position in the program execution process, the granularity is executing methods, throwing exceptions, setting variables, etc.
- In Spring AOP, it is understood as the execution of the method
-
Pointcut: match the expression of the connection point
- In Spring AOP, a pointcut can only describe one method, or it can match multiple methods
- A specific method: the save method with no formal parameters and no return value in the UserDao interface under the com.tomy.dao package
- Match multiple methods: all save methods, all methods starting with get, any method in any interface ending with Dao, all methods with one parameter
-
Advice: The operation performed at the entry point, that is, the common function
- In Spring AOP, functions are finally presented in the form of methods
-
Notification class: the class that defines the notification
-
Aspect: Describes the relationship between notifications and pointcuts
-
Target object (Target): The original object being proxied becomes the target object
case:
-
Import AOP related coordinates
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
- spring-context coordinates depend on spring-aop coordinates
-
Define dao interface and implementation class
-
Define the notification class and make notifications
-
define pointcut
public class Advice(){ @Pointcut("execution(void com.tomy.dao.UserDao.method())") private void pt(){} }
- The entry point defines a method with no practical meaning, that is, no parameters, no return value, and the method body has no actual logic
-
Bind the relationship between the pointcut and the advice, and specify the specific execution location where the advice is added to the original join point
public class Advice(){ @Pointcut("execution(void com.tomy.dao.UserDao.method())") private void pt(){} @Before("pt()") public void before(){ System.out.println(System.currentTimeMillis()); } }
-
Define the notification class to be managed by the Spring container, and define the current class as the aspect class
@Component @Aspect public class Advice(){ @Pointcut("execution(void com.tomy.dao.UserDao.method())") private void pt(){} @Before("pt()") public void before(){ System.out.println(System.currentTimeMillis()); } }
-
Enable Spring's support for AOP annotation-driven
@Configuration @ComponentScan("com.tomy") @EnableAspectJAutoProxy public class SpringConfig{ }
AOP workflow
- Spring container startup
- Read pointcuts in all aspect configurations
- Initialize the Bean and determine whether the method in the class corresponding to the Bean matches any entry point
- Match failed, create object
- If the match is successful, create a proxy object of the original object (target object)
- Get the Bean execution method
- Get the Bean, call the method and execute it, and complete the operation
- When the obtained Bean is a proxy object, run the original method and enhanced content according to the operation mode of the proxy object to complete the operation
- Target object (Target): The original function removes the object generated by the class corresponding to the common function. This kind of object cannot complete the final work
- Proxy (Proxy): The target object cannot directly complete the work, it needs to be backfilled with functions, and it is completed through the proxy object of the original object
AOP pointcut expression
-
pointcut expression: a description of the method to be enhanced
Description method 1: Execute the parameterless update method in the UserDao interface under the com.tomy.dao package
execution(void com.tomy.dao.UserDao.update())
Description method 2: Execute the parameterless update method in the UserDaoImpl class under the com.tomy.dao.impl package
execution(void com.tomy.dao.impl.UserDaoImpl.update())
-
Pointcut expression standard format: action keyword (access modifier return value package name. class/interface name. method name (parameter) exception name)
- Action keywords: describe the behavior of the entry point, for example, execution means to execute to the specified entry point
- Access modifiers: public, private, etc., can be omitted
- return value
- Package names
- class/interface name
- method name
- parameter
- Exception name: The specified exception is thrown in the method definition, which can be omitted
-
You can use wildcards to describe pointcuts, and quickly describe
-
*: A single independent arbitrary symbol, which can appear independently or as a prefix or suffix match
execution(public * com.tom..UserService.find(*))
Match all methods with one parameter starting with find in the UserService class or interface in any package under the com.tomy package
-
… : Multiple consecutive arbitrary symbols, which can appear independently, are often used to simplify the writing of package names and parameters
execution(public User com...UserService.findById(...))
Matches all methods named findById in the UserService class or interface class in any package under the com package
-
+: dedicated to matching subclass types
execution(* * ... * Service+.*(...))
-
-
AOP notification type
-
The AOP notification describes the extracted common functions. According to the location of the common function extraction, it should be added to a reasonable position when the code is finally run.
-
Name: @Around (key, commonly used)
-
Type: method annotation
-
Location: Above the notification method definition
-
Function: Set the binding relationship between the current notification method and the pointcut, the current notification method runs before and after the original pointcut method
-
example:
@Around("pt()") public Object aroud(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around before advice..."); Object ret = pjp.proceed(); System.out.println("around after advice..."); return ret; }
-
@Around Notes
-
The surrounding notification must rely on the formal parameter ProceedingJoinPoint to realize the call to the original method, and then add notification before and after the original method call
-
If the original method is called without ProceedingJoinPoint in the rule, the execution of the original method will be skipped
-
The call to the original method does not need to receive the return value, and the notification method can be set to void. If the return value is received, it must be set to Object type
-
If the return value of the original method is void type, the return value type of the notification method can be set to void or Object
-
Since it is impossible to predict whether an exception will be thrown after the original method runs, the surrounding notification method must throw a Throwable object
@Around("pt()") public Object aroud(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around before advice..."); Object ret = pjp.proceed(); System.out.println("around after advice..."); return ret; }
-
-
Name: @AfterReturning (Understanding)
-
Type: method annotation
-
Position: above the notification method
-
Function: Set the binding relationship between the current notification method and the entry point. The current notification method runs after the original entry point method is executed normally.
-
example:
@AfterReturning("pt()") public void afterReturning() { System.out.println("afterReturning advice..."); }
-
Related attributes: value (default): pointcut method name, formatted as type.methodname()
AOP notification to get data
-
Get the parameters of the pointcut method
- JoinPoint: Applicable to pre-, post-, post-return, and post-throw notifications
- ProceedJointPoint: for surround notifications
-
Get the return value of the pointcut method
- Notify upon return
- surround notification
-
Obtain the exception information of the entry point method
- Notify when an exception is thrown
- surround notification
-
The JoinPoint object describes the running status of the join point method, and can obtain the call parameters of the original method
@Before("pt()") public void before(JoinPoint jp) { Object[] args = jp.getArgs(); System.out.println(Arrays.toString(args)); }
-
ProceedingJoinPoint is a subclass of JoinPoint
@Around("pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { Object[] args = jp.getArgs(); System.out.println(Arrays.toString(args)); Object ret = pjp.proceed(); return ret; }
-
After throwing an exception, the notification can obtain the exception information that appears in the entry point method, and use the formal parameter to receive the corresponding exception information
@AfterReturning(value = "pt()",returning = "ret") public void afterReturning(String ret) { System.out.println("afterReturning advice..." + ret); }
-
The call to the original method can be manually written in the surround notification, and the result obtained is the return value of the original method
@Around("pt()") public Object around(ProceedingJoinPoint pjp) throws Throwable { Object ret = pjp.proceed(); return ret; }
10.Spring transaction
Introduction to Spring Transactions
-
Transaction role: guarantee a series of database operations at the data layer with success and failure
-
The role of Spring transactions: to ensure that a series of database operations succeed and fail at the data layer or business layer
public interface PlatformTransactionManager { void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
public class DataSourceTransactionManager { ...... }
Example: bank account transfer
-
Add Spring transaction management on the business layer interface
//@Transactional public interface AccountService { @Transactional public void transfer(String out,String in,Double money); }
- Spring annotation transactions are usually added to the business interface but not to the business layer implementation, reducing coupling
- Annotated transactions can be added to business methods to indicate that the current method starts transactions, or can be added to interfaces to indicate that all methods of the current interface start transactions
-
Set transaction manager
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { DataSourceTransactionManager ptm = new DataSourceTransactionManager(); ptm.setDataSource(dataSource); return ptm; }
- The transaction manager is chosen based on the technology
- The MyBatis framework uses JDBC transactions
-
Enable annotation-style transaction-driven
@EnableTransactionManagement public class SpringConfig { }
Spring transaction roles
- Transaction manager: the initiator of the transaction, which usually refers to the method of opening the transaction in the business layer in Spring
- Transaction coordinator: Join the transaction party, usually refers to the data layer method in Spring, or the business layer method
Spring transaction related configuration
Attributes | effect | example |
---|---|---|
readOnly | Set whether it is a read-only transaction | readOnly=true read-only transaction |
timeout | Set transaction timeout | timeout = -1 (never timeout) |
rollbackFor | Set transaction rollback exception (class) | rollbackFor = {NullPointException.class} |
rollbackForClassName | Set transaction rollback exception (String) | same format as string |
noRollbackFor | Set transaction not to rollback exception (class) | noRollbackFor = {NullPointException.class} |
noRollbackForClassName | Set transaction rollback exception (class) | same format as string |
propagation | Set transaction propagation behavior | ... |
communication behavior | Affairs administrator | business coordinator |
---|---|---|
REQUIRED (default) | Turn on T | Join T |
none | New T2 | |
REQUIRES_NEW | Turn on T | New T2 |
none | New T2 | |
SUPPORTS | Turn on T | Join T |
none | none | |
NOT_SUPPORTED | Turn on T | none |
none | none | |
MANDATORY | Turn on T | Join T |
none | ERROR | |
NEVER | Turn on T | ERROR |
none | none | |
NESTED | Set savePoint, once the transaction is rolled back, the transaction will be rolled back to savePoint, and the client will respond to commit/rollback |
SpringMVC
Overview of Spring MVC
-
SpringMVC technology is equivalent to Servlet technology, both belong to web layer development technology
-
SpringMVC is a lightweight Web framework that implements the MVC model based on Java
- Simple to use and convenient to develop (compared to Servlet)
- Strong flexibility
SpringMVC entry case
-
To use SpringMVC technology, you need to import SpringMVC coordinates and Servlet coordinates first
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency>
-
Create a SpringMVC controller class (equivalent to Servlet functionality)
@Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save() { System.out.println("user save..."); return "{'info':'springmvc'}"; } }
-
Initialize the SpringMVC environment (same as the Spring environment), and set SpringMVC to load the corresponding Bean
@Configuration @ComponentScan("com.tomy.controller") public class SpringMvcConfig { }
-
Initialize the Servlet container, load the SpringMVC environment, and set the request processed by SpringMVC technology
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } protected String[] getServletMappings() { return new String[]{"/"}; } protected WebApplicationContext createRootApplicationContext() { return null; } }
-
Name: @Controller
-
Type: class annotation
-
Location: Above the SpringMVC controller class definition
-
Role: Set the core controller Bean of SpringMVC
-
example:
@Controller public class UserController { }
-
Name: @ResponseBody
-
Type: method annotation
-
Location: Above the SpringMVC controller method definition
-
Function: Set the response content of the current controller method as the current return value without parsing
-
example:
@RequestMapping("/save") @ResponseBody public String save(){ System.out.println("user save..."); return "{'info':'springmvc'}"; }
-
Summary of SpringMVC entry program (1+N)
- one time job
- Create a project, set up a server, and load a project
- import coordinates
- Create a web container startup class, load the SpringMVC configuration, and set the SpringMVC request interception path
- SpringMVC core configuration class (set configuration class, scan controller package, load Controller controller Bean)
- work multiple times
- Define the controller class that handles the request
- Define the controller method for processing the request, and configure the mapping path (@RequestMapping) and return json data (@ResponseBody)
- one time job
-
The AbstractDispatcherServletInitializer class is an abstract class provided by SpringMVC to initialize the Web3.0 container
-
AbstractDispatcherServletInitializer provides three interface methods for users to implement
-
The createServletApplicationContext() method, when creating a Servlet container, loads the Bean corresponding to SpringMVC and puts it into the scope of the WebApplicationContext object, and the scope of the WebApplicationContext is the scope of the ServletContext, that is, the scope of the entire web container
protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; }
-
getServletMappings() method, set the request mapping path corresponding to SpringMVC, set to / means to intercept all requests, any request will be transferred to SpringMVC for processing
protected String[] getServletMappings() { return new String[]{"/"}; }
-
createRootApplicationContext() method, if you need to load non-SpringMVC corresponding beans when creating a Servlet container, use the current method, and use the same method as createServletApplicationContext()
protected WebApplicationContext createRootApplicationContext() { return null; }
-
-
Start the service initialization process
- The server starts, executes the ServletContainersInitConfig class, and initializes the web container
- Execute the createServletApplicationContext method to create a WebApplicationContext object
- Load SpringMvcConfig
- Execute @ComponentScan to load the corresponding Bean
- Load UserController, each @RequestMapping name corresponds to a specific method
- Execute the getServletMapping method and define that all requests pass through SpringMVC
-
single request process
- Send request to localhost/save
- The web container finds that all requests have passed through SpringMVC, and hands the requests to SpringMVC for processing
- Parsing the request path /save
- The corresponding method save() is executed by /save matching
- Execute save()
- It is detected that @ResponseBody directly returns the return value of the save() method as the response body to the requester
Bean loading control
Controller loading control and business Bean loading control
-
SpringMVC related beans (presentation layer beans)
-
Bean s controlled by Spring
- Business Bean (Service)
- Functional Bean (DataSource, etc.)
-
SpringMVC related Bean loading control
- The packages corresponding to the beans loaded by SpringMVC are all in the com.tomy.controller package
-
Spring related Bean loading control
- Method 1: Set the scanning scope of the Bean loaded by Spring to com.tomy, and exclude the Bean in the controller package
- Method 2: Set the scanning range of the Bean loaded by Spring to the precise range, such as service package, dao package, etc.
-
Name: @ComponentScan
-
Type: class annotation
-
example:
@Configuration @ComponentScan(value = "com.tomy", excludeFilters = @ComponentScan.Filter( type = FilterType.ANNOTATION, classes = Controller.class ) ) public class SpringConfig{ }
-
Attributes
- excludeFilters: exclude beans loaded in the scan path, need to specify the type (type) and specific items (classes)
- includeFilters: To load the specified Bean, you need to specify the category (type) and specific items (classes)
-
Bean loading format
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } }
request mapping path
-
Name: @RequestMapping
-
Type: method annotation class annotation
-
Location: Above the SpringMVC controller method definition
-
Function: Set the current controller method request access path, if set on the class, set the current controller method request access path prefix uniformly
-
example:
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("user save..."); return "{'module':'user save'}"; } }
-
Attributes:
- value (default): request access path, or access path prefix
Post request to solve Chinese garbled processing
-
Add a filter to the web container and specify a character set, a dedicated character filter is provided in the Spring-web package
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { //match character encoding filter protected Filter[] getServletFilters(){ CharacterEncodingFilter filter = new CharacterEncodingFilter(); filter.setEncoding("utf-8"); return new Filter[]{filter}; } }
request and response
request parameters
-
name: @RequestParam
-
Type: Parameter Annotation
-
Position: Before the SpringMVC controller method parameter definition
-
Role: the relationship between binding request parameters and processor method parameters
-
example:
@RequestMapping("/commonParamDifferentName") @ResponBody public String commonParamDifferentName(@RequestParam("name")String userName, int age) { System.out.println("Normal parameter passing userName ==> "+ userName); System.out.println("Normal parameter passing age ==> "+ age); return "{'module':'common param different name'}"; }
-
parameter:
- required: whether it is a required parameter
- defaultValue: parameter default value
-
POJO parameter: The name of the request parameter is the same as the property name of the parameter object, and the parameter can be received by defining the POJO type parameter
@RequestMapping("/pojoParam") @ResponseBody public String pojoParam(User user) { System.out.println("pojo Parameter passing user ==> "+ user); return "{'module':'pojo param'}"; }
-
Nested POJO parameters: POJO objects contain POJO objects
public class User { private String name; private int age; private Address address; } public class Address { private String province; private String city; }
-
Nested POJO parameters: The request parameter name is the same as the formal parameter object attribute name, and nested POJO attribute parameters can be received according to the object hierarchy relationship
@RequestMapping("/pojoContainPojoParam") @ResponseBody public String pojoContainPojoParam(User user) { System.out.println("pojo nesting pojo Parameter passing user ==> "+ user); return "{'module':'pojo contain pojo param'}"; }
-
Array parameter: The request parameter name is the same as the attribute name of the formal parameter object and there are multiple request parameters. Define the array type parameter to receive the parameter
@RequestMapping("/arrayParam") @ResponseBody public String arrayParam(String[] likes) { System.out.println("Array parameter passing likes ==> "+ Arrays.toString(likes)); return "{'module':'array param'}"; }
-
The collection saves ordinary parameters: the request parameter name is the same as the formal parameter collection object name and there are multiple request parameters, @RequestParam binds the parameter relationship
@RequestMapping("/listParam") @ResponseBody public String listParam(@RequestParam List<String> likes) { System.out.println("Collection parameter passing likes ==> "+ likes); return "{'module':'list param'}"; }
JSON data passing parameters
-
Add json data conversion related coordinates
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
-
Set to send json data (add json data to the request body (raw))
-
Enable support for automatic conversion of json data
@Configuration @ComponentScan("com.tomy.controller") @EnableWebMvc public class SpringMvcConfig { }
- The @EnableWebMvc annotation is powerful. This annotation integrates multiple functions. Only some of them are used here, that is, automatic type conversion of json data.
-
Set to receive json data
@RequestMapping("/listParamForJson") @ResponseBody public String listParamForJson(@RequestBody List<String> likes) { System.out.println("list common(json)Parameter passing list ==> "+ likes); return "{'module':'list common for json param'}"; }
-
Name: @EnableWebMvc
-
Type: configuration class annotation
-
Location: Above the SpringMVC configuration class definition
-
Role: Enable multiple auxiliary functions of SpringMVC
-
example:
@Configuration @ComponentScan("com.tomy.controller") @EnableWebMvc public class SpringMvcConfig { }
-
Name: @ResponseBody
-
Type: Parameter Annotation
-
Position: Before the SpringMVC controller method parameter definition
-
Function: Pass the data contained in the request body in the request to the request parameters. This annotation can only be used once for a processor method
-
example:
@RequestMapping("/listParamForJson") @ResponseBody public String listParamForJson(@RequestBody List<String> likes) { System.out.println("list common(json)Parameter passing list ==> "+ likes); return "{'module':'list common for json param'}"; }
The difference between @RequestBody and @RequestParam
- the difference
- @RequestParam is used to receive url address pass parameters, form pass parameters [application/x-www-form-urlencoded]
- @RequestBody is used to receive json data [application/json]
- application
- In the later stage of development, the data in json format is mainly sent, and @RequestBody is widely used
- If you send data in non-json format, use @RequestParam to receive the request data
Date type parameter passing
-
Date type data is based on different formats of the system and is not the same
- 2023-01-01
- 2023/01/01
- 01/01/2023
-
When receiving formal parameters, set different receiving methods according to different date formats
@RequestMapping("/dataParam") @ResponseBody public String dataParam(Date date, @DateTimeFormat(pattern = "yyyy-MM-dd") Date date2, @DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date3) { System.out.println("Parameter passing date ==> " + date); System.out.println("Parameter passing date(yyyy-MM-dd) ==> " + date2); System.out.println("Parameter passing date(yyyy/MM/dd HH:mm:ss) ==> " + date3); return "{'module':data param}"; }
http://localhost/dataParam?date=2023/01/01&date2=2023-01-01&date3=2023/01/01 8:00:00
-
Name: @DateTimeFormat
-
Type: Parameter Annotation
-
Position: In front of SpringMVC controller method formal parameters
-
Function: set the date and time data format
-
example:
@RequestMapping("/dataParam") @ResponseBody public String dataParam(Date date) { System.out.println("Parameter passing date ==> " + date); return "{'module':'date param'}"; }
-
Attribute: pattern: datetime format string
type converter
-
Converter interface
public interface Converter<S, T> { @Nullable T convert(S source); }
-
Request parameter age data (String->Integer)
-
Date format conversion (String->Date)
-
One of the functions of @EnableWebMvc: the pattern type matches the corresponding type converter
response
-
Name: @ResponseBody
-
Type: method annotation
-
Location: Above the SpringMVC controller method definition
-
Function: set the current controller return value as the response body
-
example:
@RequestMapping("/save") @ResponseBody public String save() { System.out.println("save..."); return "{'info':'springmvc'}"; }
-
HttpMessageConverter interface
public interface HttpMessageConverter<T> { boolean canRead(Class<?> var1, @Nullable MediaType var2); boolean canWrite(Class<?> var1, @Nullable MediaType var2); List<MediaType> getSupportedMediaTypes(); T read(Class<? extends T> var1, HttpInputMessage var2) throws IOException, HttpMessageNotReadableException; void write(T var1, @Nullable MediaType var2, HttpOutputMessage var3) throws IOException, HttpMessageNotWritableException; }
REST style
-
REST(Representational State Transfer), representational state transfer
-
Traditional Style Resource Description Form
http://localhost/user/getById?id=1
http://localhost/user/saveUser
-
REST style description form
http://localhost/user/1
http://localhost/user
-
-
sort of:
- Hiding the resource access behavior, it is impossible to know what kind of operation is performed on the resource through the address
- writing simplification
-
Follow the REST style to access resources and use behavior actions to distinguish what operations are performed on resources
- http://localhost/users Query all user information GET (query)
- http://localhost/users/1 query specified user information GET (query)
- http://localhost/users Add user information POST (add/save)
- http://localhost/users Modify user information PUT (modify/update)
- http://localhost/users/1 delete user information DELETE (delete)
-
Accessing resources according to the REST style becomes RESTful
-
The above-mentioned behavior is an agreed method, and the agreement is not a specification and can be broken, so it is called REST style, not REST specification.
The name of the description module usually uses a plural number, that is, the format description with s added, indicating this type of resource instead of a single resource.
For example: users, accounts...
-
Set http request action (verb)
@RequestMapping(value = "/users", method = RequestMethod.POST) @ResponseBody public String save(@ResponseBody User user) { System.out.println("user save..." + user); return "{'module':'user save'}"; } @RequestMapping(value = "/users", method = RequestMethod.PUT) @ResponseBody public String update(@ResponseBody User user) { System.out.println("user update..." + user); return "{'module':'user update'}"; }
-
Set request parameters (path variables)
@RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable Integer id) { System.out.println("user delete..." + id); return "{'module':'user delete'}"; }
-
Name: @RequestMapping
-
Type: method annotation
-
Location: Above the SpringMVC controller method definition
-
Role: set the current controller method request access path
-
example:
@RequestMapping(value = "/users", method = RequestMethod.POST) @ResponseBody public String save(@ResponseBody User user) { System.out.println("user save..." + user); return "{'module':'user save'}"; }
-
Attributes:
- value (default): request access path
- method: http request action, standard action (GET/POST/PUT/DELETE)
-
Name: @PathVariable
-
Type: Parameter Annotation
-
Position: Before the SpringMVC controller method parameter definition
-
Function: bind the relationship between the path parameter and the formal parameter of the processor method, requiring a one-to-one correspondence between the path parameter name and the formal parameter name
-
example:
@RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable Integer id) { System.out.println("user delete..." + id); return "{'module':'user delete'}"; }
@RequestBody @RequestParam @PathVariable
- the difference
- @RequestParam is used to receive url address or form parameters
- @RequestBody is used to receive json data
- @PathVariable is used to receive path parameters, use {parameter name} to describe path parameters
- application
- In the later stage of development, more than one request parameter is sent, mainly in json format, and @RequestBody is widely used
- If you send non-json data, use @RequestParam to receive request parameters
- Use RESTful for development. When the number of parameters is small, such as 1, you can use @PathVariable to receive the variable of the request path, which is usually used to pass the id value
RESTful rapid development
-
Name: @RestController
-
Type: class annotation
-
Location: Above the controller class definition for RESTful development based on SpringMVC
-
Function: Set the current controller class to RESTful style, which is equivalent to the combination of @Controller and @ResponseBody annotations
-
example:
@RestController public class BookController{ }
-
Name: @GetMapping @PostMapping @PutMapping @DeleteMapping
-
Type: method annotation
-
Location: Above the definition of the controller method for RESTful development based on SpringMVC
-
Function: Set the current controller method request access path and request action, each corresponding to a request action, for example, @GetMapping corresponds to a GET request
-
example:
@GetMapping("/{id}") public String getById(@PathVariable Integer id) { System.out.println("user getById..." + id); return "{'module':'user getById'}"; }
-
Attributes
- value (default): request access path
-
Access release of static resources
@Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { protected void addResourceHandlers(ResourceHandlerRegistry registry) { //When accessing /pages/???, go to the contents of the /pages directory registry.addResourceHandler("/pages/**").addResourceLocations("/pages"); registry.addResourceHandler("/css/**").addResourceLocations("/css"); registry.addResourceHandler("/js/**").addResourceLocations("/js"); } }
Presentation Layer Data Encapsulation
-
After the addition, deletion, and modification operations at the Controller layer are completed, the data returned to the front end is boolean type data
true
-
Query a single at the Controller layer, and return the object to the front end
{ "id": 1, "type": "computer theory", "name": "Spring Combat Fifth Edition", "description": "Spring Introductory classic tutorial, in-depth understanding Spring Principle Technology Insider" }
-
Query all at the Controller layer, and what is returned to the front end is a collection object
[ { "id": 1, "type": "computer theory", "name": "Spring Combat Fifth Edition", "description": "Spring Introductory classic tutorial, in-depth understanding Spring Principle Technology Insider" }, { "id": 2, "type": "computer theory", "name": "Spring 5 Core Principles and Handwriting Practice in 30 Classes", "description": "Ten years of accumulated work, handwritten Spring Essence of thought" }, ... ]
-
Set the unified data return result class
public class Result { private Object data; private Integer code; private String msg; }
-
In order to encapsulate the returned result data: Create a result model class and encapsulate the data into the data attribute
In order to encapsulate what kind of operation the returned data is and whether the operation is successful: encapsulate the result into the code attribute
After the operation fails, it is necessary to encapsulate and return an error message to prompt the user: encapsulate the special message into the msg attribute
-
The fields in the Result class are not fixed and can be increased or decreased as needed
Provide several construction methods for easy operation
-
Set unified data return result encoding
public class Code { public static final Integer SAVE_OK = 20011; public static final Integer UPDATE_OK = 20021; public static final Integer DELETE_OK = 20031; public static final Integer GET_OK = 20041; public static final Integer SAVE_ERR = 20010; public static final Integer UPDATE_ERR = 20020; public static final Integer DELETE_ERR = 20030; public static final Integer GET_ERR = 20040; }
-
The constant design of the Code class is not fixed, you can increase or decrease according to your needs, for example, subdivide the query into GET_OK, GET_ALL_OK, GET_PAGE_OK
-
Set a reasonable Result according to the situation
@RequestMapping("/books") public class BookController { @Autowired private BookService bookService; @GetMapping("/{id}") public Result getById(@PathVariable Integer id) { Book book = bookService.getById(id); Integer code = book != null ? Code.GET_OK : Code.GET_ERR; String msg = book != null ? "" : "Data query failed, please try again!" : ""; return new Result(code, book, msg); } }
Unified exception handling
exception handler
-
Unavoidable exceptions will be encountered in the process of program development
-
Common locations and common causes of abnormal phenomena are as follows:
- Exception thrown inside the framework: caused by non-compliant use
- Exception thrown by the data layer: caused by failure to use an external server (for example: server access timeout)
- Exceptions thrown by the business layer: caused by business logic writing errors (for example: traversing business writing operations, causing index out-of-bounds exceptions, etc.)
- Exceptions thrown by the presentation layer: caused by rules such as data collection and verification (for example: conversion between mismatched data types causes exceptions)
- Exceptions thrown by tool classes: due to imprecise writing of tool classes and insufficient robustness (for example: connection released when necessary, not released for a long time, etc.)
-
Exceptions occur at all levels, which layer is the exception handling code written in?
– All exceptions are thrown to the presentation layer for processing
-
The presentation layer handles exceptions, each method is written separately, the amount of code writing is huge and the meaning is not strong, how to solve it – AOP idea
-
Centralized and unified processing of exceptions that occur in the project
@RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(Exception.class) public Result doException(Exception ex) { return new Result(666,null); } }
-
Name: @RestControllerAdvice
-
Type: class annotation
-
Position: Above the controller enhancement class definition for Rest-style development
-
Role: Enhance the controller class developed in Rest style
-
example:
@RestControllerAdvice public class ProjectExceptionAdvice { }
-
illustrate:
- This annotation comes with @ResponseBody annotation and @Component annotation, with corresponding functions
-
Name: @ExceptionHandler
-
Type: method annotation
-
Location: above the controller method dedicated to exception handling
-
Function: Set the processing plan for the specified exception. The function is equivalent to the controller method. After an exception occurs, the execution of the original controller is terminated and transferred to the current method for execution.
-
example:
@RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(Exception.class) public Result doException(Exception ex) { return new Result(666,null); } }
-
illustrate
- This type of method can make multiple methods to handle the corresponding exceptions according to the exceptions handled
Project exception handling plan
-
Item Anomaly Classification
- Business exception (BusinessException)
- Anomalies generated by normative user behavior
- Abnormalities caused by irregular user behavior operations
- System exception (SystemException)
- Predictable and unavoidable exceptions during project operation
- Other exceptions (Exception)
- Exceptions that the programmer did not expect
- Business exception (BusinessException)
-
Project exception handling plan
- Business exception (BusinessException)
- Send the corresponding message to the user to remind the standard operation
- System exception (SystemException)
- Send a fixed message to the user to appease the user
- Send specific messages to operation and maintenance personnel to remind maintenance
- record log
- Other exceptions (Exception)
- Send a fixed message to the user to appease the user
- Send specific messages to operation and maintenance personnel to remind maintenance
- record log
- Business exception (BusinessException)
-
Project exception handling
-
Custom project system-level exceptions
public class SystemException extends RuntimeException { private Integer code; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public SystemException(Integer code, String message) { super(message); this.code = code; } public SystemException(Integer code, String message, Throwable cause) { super(message, cause); this.code = code; } }
-
Custom project business-level exceptions
public class BusinessException extends RuntimeException{ private Integer code; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public BusinessException(Integer code, String message) { super(message); this.code = code; } public BusinessException(Integer code, String message, Throwable cause) { super(message, cause); this.code = code; } }
-
Custom exception encoding (continuously supplemented)
public class Code { public static final Integer SYSTEM_UNKNOW_ERROR = 50001; public static final Integer SYSTEM_TIMEOUT_ERROR = 50002; public static final Integer PROJECT_VALIDATE_ERROR = 60001; public static final Integer PROJECT_BUSINESS_ERROR = 60002; }
-
Trigger a custom exception
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao bookDao; public User getById(Integer id){ if (id < 0){ throw new BusinessException(Code.PROJECT_BUSSINESS_ERROR,"Do not do illegal operations!"); return userDao.getById(id); } } }
-
Intercept and handle exceptions
@RestControllerAdvice public class ProjectExceptionAdvice { @ExceptionHandler(SystemException.class) public Result doSystemException(SystemException ex) { return new Result(ex.getCode(), null, ex.getMessage()); } @ExceptionHandler(BusinessException.class) public Result doBusinessException(BusinessException ex) { //logging (error stack) //send email to developer //Send a text message to the operation and maintenance personnel return new Result(ex.getCode(), null, ex.getMessage()); } @ExceptionHandler(Exception.class) public Result doException(Exception ex) { //logging (error stack) //send email to developer //Send a text message to the operation and maintenance personnel return new Result(Code.SYSTEM_UNKNOW_ERR, null, "The system is busy, please try again later!"); } }
-
Exception handler effect comparison
{ "data": { "id": 1, "type": "computer theory", "name": "Spring Actual Combat 5th Edition", "description": "Spring Introductory classic tutorial, in-depth understanding Spring Principle Technology Insider" }, "code": 20041, "msg": null }
{ "data": null, "code": 60002, "msg": "Do not do illegal operations!" }
-
interceptor
Interceptor concept
- Interceptor (Interceptor) is a mechanism for dynamically intercepting method calls, and dynamically intercepts the execution of controller methods in SpringMVC
- effect:
- Execute preset code before and after the specified method call
- Block execution of the original method
Difference between interceptor and filter
- Different ownership: Filter belongs to Servlet technology, Interceptor belongs to SpringMVC technology
- The interception content is different: Filter enhances all access, and Interceptor only enhances SpringMVC access
Interceptor entry case
-
Declare the Bean of the interceptor and implement the HandlerInterceptor interface (note: scan to load the Bean)
@Component //Note that the current class must be controlled by the Spring container public class ProjectInterceptor implements HandlerInterceptor { //What was executed before the original method call public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); return true; } //What to execute after the original method call public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); } //What to execute after the original method call completes public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); } }
-
Define the configuration class, integrate WebMvcConfigurationSupport, and implement the addInterceptor method (note: scan loading configuration)
public class SpringMvcSupport extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) { //Configure the interceptor, the interception path is /books, only /books will be intercepted, and /books/1 will not be intercepted registry.addInterceptor(projectInterceptor).addPathPatterns("/books"); } }
-
Add an interceptor and set the intercepted access path. Multiple paths can be set through variable parameters
public class SpringMvcSupport extends WebMvcConfigurationSupport { @Autowired private ProjectInterceptor projectInterceptor; @Override protected void addInterceptors(InterceptorRegistry registry) { //Configure the interceptor, the interception path is /books, only /books will be intercepted, and /books/1 will not be intercepted registry.addInterceptor(projectInterceptor).addPathPatterns("/books"); } }
-
Use the standard interface WebMvcConfigurer to simplify development (note: strong intrusion)
@Configuration @ComponentScan("com.tomy.controller") @EnableWebMvc //Implementing the WebMvcConfigurer interface can simplify development, but it is somewhat intrusive public class SpringMvcConfig implements WebMvcConfigurer { @Autowired private ProjectInterceptor projectInterceptor; public void addResourceHandlers(ResourceHandlerRegistry registry) { //Release for static resources registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); } public void addInterceptors(InterceptorRegistry registry) { //Configure interceptors registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*"); } }
- When there is an interceptor, the request will first enter the preHandler method
- If the method returns true, the release will continue to execute the subsequent handle (Controller's method) and subsequent methods
- If false is returned, the execution of the following method will be skipped directly
interceptor parameters
-
Preprocessing
//What was executed before the original method call public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); return true; }
-
parameter
- request: request object
- response: response object
- handler: The invoked processor object is essentially a method object that repackages the Method object in reflection
-
return value
- If the return value is false, the intercepted processor will not execute
-
post processing
//What to execute after the original method call public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); }
-
parameter
- modelAndView: If the processor execution is completed and has a return result, you can read the corresponding data and page information and make adjustments
-
Processing after completion
//What to execute after the original method call completes public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); }
-
parameter:
- ex: If an exception object occurs during the execution of the processor, it can be handled separately for the exception
Interceptor execution order
-
When multiple interceptors are configured, an interceptor chain is formed
-
Create interceptor class
@Component //Note that the current class must be controlled by the Spring container public class ProjectInterceptor2 implements HandlerInterceptor { //What was executed before the original method call public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle..222"); return true; } //What to execute after the original method call public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle..222"); } //What to execute after the original method call completes public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion..222"); } }
-
Enter the SpringMvcConfig configuration class to configure multiple interceptors
@Configuration @ComponentScan("com.tomy.controller") @EnableWebMvc public class SpringMvcConfig implements WebMvcConfigurer { @Autowired private ProjectInterceptor projectInterceptor; @Autowired private ProjectInterceptor2 projectInterceptor2; public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor).addPathPatterns("/books", "/books/*"); registry.addInterceptor(projectInterceptor2).addPathPatterns("/books", "/books/*"); } }
-
-
The running order of interceptors refers to the order in which interceptors are added
-
When the interception of the original processor occurs in the interceptor, the subsequent interceptors will all terminate
-
When the interceptor is interrupted, only the afterCompletion operation configured in the previous interceptor will be run
-
preHandle: same as configuration order, must run
-
postHandle: in reverse order of configuration, may not run
-
afterCompletion: May not run in reverse order of configuration.
SpringBoot
SpringBoot starter
- Create a new module, select Spring Initializr initialization, and configure basic information about the module
- Select the technology set that the current module needs to use
- Develop controller class
- Run the automatically generated Application class
Introduction to Spring
-
Comparison of Spring program and SpringBoot program
class/config file Spring SpringBoot Coordinates in the pom file Add manually Tick to add web3.0 configuration class Handmade none Spring/SpringMVC configuration class Handmade none controller Handmade Handmade -
Create a project based on SpringBoot official website
https://start.spring.io/
SpringBoot project quick start
-
Package the SpringBoot project (execute the Maven build instruction package) to generate the corresponding jar package in the target directory.
-
Execute the start command
java -jar springboot.jar
-
The jar supports command-line startup and needs to rely on maven plug-in support. It is necessary to confirm whether there is a Maven plug-in corresponding to SpringBoot when packaging.
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
Overview of Spring Boot
- SpringBoot is a new framework provided by the Pivotal team, which is designed to simplify the initial construction and development process of Spring applications.
- The following problems exist in the original Spring environment construction and development
- Configuration is cumbersome
- Dependency settings are cumbersome
- The advantages of the SpringBoot program happen to be aimed at the shortcomings of Spring
- Automatic configuration.
- Start depends.
- Accessibility (built-in server, ...). When starting the SpringBoot program, neither the local tomcat nor the tomcat plug-in is used, but the built-in server of SpringBoot is used.
SpringBoot starting dependency
<parent> <groupId>org.springframework.boot</groupId> <!-- ↓↓↓ --> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.9</version> <relativePath/> </parent> <groupId>com.tomy</groupId> <artifactId>springboot_study</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <!-- ↓↓↓ --> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <!-- ↓↓↓ --> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
- starter
- The common project name in SpringBoot defines all project coordinates used by the current project to achieve the purpose of reducing dependency configuration
- parent
- Projects to be inherited by all SpringBoot projects define several coordinate version numbers (dependency management, not dependencies) to reduce dependency conflicts
- actual development
- When using arbitrary coordinates, only write G and A in GAV, and V is provided by SpringBoot
- G: groupid
- A: artifactId
- V: version
- If a coordinate error occurs, specify the version again (be careful of version conflicts)
- When using arbitrary coordinates, only write G and A in GAV, and V is provided by SpringBoot
SpringBoot program starts
-
start method
@SpringBootApplication public class SpringBootStudyApplication { public static void main(String[] args) { SpringApplication.run(SpringBootStudyApplication.class, args); } }
-
When SpringBoot creates a project, it uses the jar packaging method
-
The boot class of SpringBoot is the entry point of the project, and the project can be started by running the main method
-
Using Maven Dependency Management to Change Startup Dependencies
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--web Start dependent environment, exclude Tomcat Start dependency--> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <!--Add to Jetty Starting dependencies, version by SpringBoot of starter control--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> </dependencies>
-
Jetty is more lightweight and scalable than Tomcat (compared to Tomcat), Google Application Engine (GAE) has been fully switched to Jetty
basic configuration
configuration format
-
Modify server port
Now the default port number to start the server is 8080, and the access path can be written as
http://localhost:8080/books/1In the online environment, I still hope to change the port number to 80, so that the port number can not be written when accessing, as follows
http://localhost/books/1 -
SpringBoot provides a variety of property configuration methods
-
application.properties
server.port=80
-
application.yml
server: port: 81
-
application.yaml
server: port: 82
-
yaml
- YAML (YAML Ain’t Markup Language), a data serialization format
- advantage:
- easy to read
- Easy to interact with scripting languages
- Take data as the core, pay more attention to data than format
- YAML file extension
- .yml (mainstream)
- .yaml
yaml syntax rules
-
Case Sensitive
-
The attribute hierarchy is described in multiple lines, and the end of each line is terminated with a colon
-
Use indentation to indicate hierarchical relationships, align to the left of the same level, and only spaces are allowed (Tab keys are not allowed)
-
The number of spaces is not important, as long as the left alignment of the same level is guaranteed.
-
Add a space before the attribute value (a colon + space is used as a separator between the attribute name and the attribute value)
-
#Represents comments
- Core rules: data should be preceded by a space and a colon to separate
-
The array data uses a minus sign as the data start symbol below the data writing position, and writes one data per line, and the minus sign and the data are separated by spaces
enterprise: name: tomy age: 22 tel: 131xxxxxxxx subject: - Java - Python - C#
yaml configuration file data reading
-
Use @Value to read a single data, attribute name reference method: ${first-level attribute name.second-level attribute name...}
lesson: SpringBoot server: port: 82 enterprise: name: tomy age: 22 tel: 131xxxxxxxx subject: - Java - Python - C#
-
You can use the @Value annotation in BookController to read the matching file data
@RestController @RequestMapping("/books") public class BookController { @Value("${lesson}") private String lesson; @Value("${server.port}") private Integer port; @Value("${enterprise.subject[0]}") private String subject_0; @GetMapping("/{id}") public String getById(@PathVariable Integer id) { System.out.println(lesson); System.out.println(port); System.out.println(subject_0); return "hello , spring boot!"; } }
-
Encapsulate all data into Environment object
SpringBoot can also read data by injecting the Environment object using the @Autowired annotation. In this way, SpringBoot will encapsulate all the data in the configuration file into the Environment object. If you need to use which data, you only need to get it by calling the getProperty(String name) method of the Environment object.
@RestController @RequestMapping("/books") public class BookController { @Autowired private Environment environment; @GetMapping("/{id}") public String getById(@PathVariable Integer id) { System.out.println(environment.getProperty("lesson")); System.out.println(environment.getProperty("enterprise.name")); System.out.println(environment.getProperty("enterprise.subject[1]")); return "hello , spring boot!"; } }
-
Custom objects encapsulate specified data
@Component @ConfigurationProperties(prefix = "enterprise") public class Enterprise { private String name; private int age; private String tel; private String[] subject; }
-
Custom packaged data warning solution
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
multi-environment startup
-
Use --- in application.yml to separate different configurations, as follows
spring: profiles: active: dev --- # development environment spring: profiles: dev # A name for the development environment server: port: 80 --- # Production Environment spring: profiles: pro # The name given to the production environment server: port: 81 --- # test environment spring: profiles: test # Give the test environment a name server: port: 82 port: 82
-
The spring.profiles in the configuration are used to name the different configurations. Use spring.profiles.active to tell SpringBoot to enable a configuration
-
The spring.profiles configuration item in the above configuration that names the different configurations is obsolete. The recommended latest configuration item is
# development environment spring: config: activate: on-profile: dev # A name for the development environment
-
properties file multi-environment startup
-
The main startup configuration file application.properties
spring.profiles.active=pro
-
Environment classification configuration file application-pro.properties
server.port=80
-
Environment classification configuration file application-dev.properties
server.port=81
-
Environment classification configuration file application-test.properties
server.port=82
-
Multi-environment startup command format
-
Start SpringBoot with parameters
java -jar xxx.jar --spring.profiles.active=test
-
Temporarily modify the port number to 8088
java -jar xxx.jar --server.port=8088
-
That is, specify which environment configuration to enable, and temporarily specify the port
java -jar xxx.jar -server.port=8088 --spring.profiles.active=pro
Multi-environment development control
Maven is compatible with SpringBoot multi-environment
-
Set multi-environment properties in Maven
<profiles> <!--development environment--> <profile> <id>dev</id> <properties> <profile.active>dev</profile.active> </properties> </profile> <!--Production Environment--> <profile> <id>pro</id> <properties> <profile.active>pro</profile.active> </properties> </profile> <!--test environment--> <profile> <id>test</id> <properties> <profile.active>test</profile.active> </properties> </profile> </profiles>
-
Reference Maven properties in SpringBoot
spring: profiles: active: ${profile.active} --- spring: config: activate: on-profile: dev server: port: 80 --- spring: profiles: pro server: port: 81 --- spring: profiles: test server: port: 82
-
Execute Maven packaging instructions
-
After the execution of the Maven command is completed, the corresponding package is generated, in which the class participates in compilation, but the configuration file is not compiled, but copied into the package
-
Solution: For the operation of non-Java classes in the source code, it is required to load the corresponding properties of Maven, and parse the ${} placeholder
Enable parsing of default placeholders for resource files
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.2.0</version> <configuration> <encoding>UTF-8</encoding> <useDefaultDelimiters>true</useDefaultDelimiters> </configuration> </plugin> </plugins> </build>
-
Profile Classification
-
Level 4 configuration files in SpringBoot
Level 1: file: config/application.yml [highest]
Level 2: file: application.yml
Level 3: classpath:config/application.yml
Level 4: classpath: application.yml [Minimum]
-
effect:
- Level 1 and Level 2 are reserved for setting common properties after system packaging
- Levels 3 and 4 are used to set common attributes during the system development phase
Integrate third-party technology
Integrate JUnit
-
SpringBoot integrates JUnit
-
Create BookService interface under com.tomy.service package
public interface BookService { void save(); }
-
Create an implementation class of the BookService interface under the com.tomy.service.impl package, and rewrite its methods
@Service public class BookServiceImpl implements BookService { @Override public void save() { System.out.println("book service is running .."); } }
-
write test class
Create a com.tomy package under test/java, create a test class under this package, and inject BookService into the test class
@SpringBootTest class SpringbootJunitApplicationTests { @Autowired private BookService bookService; @Test void contextLoads() { bookService.save(); } }
Run the save() test method, the console successfully outputs
-
-
Name: @SpringBootTest
-
Type: Test class annotation
-
Location: Above the test class definition
-
Function: Set the SpringBoot startup class loaded by JUnit
-
example:
@SpringBootTest(classes = SpringbootJunitApplicationTests.class) class SpringbootJunitApplicationTests {}
-
related attributes
- classes: Set the SpringBoot startup class
-
Precautions
If the test class is in the package or subpackage of the SpringBoot startup class, the setting of the startup class can be omitted, that is, the setting of classes can be omitted
Integrate MyBatis
SpringBoot integrates MyBatis
-
Create a new module, select Spring initialization, and configure basic information about the module
-
Select the technology set that the current module needs to use (MyBatis, MySQL) MyBatis Framework, MySQL Driver
-
Set data source parameters
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/db_name username: username password: password
-
Precautions:
When the SpringBoot version is lower than 2.4.3 (not included), and the MySQL driver version is higher than 8.0, the time zone needs to be configured in the url connection string
url: jdbc:mysql://localhost:3306/db_name?serverTimezone=UTC
Or configure the time zone on the MySQL database side to solve this problem
-
-
Define the data layer interface and mapping configuration
@Mapper public interface UserDao { @Select("SELECT * FROM user") public List<User> getAll(); }
MyBatis-Plus
MyBaitsPlus Getting Started Case
-
SpringBoot integrates MyBatisPlus development process
-
Create a SpringBoot project
-
Check the technology used by the configuration
-
Manually add MyBatisPlus starter dependencies
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.3</version> </dependency>
- Since MyBatisPlus has not been included in IDEA's system built-in configuration, it cannot be directly selected to join
-
Set dataSource related properties (JDBC parameters) – application.yml
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/springboot_db?serverTimezone=UTC username: username password: password
- If you use the Druid data source, you need to import the corresponding coordinates
- Make entity classes and table structures (class names correspond to table names, attribute names correspond to field names)
CREATE TABLE user ( id bigint(20) not null auto_increment comment 'serial number', name varchar(32) character set utf8 collate utf8_general_ci not null comment 'username', password varchar(32) character set utf8 collate utf8_general_ci not null comment 'password', age int(3) not null comment 'age', tel varchar(32) character set utf8 collate utf8_general_ci not null comment 'Telephone' ); insert into user values(1,'Tom','tom',3,'18866668888'); insert into user values(2,'Jerry','jerry',4,'16688886666'); insert into user values(3,'Jock','123456',41,'18812345678');
public class User { private Long id; private String name; private String password; private Integer age; private String tel; }
- Note that id is of type Long
- Define and create Dao data interface, integrate BaseMapper
@Mapper public interface UserDao extends BaseMapper<User>{ }
- core steps
- Inject the Dao interface into the test class to test the function
@SpringBootTest class MybatisplusApplicationTests { @Autowired private UserDao userDao; @Test void contextLoads() { List<User> users = userDao.selectList(null); userList.forEach(System.out::println); } }
-
Introduction to MyBatisPlus
MyBatisPlus Features
- No intrusion: only enhancement and no change, the introduction of it will not affect the existing project, as smooth as silk
- Low loss: the basic CURD will be automatically injected at startup, with basically no loss in performance, and direct object-oriented operations
- Powerful CRUD operations: Built-in general-purpose Mapper and general-purpose Service can realize most of the CRUD operations of a single table with only a small amount of configuration, and a powerful conditional constructor to meet various usage needs
- Support Lambda form invocation: through Lambda expressions, it is convenient to write various query conditions, no need to worry about field typos
- Supports automatic primary key generation: supports up to 4 primary key strategies (including a distributed unique ID generator - Sequence), which can be freely configured to perfectly solve the primary key problem
- Support ActiveRecord mode: support ActiveRecord form calls, entity classes only need to inherit the Model class to perform powerful CRUD operations
- Support custom global general operations: support global general method injection ( Write once, use anywhere )
- Built-in code generator: use code or Maven plug-ins to quickly generate Mapper, Model, Service, and Controller layer codes, support template engines, and have a lot of custom configurations waiting for you to use
- Built-in paging plug-in: Based on MyBatis physical paging, developers don't need to care about specific operations. After configuring the plug-in, writing paging is equivalent to ordinary List query
- The paging plug-in supports multiple databases: supports MySQL, MariaDB, Oracle, DB2, H2, HSQL, SQLite, Postgre, SQLServer and other databases
- Built-in performance analysis plug-in: It can output SQL statements and their execution time. It is recommended to enable this function when developing and testing, which can quickly find out slow queries
- Built-in global interception plug-in: Provides intelligent analysis and blocking of delete and update operations on the entire table, and can also customize interception rules to prevent misoperations
Standard Data Layer Development
Function | custom interface | MyBatisPlus interface |
---|---|---|
Add | boolean save(T t) | int insert(T t) |
delete | boolean delete(int id) | int deleteById(Serializable id) |
Revise | boolean update(T t) | int updateById(T t) |
query by id | T getById(int id) | T selectById(Serializable id) |
query all | List getALL() | List selectList() |
Paging query | PageInfo getAll(int page,int size) | IPage selectPage(IPage page) |
query by condition | List getAll(Condition condition) | IPage selectPage(Wrapper queryWrapper) |
-
Add
int insert(T t)
- The parameter type is generic, that is, when we first inherited BaseMapper, we filled in the generic type, and the return value is int type, 0 means that the addition failed, and 1 means that the addition was successful
@Test void testInsert(){ User user = new User(); user.setName("Tomy"); user.setAge(23); user.setTel("131xxxxxxxx"); user.setPassword("tomy"); userDao.insert(user); }
- Just write the data of a User, run the program, and then go to the database to see if the addition is successful
1572364408896622593 Tomy MUSICIAN 23 131xxxxxxx
- Because the id is generated using the snowflake algorithm, and the data type is Long, so the corresponding entity class needs to set the id to Long
-
delete
int deleteByIds(Serializable id)
- Why is the parameter type a serialization class Serializable
- By looking at the source code of String, you will find that String implements the Serializable interface, and the Number class also implements the Serializable interface
- The Number class is the parent class of Float, Double, Long, etc.
- Now the data types that can be used as primary keys are already subclasses of the Serializable type.
- MP uses the Serializable type as the parameter type, just like we use the Object type to receive all types
- The return value type is int
- Data deleted successfully returns 1
- Returns 0 for undeleted data.
- Let's delete the data just added, pay attention to add an L at the end
@Test void testDelete(){ userDao.deleteById(1572364408896622593L); }
-
delete
int updateById(T t)
- T: Generic, the data content that needs to be modified, note that because it is modified according to the ID, the ID attribute value needs to be included in the incoming object
- int: return value
- Returns 1 after the modification is successful
- Unmodified data returns 0
@Test void testUpdate(){ User user = new User(); user.setId(1L); user.setName("Alen"); userDao.updateById(user); }
- The modification function only modifies the specified fields, and the unspecified fields remain as they are
-
query by id
T selectById (Serializable id)
- Serializable: parameter type, the value of the primary key ID
- T: query based on ID will only return one piece of data
@Test void testSelectById(){ User user = userDao.selectById(1); System.out.println(user); }
-
query all
List<T> selectList(Wrapper<T> queryWrapper)
- Wrapper: The conditions used to construct conditional queries, currently we do not have a direct pass as Null
@Test void testSelectAll() { List<User> userList = userDao.selectList(null); System.out.println(userList); }
lombok
-
Lombok, a Java class library, provides a set of annotations to simplify the development of POJO entity classes
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <!--<version>1.18.12</version>--> <!--<scope>provided</scope>--> </dependency>
- The version does not need to be written, the version of lombok has been managed in SpringBoot
- The common annotations of Lombok are:
- @Setter: Provides setter methods for attributes of model classes
- @Getter: Provides a getter method for an attribute of a model class
- @ToString: Provides the toString method for the attributes of the model class
- @EqualsAndHashCode: Provides equals and hashcode methods for attributes of model classes
- @Data: It is a combined annotation that contains the functions of the above annotations
- @NoArgsConstructor: Provide a no-argument constructor
- @AllArgsConstructor: Provide a constructor that contains all parameters
paging function
-
Set the pagination interceptor as a Spring-managed Bean
public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor myInterceptor = new MybatisPlusInterceptor(); myInterceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return myInterceptor; } }
-
Execute paging query
@Test void testSelectPage() { IPage<User> page = new Page(2, 3); userDao.selectPage(page, null); System.out.println("current page number" + page.getCurrent()); System.out.println("Articles on this page" + page.getSize()); System.out.println("total pages" + page.getPages()); System.out.println("total number" + page.getTotal()); System.out.println("current page data" + page.getRecords()); }
open log
# Log information of MybatisPlus mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
DQL programming control
Conditional query – set query conditions
-
Format 1: regular format
QueryWrapper<User> qw = new QueryWrapper<User>(); //Query users whose age is greater than or equal to 18 and younger than 65 qw.lt("age",65); qw.gt("age",18); List<User> userList = userDao.selectList(qw); System.out.println(userList);
-
Format 2: Chain programming format
QueryWrapper<User> qw = new QueryWrapper<User>(); //Query users whose age is greater than or equal to 18 and younger than 65 qw.lt("age",65).gt("age",18); List<User> userList = userDao.selectList(qw); System.out.println(userList);
-
Format 3: lambda format (recommended)
QueryWrapper<User> qw = new QueryWrapper<User>(); //Query users whose age is greater than or equal to 18 and younger than 65 qw.lambda().lt(User::getAge,65).gt(User::getAge,18); List<User> userList = userDao.selectList(qw); System.out.println(userList);
-
Format 4: lambda format (recommended)
LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<User>(); //Query users whose age is greater than or equal to 18 and younger than 65 qw.lambda().lt(User::getAge,65).gt(User::getAge,18); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
Conditional query – null value processing
-
When we do conditional query, there are usually many conditions for users to query
-
Users can choose to use these conditions, or they can choose not to
-
Before, we implemented it through dynamic SQL
<select id="selectByPageAndCondition" resultMap="brandResultMap"> select * from tb_brand <where> <if test="brand.brandName != null and brand.brandName != '' "> and brand_name like #{brand.brandName} </if> <if test="brand.companyName != null and brand.companyName != '' "> and company_name like #{brand.companyName} </if> <if test="brand.status != null"> and status = #{brand.status} </if> </where> limit #{begin} , #{size} </select>
-
If the background wants to receive two data from the front end, how should it be received?
-
We can use two simple data types, or we can use a model class, but there is currently only one age attribute in the User class
@Data @TableName("tb_user") //Table Name public class User { private Long id; private String name; private String password; private Integer age; private String tel; }
-
Using an age attribute, how to receive two values on the page? At this time we have two solutions
- Solution 1: Add attribute age2, this method can but will affect the attribute content of the original model class
- Solution 2: Create a new model class, let it inherit the User class, and add the age2 attribute to it, and UserQuery has added the User attribute at the same time
@Data @TableName("tb_user") public class UserQuery extends User{ private Integer age2; }
-
The if statement controls conditional appending
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); if(null != userQuery.getAge()){ lqw.ge(User::getAge,userQuery.getAge()); } if(null != userQuery.getAge2()){ lqw.lt(User::getAge,userQuery.getAge2()); } List<User> userList = userDao.selectList(lqw); System.out.println(userList);
-
The above writing method can complete the judgment that the condition is not empty, but the problem is obvious. If there are many conditions, each condition needs to be judged, and the amount of code is relatively large.
-
Condition parameter control
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); lqw.ge(null != userQuery.getAge(),User::getAge,userQuery.getAge()); lqw.lt(null != userQuery.getAge2(),User::getAge,userQuery.getAge2()); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
- A method of lt overload, when the condition is true, add the condition, when it is false, do not add the condition
-
Condition parameter control (chain programming)
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); lqw.ge(null != userQuery.getAge(),User::getAge,userQuery.getAge()) .lt(null != userQuery.getAge2(),User::getAge,userQuery.getAge2()); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
-
query projection
At present, when querying data, if nothing is done, the default is to query the contents of all fields in the table. The query projection we call does not query all fields, but only queries the data of the specified content.
-
The query result contains some attributes in the model
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); lqw.select(User::getId,User::getName,User::getAge); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
-
The query result contains a property that is not defined in the model
QueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); lqw.select("count(*) as count,tel"); lqw.groupBy("tel"); List<Map<String, Object>> userList = userDao.selectMaps(lqw); System.out.println(userList);
Query conditions
- range matching (> , = , between)
- Fuzzy matching (like)
- Empty judgment (null)
- inclusive match (in)
- group
- order
- ......
Equivalent query
Requirements: Query user information based on username and password
-
User login (eq match)
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); lqw.eq(User::getName,userQuery.getName()).eq(User::getPassword,userQuery.getPassword); User loginUser = userDao.selectOne(lqw); System.out.println(loginUser);
range query
Requirement: range query for age, use lt(), le(), gt(), ge(), between() for range query
-
Shopping cart setting to add an interval, household registration to set an age interval (le ge matching or between matching)
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>(); //Solution 1: Set upper and lower limits lqw.le(User::getAge,userQuery.getAge()).ge(User::getAge,userQuery.getAge2()); //Option 2: Set the scope lqw.between(User::getAge,userQuery.getAge(),userQuery.getAge2()); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
- gt(): greater than (>)
- ge(): greater than or equal to (>=)
- lt(): less than (<)
- lt e(): less than or equal to (<=)
- between():between ? and ?
fuzzy query
Requirements: Query the user information whose name attribute value starts with J in the query table, use like to perform fuzzy query
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>(); lqw.likeRight(User::getName,"J"); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
- like(): Add percent signs before and after, such as %J%, which is equivalent to the name containing J
- likeLeft(): Add a percent sign in front, such as %J, which is equivalent to the name at the end of J
- likeRight(): Add a percent sign after it, such as J%, which is equivalent to the name starting with J
Sort query
Requirement: Query all the data in the statistical report, and then sort by age in descending order
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>(); /** * condition : condition, return boolean, When the condition is true, sort it, if it is false, it will not sort * isAsc:Whether it is ascending order, true is ascending order, false is descending order * columns: Columns to operate on */ lqw.orderBy(true,false,User::getAge); List<User> userList = userDao.selectList(lqw); System.out.println(userList);
Field mapping and table name mapping
-
Problem 1: The design of table fields and encoding attributes is out of sync
CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(32), `pwd` varchar(32), `age` int(3), `tel` varchar(32), PRIMARY KEY(`id`) )
public class User { private Long id; private String name; @TableField(value="pwd") private String passowrd; private Integer age; private String tel; }
-
Question two:
CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(32), `pwd` varchar(32), `age` int(3), `tel` varchar(32), PRIMARY KEY(`id`) )
public class User { private Long id; private String name; @TableField(value="pwd") private String passowrd; private Integer age; private String tel; @TableField(exist = false) private Integer online; }
-
Question 3: More field viewing permissions are opened by default
SELECT id, name, pwd, age, tel, speciality FROM user
CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(32), `pwd` varchar(32), `age` int(3), `tel` varchar(32), PRIMARY KEY(`id`) )
public class User { private Long id; private String name; @TableField(value="pwd",select = false) private String passowrd; private Integer age; private String tel; @TableField(exist = false) private Integer online; }
-
name: @TableField
-
Type: Attribute Annotation
-
Location: Above the model class attribute definition
-
Function: Set the field relationship in the database table corresponding to the current attribute
-
example:
public class User { @TableField(value='pwd',select = false) private String password; @TableField(exist = false) private Integer online; }
-
Related properties:
- value (default): set the database table field name
- exist: Set whether the attribute exists in the database table field, the default is true. This attribute cannot be combined with value
- select: Whether to set the attribute to participate in the query, this attribute does not conflict with the select () mapping configuration
-
-
Question 4: The table name is not synchronized with the code development and design
CREATE TABLE `tbl_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(32), `pwd` varchar(32), `age` int(3), `tel` varchar(32), PRIMARY KEY(`id`) )
@Table_name("tbl_user") public class User { private Long id; private String name; @TableField(value="pwd",select = false) private String passowrd; private Integer age; private String tel; @TableField(exist = false) private Integer online; }
-
Name: @TableName
-
Type: class annotation
-
Location: above the model class definition
-
Role: set the current class corresponding to the database relationship
-
example:
@TableName("tbl_user") public class User { private Long id; }
-
Related attributes:
- value: set the database name
-
DML programming control
id generation policy control
-
Different tables apply different id generation strategies
- log: increment(1 2 3 4)
- Shopping order: special rules (offline shopping invoice, you can pay attention to it next time)
- Takeaway order: date and other information related to the region (I am familiar with this, for example, 10 04 20220921 13 14, for example, 10 means Beijing, 04 means Chaoyang District, 20220921 means date, etc.)
- Relational table: ID can be omitted
- ......
-
Name: @TableId
-
Type: Attribute Annotation
-
Location: above the definition of the property used to represent the primary key in the model class
-
Role: Set the generation strategy of the primary key attribute in the current class
-
example:
public class User { @TableId(type = IdType.AUTO) private Long id; }
-
Related properties:
- value: Set the database primary key name
- type: Set the generation strategy of the primary key attribute, the value refers to the IdType enumeration value
-
NONE: No id generation strategy is set
-
INPUT: The user manually enters the id
-
ASSIGN_ID: Snowflake algorithm generates id (compatible with numeric and string types)
-
ASSIGN_UUID: Use the UUID generation algorithm as the id generation strategy
-
Several other strategies are obsolete and will be replaced by ASSIGN_ID and ASSIGN_UUID.
global configuration
Model Class Primary Key Policy Settings
If you want to use the same generation strategy for each model class in the project, for example, if you have multiple tables such as Book table, User table, Student table, and Score table, if the primary key generation strategy of each of your tables is ASSIGN_ID , you can use the yml configuration file to simplify development, without adding @TableId(type = IdType.ASSIGN_ID) to the id of each table
Mapping relationship between database tables and model classes
MP will use the lowercase first letter of the class name of the model class as the table name by default. If the names of the database tables start with tb_, then we need to add @TableName("tb_TABLENAME") to all the model classes. Do this Very cumbersome, the simpler way is to modify the configuration file
mybatis-plus: global-config: db-config: id-type: assign_id table-prefix: tb_
Set the prefix content of the table, so that MP will use tb_ plus the first letter of the model class in lowercase, and it will just be assembled into the table name of the database (provided that your table name has a standard name, don’t make up a fancy name). Remove the @TableName annotation of the User class and run the new method again
@Data public class User { @TableId(type = IdType.ASSIGN_ID) private Long id; private String name; private String password; private Integer age; private String tel; }
multi-record operation
-
Delete multiple records by primary key
@Test void testDeleteByIds(){ ArrayList<Long> list = new ArrayList<>(); list.add(1572543345085964289L); list.add(1572554951983460354L); list.add(1572555035978534913L); userDao.deleteBatchIds(list); }
After the execution is successful, the data in the database table will be deleted according to the specified id. The above three data were added and inserted before, and can be replaced with any id in the database
-
Query multiple records based on primary key
@Test void testSelectByIds() { ArrayList<Long> list = new ArrayList<>(); list.add(1L); list.add(2L); list.add(3L); userDao.selectBatchIds(list); }
Tombstone
For the delete operation business problem there are:
-
Physical deletion: business data is discarded from the database, and the delete operation is performed
-
Logical deletion: set the availability status field for the data, set the status field to unavailable status when deleting, the data is kept in the database, and the update operation is performed
-
Step 1: Modify the database table and add the deleted column
Field name is arbitrary, type int, length 1, default value 0 -
Step 2: Add attributes to the entity class
You have to modify the corresponding POJO class and add the delete attribute (the attribute name is also arbitrary, sorry to use @TableField to add the mapping relationship
Identify the newly added field as a tombstone field, using @TableLogic
@Data public class User { private Long id; private String name; private String password; private Integer age; private String tel; //Add delete property //value is the value of in-service normal data (on-job), delval is the value of resigned deleted data (resigned) @TableLogic(value = "0",delval = "1") private Integer deleted; }
-
If each table needs logical deletion, then you need to add the @TableLogic annotation to the attributes of each model class, modify the configuration file optimization
mybatis-plus: global-config: db-config: # tombstone field name logic-delete-field: deleted # Tombstone literal: 0 for not deleted logic-not-delete-value: 0 # Tombstone literal: delete is 1 logic-delete-value: 1
- After configuring with the yml configuration file, there is no need to annotate the model class with @TableLogic
-
The essence of logical deletion is a modification operation. If a tombstone field is added, the tombstone field will be automatically added when querying data.
UPDATE tb_user SET deleted=1 WHERE id=? AND deleted=0
-
Name: @TableLogic
-
Type: Attribute Annotation
-
Location: above the definition of the property used to represent the deleted field in the model class
-
Role: identify the field as a field for logical deletion
-
example:
@Data public class User { //Add delete attribute //value is the value of in-service normal data (on-job), delval is the value of resigned deleted data (resigned) @TableLogic(value = "0",delval = "1") private Integer deleted; }
-
Related properties:
- value: Logical undeleted value
- delval: logical deletion value
optimistic lock
-
Add lock tag field to database table
Add a column version, the length is 11, and the default value is 1
-
Add the corresponding field to the entity class, and set the current field as the logical deletion mark field
@Data public class User { private Long id; @Version private Integer version; }
-
Configure the optimistic lock interceptor to realize the dynamic SQL statement assembly corresponding to the lock mechanism
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mpInterceptor() { //1. Define the Mp interceptor MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor(); //2. Add an optimistic lock interceptor mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mpInterceptor; } }
-
Using the optimistic locking mechanism, you must first obtain the version of the corresponding data before modifying it.
@Test void testUpdate(){ //1. First obtain the version data through the data id to be modified User user = userDao.selectById(1L); //2. Execute the operation of modifying attributes user.setName("Tomy"); userDao.updateById(user); }
-
Execute the query statement before executing the modification:
SELECT id,name,age,tel,deleted,version FROM tbl_user WHERE id=?
-
Use the version field as the basis for optimistic lock checking when performing modifications
UPDATE tbl_user SET name=?, age=?, tel=?, version=? WHERE id=? AND version=?
We pass 1(oldVersion), MyBatisPlus will add 1 to 2, and then update it back to the database (newVersion)
After roughly analyzing the implementation steps of optimistic locking, simulate a locking situation to see if multiple people can modify the same data, only one person can modify it successfully.
@Test void testUpdate() { User userA = userDao.selectById(1L); //version=1 User userB = userDao.selectById(1L); //version=1 userB.setName("Jackson"); userDao.updateById(userB); //After B is modified, version=2 userA.setName("Person"); //The version obtained by A is 1, but the current version is already 2, then when A executes UPDATE ... WHERE version = 1, it will inevitably fail userDao.updateById(userA); }
- The implementation of optimistic locking has been completed
-
Code generator
-
Create a Maven project
-
Import the corresponding jar package
<dependencies> <!--Code generator--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.1</version> </dependency> <!--velocity template engine--> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.3</version> </dependency> </dependencies>
-
Write boot class
@SpringBootApplication public class Mybatisplus04GeneratorApplication { public static void main(String[] args) { SpringApplication.run(Mybatisplus04GeneratorApplication.class, args); } }
-
Create a code generation class
public class CodeGenerator { public static void main(String[] args) { //1. Get the object of the code generator AutoGenerator autoGenerator = new AutoGenerator(); //Set database related configuration DataSourceConfig dataSource = new DataSourceConfig(); dataSource.setDriverName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC"); dataSource.setUsername("root"); dataSource.setPassword("YOURPASSWORD"); autoGenerator.setDataSource(dataSource); //Set global configuration GlobalConfig globalConfig = new GlobalConfig(); globalConfig.setOutputDir(System.getProperty("user.dir")+"/Item name/src/main/java"); //Set code generation location globalConfig.setOpen(false); //Set whether to open the directory where the generated code is located after the generation is complete globalConfig.setAuthor("Kyle"); //set author globalConfig.setFileOverride(true); //Set whether to overwrite the original generated file globalConfig.setMapperName("%sDao"); //Set the data layer interface name, %s is a placeholder, referring to the module name globalConfig.setIdType(IdType.ASSIGN_ID); //Set the Id generation strategy autoGenerator.setGlobalConfig(globalConfig); //Set package name related configuration PackageConfig packageInfo = new PackageConfig(); packageInfo.setParent("com.tomy"); //Set the generated package name, which does not conflict with the location of the code, and the two are superimposed to form a complete path packageInfo.setEntity("domain"); //Set entity class package name packageInfo.setMapper("dao"); //Set the data layer package name autoGenerator.setPackageInfo(packageInfo); //policy settings StrategyConfig strategyConfig = new StrategyConfig(); strategyConfig.setInclude("tb_user"); //Set the name of the table currently participating in the generation, and the parameter is a variable parameter strategyConfig.setTablePrefix("tb_"); //Set the prefix name of the database table, module name = database table name - prefix name For example: User = tb_user - tb_ strategyConfig.setRestControllerStyle(true); //Set whether to enable Rest style strategyConfig.setVersionFieldName("version"); //Set optimistic lock field name strategyConfig.setLogicDeleteFieldName("deleted"); //Set the tombstone field name strategyConfig.setEntityLombokModel(true); //Set whether to enable lombok autoGenerator.setStrategy(strategyConfig); //2. Execute the build operation autoGenerator.execute(); } }
- For the code content in the code generator, we can directly obtain the code from the official document for modification, https://baomidou.com/pages/981406/
-
run the program
After running successfully, a lot of code will be generated in the current project, the code includes controller,service, mapper and entity, etc.
So far, the code generator has completed its work, and can quickly create corresponding classes based on database tables, simplifying code development.
CRUD of Service in MyBatisPlus
- Review the writing of the previous business layer code, write the interface and the corresponding implementation class:
public interface UserService{ } @Service public class UserServiceImpl implements UserService{ }
- After the interface and implementation class are available, methods need to be declared in the interface and implementation class
public interface UserService{ public List<User> findAll(); } @Service public class UserServiceImpl implements UserService{ @Autowired private UserDao userDao; public List<User> findAll(){ return userDao.selectList(null); } }
-
After seeing the above code, MyBatisPlus said that these methods are relatively fixed and general, so I will help you extract them, so MyBatisPlus provides a Service interface and implementation class, respectively: IService and ServiceImpl, the latter is for the former A concrete implementation.
-
The Service written in the future can be modified as follows:
public interface UserService extends IService<User>{ } @Service public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService{ }
-
The advantage after the modification is that MP has helped us realize some basic additions, deletions, changes, and queries of the business layer, which can be used directly.
-
Write a test class for testing:
@SpringBootTest class Mybatisplus04GeneratorApplicationTests { private IUserService userService; @Test void testFindAll() { List<User> list = userService.list(); System.out.println(list); } }