# springboot-learn
**Repository Path**: hrbu-2022/springboot-learn
## Basic Information
- **Project Name**: springboot-learn
- **Description**: springboot-learn
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-03-19
- **Last Updated**: 2025-03-25
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# SpringBoot

# 创建spirngboot 快速搭建spirngmvc
## 使用 Spirng initiaizr
### 创建项目

### 选择启动器

### 编写Controller
```java
package com.neuedu.boot.boot01helloworld.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/1913:43
*/
@RestController
public class UserController {
/**
* http://localhost:8080/
* :8080
* @return
*/
@RequestMapping("")
String index(){
return "success";
}
}
```
### 启动
运行Boot01HelloworldApplication中的main方法
```shell
"D:\Program Files\Java\jdk-17\bin\java.exe" com.neuedu.boot.boot01helloworld.Boot01HelloworldApplication
Java HotSpot(TM) 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
---- IntelliJ IDEA coverage runner ----
sampling ...
include patterns:
exclude patterns:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.3.9)
2025-03-19T13:49:10.763+08:00 INFO 16600 --- [boot-01-helloworld] [ main] c.n.b.b.Boot01HelloworldApplication : Starting Boot01HelloworldApplication using Java 17.0.12 with PID 16600 (D:\workspace\boot-learn\boot-01-helloworld\target\classes started by Administrator in D:\workspace\boot-learn)
2025-03-19T13:49:10.766+08:00 INFO 16600 --- [boot-01-helloworld] [ main] c.n.b.b.Boot01HelloworldApplication : No active profile set, falling back to 1 default profile: "default"
[2025.03.19 13:49:11] (Coverage): Error during class instrumentation: org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport: java.lang.RuntimeException: java.io.IOException: Class jakarta/validation/ValidatorFactory not found
2025-03-19T13:49:11.700+08:00 INFO 16600 --- [boot-01-helloworld] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2025-03-19T13:49:11.717+08:00 INFO 16600 --- [boot-01-helloworld] [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2025-03-19T13:49:11.718+08:00 INFO 16600 --- [boot-01-helloworld] [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.36]
2025-03-19T13:49:11.772+08:00 INFO 16600 --- [boot-01-helloworld] [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2025-03-19T13:49:11.772+08:00 INFO 16600 --- [boot-01-helloworld] [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 962 ms
2025-03-19T13:49:12.134+08:00 INFO 16600 --- [boot-01-helloworld] [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2025-03-19T13:49:12.142+08:00 INFO 16600 --- [boot-01-helloworld] [ main] c.n.b.b.Boot01HelloworldApplication : Started Boot01HelloworldApplication in 1.834 seconds (process running for 2.442)
```
### 访问测试

## 手动创建 boot项目
根据官网 :https://docs.spring.io/spring-boot/3.3/tutorial/first-application/index.html
- boot-02-helloworld
- 添加 parent
- 添加 starter-web的依赖
- APP -> main
- @SpringBootApplicaiton
- Controller
### 创建项目

### 设置pom
```xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
3.3.9
org.example
boot-02-helloworld
1.0-SNAPSHOT
17
17
org.springframework.boot
spring-boot-starter-web
```
### 启动类 BootApp
```java
package com.neuedu.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/1914:39
*/
@SpringBootApplication
public class BootApp {
public static void main(String[] args) {
SpringApplication.run(BootApp.class, args);
}
}
```
### 编写controller
```java
package com.neuedu.boot.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/1914:40
*/
@RestController
public class IndexController {
/**
* http://localhost:8080/
* @return
*/
@RequestMapping("/")
String home() {
return "Hello World!";
}
}
```

# 热部署
- 热部署配置
- devtools 依赖
- maven-boot的插件、
```xml
boot-learn
com.neuedu.boot
1.0-SNAPSHOT
4.0.0
boot-03-helloworld
17
17
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-devtools
org.springframework.boot
spring-boot-maven-plugin
```
- 自动编译


# 独立运行jar
将spirngboot 打包之后可以直接运行 无需额外的 tomncat
添加一个 spring-boot-maven-plugin插件
```xml
org.springframework.boot
spring-boot-maven-plugin
```


D:\workspace\boot-learn\boot-03-helloworld\target\classes\com\neuedu\boot\controller\TestController。class
D:\workspace\boot-learn\boot-03-helloworld\target\xxxxx.jar
# SpringBoot 核心配置文件
约定大于配置(一系列参数有默认)
- application.properties
- application.yaml(application.yml)
## 属性配置
```properties
server.port=9090
server.servlet.context-path=/his
```
## Yaml
```yaml
#server.port=9090
#server.servlet.context-path=/his
#key: value
server:
port: 7070
servlet:
context-path: /server
```
properties优先级更高
可以通过 查看 官网API文档
https://docs.spring.io/spring-boot/3.3/appendix/application-properties/index.html
可以配置日志级别 SpringBoot 默认使用的 LogBack 库
```yaml
#日志
logging:
level:
org: DEBUG
```
## 在Controller中设置日志
```yaml
#日志
logging:
level:
org: INFO
com.neuedu.boot.controller.LogController: INFO
```
```java
package com.neuedu.boot.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2010:35
*/
@RestController
public class LogController {
Logger logger = LoggerFactory.getLogger(LogController.class);
@RequestMapping("/log")
String log(){
logger.trace("冗余信息-debug");
logger.debug("调试信息-debug");
logger.info("用意义的信息-info");
logger.warn("警告信息-warn");
logger.error("错误信息-error");
return "log-success";
}
}
```

## 使用lombok应用日志
在pom.xml中添加lombok
```xml
org.projectlombok
lombok
```

```java
package com.neuedu.boot.controller;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2010:35
*/
@RestController
@Slf4j
public class LogController {
/**
* http://localhost:8080/log
* @return
*/
@RequestMapping("/log")
String log(){
log.trace("冗余信息-debug");
log.debug("调试信息-debug");
log.info("用意义的信息-info");
log.warn("警告信息-warn");
log.error("错误信息-error");
return "log-success";
}
}
```
# @Value注解
使用注解直接读取 application核心配置文件的属性值
```java
package com.neuedu.boot.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2011:23
*/
@RestController
public class ReadValueController {
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.driver-class-name}")
private String driverClass;
/**
* http://localhost:8080/readValue
* @return
*/
@RequestMapping("/readValue")
Map readValue(){
Map info = new HashMap();
info.put("username",username);
info.put("password",password);
info.put("url",url);
info.put("driverClass",driverClass);
return info;
}
}
```
如果获取不到,可以使用默认值
@Value("${key:default}")
```
@Value("${server.port:9090}")
```
# Starters
启动器是一组方便的依赖描述符,可以包含在应用程序中。您可以一站式地获得所需的所有Spring和相关技术,而不必遍历示例代码并复制粘贴依赖描述符。例如,如果您想开始使用Spring和JPA进行数据库访问,请在您的项目中包含Spring -boot-starter-data- JPA依赖项。
启动器包含大量依赖项,您需要这些依赖项来快速启动和运行项目,并使用一致的、受支持的托管传递依赖项集。
| `spring-boot-starter` | Core starter, including auto-configuration support, logging and YAML |
| ------------------------------------------------- | ------------------------------------------------------------ |
| `spring-boot-starter-activemq` | Starter for JMS messaging using Apache ActiveMQ |
| `spring-boot-starter-amqp` | Starter for using Spring AMQP and Rabbit MQ |
| `spring-boot-starter-aop` | Starter for aspect-oriented programming with Spring AOP and AspectJ |
| `spring-boot-starter-artemis` | Starter for JMS messaging using Apache Artemis |
| `spring-boot-starter-batch` | Starter for using Spring Batch |
| `spring-boot-starter-cache` | Starter for using Spring Framework’s caching support |
| `spring-boot-starter-data-cassandra` | Starter for using Cassandra distributed database and Spring Data Cassandra |
| `spring-boot-starter-data-cassandra-reactive` | Starter for using Cassandra distributed database and Spring Data Cassandra Reactive |
| `spring-boot-starter-data-couchbase` | Starter for using Couchbase document-oriented database and Spring Data Couchbase |
| `spring-boot-starter-data-couchbase-reactive` | Starter for using Couchbase document-oriented database and Spring Data Couchbase Reactive |
| `spring-boot-starter-data-elasticsearch` | Starter for using Elasticsearch search and analytics engine and Spring Data Elasticsearch |
| `spring-boot-starter-data-jdbc` | Starter for using Spring Data JDBC |
| `spring-boot-starter-data-jpa` | Starter for using Spring Data JPA with Hibernate |
| `spring-boot-starter-data-ldap` | Starter for using Spring Data LDAP |
| `spring-boot-starter-data-mongodb` | Starter for using MongoDB document-oriented database and Spring Data MongoDB |
| `spring-boot-starter-data-mongodb-reactive` | Starter for using MongoDB document-oriented database and Spring Data MongoDB Reactive |
| `spring-boot-starter-data-neo4j` | Starter for using Neo4j graph database and Spring Data Neo4j |
| `spring-boot-starter-data-r2dbc` | Starter for using Spring Data R2DBC |
| `spring-boot-starter-data-redis` | Starter for using Redis key-value data store with Spring Data Redis and the Lettuce client |
| `spring-boot-starter-data-redis-reactive` | Starter for using Redis key-value data store with Spring Data Redis reactive and the Lettuce client |
| `spring-boot-starter-data-rest` | Starter for exposing Spring Data repositories over REST using Spring Data REST and Spring MVC |
| `spring-boot-starter-freemarker` | Starter for building MVC web applications using FreeMarker views |
| `spring-boot-starter-graphql` | Starter for building GraphQL applications with Spring GraphQL |
| `spring-boot-starter-groovy-templates` | Starter for building MVC web applications using Groovy Templates views |
| `spring-boot-starter-hateoas` | Starter for building hypermedia-based RESTful web application with Spring MVC and Spring HATEOAS |
| `spring-boot-starter-integration` | Starter for using Spring Integration |
| `spring-boot-starter-jdbc` | Starter for using JDBC with the HikariCP connection pool |
| `spring-boot-starter-jersey` | Starter for building RESTful web applications using JAX-RS and Jersey. An alternative to [`spring-boot-starter-web`](https://docs.spring.io/spring-boot/3.3/reference/using/build-systems.html#spring-boot-starter-web) |
| `spring-boot-starter-jooq` | Starter for using jOOQ to access SQL databases with JDBC. An alternative to [`spring-boot-starter-data-jpa`](https://docs.spring.io/spring-boot/3.3/reference/using/build-systems.html#spring-boot-starter-data-jpa) or [`spring-boot-starter-jdbc`](https://docs.spring.io/spring-boot/3.3/reference/using/build-systems.html#spring-boot-starter-jdbc) |
| `spring-boot-starter-json` | Starter for reading and writing json |
| `spring-boot-starter-mail` | Starter for using Java Mail and Spring Framework’s email sending support |
| `spring-boot-starter-mustache` | Starter for building web applications using Mustache views |
| `spring-boot-starter-oauth2-authorization-server` | Starter for using Spring Authorization Server features |
| `spring-boot-starter-oauth2-client` | Starter for using Spring Security’s OAuth2/OpenID Connect client features |
| `spring-boot-starter-oauth2-resource-server` | Starter for using Spring Security’s OAuth2 resource server features |
| `spring-boot-starter-pulsar` | Starter for using Spring for Apache Pulsar |
| `spring-boot-starter-pulsar-reactive` | Starter for using Spring for Apache Pulsar Reactive |
| `spring-boot-starter-quartz` | Starter for using the Quartz scheduler |
| `spring-boot-starter-rsocket` | Starter for building RSocket clients and servers |
| `spring-boot-starter-security` | Starter for using Spring Security |
| `spring-boot-starter-test` | Starter for testing Spring Boot applications with libraries including JUnit Jupiter, Hamcrest and Mockito |
| `spring-boot-starter-thymeleaf` | Starter for building MVC web applications using Thymeleaf views |
| `spring-boot-starter-validation` | Starter for using Java Bean Validation with Hibernate Validator |
| `spring-boot-starter-web` | Starter for building web, including RESTful, applications using Spring MVC. Uses Tomcat as the default embedded container |
| `spring-boot-starter-web-services` | Starter for using Spring Web Services |
| `spring-boot-starter-webflux` | Starter for building WebFlux applications using Spring Framework’s Reactive Web support |
| `spring-boot-starter-websocket` | Starter for building WebSocket applications using Spring Framework’s MVC WebSocket support |
# 自动配置
当我们添加
```xml
org.springframework.boot
spring-boot-starter-jdbc
```
自动的在 Bean容器中注册Datasource

``` 889
SpringApplication 889
```
```java
public static ConfigurableApplicationContext run(Class>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
```
```java
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
```
```
SpringFactoriesLoader
```


加载所有jar中 META-INF/spring.factories


SpringBoot内置了很多 自动配置类
```
DataSourceAutoConfiguration
```



当不需要自动配置生效的时候可以使用 exclude排除 自动配置类
```
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
```

boot项目中定义的 mysql

# 返回值类型
PO DO DTO 等
https://zhuanlan.zhihu.com/p/396192444
- 返回字符串
- 返回pojo对象
- 返回集合对象
- 返回Map对象
## 日期格式
- 响应 Date--String 使用什么格式
- 接受参数
### 响应 Date--String 使用什么格式

使用 配置全局的格式化 方式
```properties
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
```
个性化的可以使用@JSONFormat


解决时间序列化 差8个小时的问题
添加jackson 时区

## 接收日期类型


# 需要自定义 转换器 String--Date
定义工具,将字符串转换成 Date
```java
package com.neuedu.boot.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/219:00
*/
public class StringUtils {
private static Map patternMap = new HashMap<>();
static {
patternMap.put( Pattern.compile("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}$"),
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
patternMap.put( Pattern.compile("^\\d{4}-\\d{2}-\\d{2}$"),
new SimpleDateFormat("yyyy-MM-dd"));
patternMap.put( Pattern.compile("^\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}:\\d{2}$"),
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"));
patternMap.put( Pattern.compile("^\\d{4}/\\d{2}/\\d{2}$"),
new SimpleDateFormat("yyyy/MM/dd"));
patternMap.put( Pattern.compile("^\\d{2}:\\d{2}:\\d{2} \\d{4}-\\d{2}-\\d{2}$"),
new SimpleDateFormat("HH:mm:ss yyyy-MM-dd"));
}
public static Date string2Date(String source){
//需求,验证字符串,是否满足 四个数字-两个数字-两个数字
Date date = null;
Set patterns = patternMap.keySet();
Iterator it = patterns.iterator();
while (it.hasNext()){
Pattern pattern = it.next();
if(pattern.matcher(source).matches()){
SimpleDateFormat sdf = patternMap.get(pattern);
try {
date = sdf.parse(source);
break;
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
return date;
}
}
```
在Convert 中使用
```java
package com.neuedu.boot.config;
import com.neuedu.boot.utils.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2014:59
*/
@Configuration
public class MVCConfig {
@Bean
public Converter string2DateConverter(){
return new Converter(){
@Override
public Date convert(String source) {
//调用工具 将 字符串转换成 日期
return StringUtils.string2Date(source);
}
};
}
}
```
编写controller 接受日期参数
```java
package com.neuedu.boot.controller;
import com.neuedu.boot.po.User;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2014:25
*/
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping("/save")
public String save(User user){
// 使用打印 模拟存储数据库
System.out.println(user);
return "保存成功";
}
}
```

# 整合Mybatis
- boot starter-web
> myatis
依赖
- mybatis-spring
- starter-jdbc
- mybatis-spring-starter(自动配置 声明 SqlSessionFactory Mapper)
- 数据库驱动 mysql mysql-connecter-j
使用mybatisx 生成 Mapper(java、xml)、PO
配置数据库,在application.yml
- url
- driver
- username
- password
- mapperLocations
配置Mapper扫描,在容器中注册 Mapper接口的代理对象
```
@MapperScan("com.neuedu.ssm.mapper")
```
测试
可以在Controller中调用service--Mapper
## 搭建boot mvc
```xml
boot-learn
com.neuedu.boot
1.0-SNAPSHOT
4.0.0
boot-06-mybaits
17
17
org.springframework.boot
spring-boot-starter-web
```
启动类
com.neuedu.boot.mybatis.BootMybaitsApp
```JAVA
package com.neuedu.boot.mybatis;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/219:46
*/
@SpringBootApplication
public class BootMybaitsApp {
public static void main(String[] args) {
SpringApplication.run(BootMybaitsApp.class ,args);
}
}
```
```java
package com.neuedu.boot.mybatis.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/219:47
*/
@RestController
public class IndexController {
@RequestMapping("/")
String index(){
return "hello";
}
}
```

## myatis
### 依赖
依赖
- mybatis-spring-starter(自动配置 声明 SqlSessionFactory Mapper)
- 数据库驱动 mysql mysql-connecter-j

```xml
boot-learn
com.neuedu.boot
1.0-SNAPSHOT
4.0.0
boot-06-mybaits
17
17
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
3.0.4
com.mysql
mysql-connector-j
```
自动配置类,声明 SqlSessionFactory
### 生成代码
基础包: com.neuedu.boot.mybatis
实体类的包 po
mapper.xml




生成之后的效果

### 容器中配置 Mapper代理对象
在App上 添加MyBaits的接口包扫描
```
@MapperScan("com.neuedu.boot.mybatis.mapper")
```

配置 数据源信息
url\username\password。。。。。
> application.yml
```yaml
logging:
level:
com.neuedu.boot.mybatis.mapper: DEBUG
# 数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/his?characterEncoding=utf-8
username: root
password: root
# Mybatis配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.neuedu.boot.mybatis.po
```
编写Controller 测试 Mapper是否可以用
```
package com.neuedu.boot.mybatis.controller;
import com.neuedu.boot.mybatis.mapper.DeptMapper;
import com.neuedu.boot.mybatis.po.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/219:47
*/
@RestController
@RequestMapping("/dept")
public class DeptController {
@Autowired
private DeptMapper deptMapper;
/**
* http://localhost:8080/dept/getById
* @return
*/
@RequestMapping("/getById")
Dept getById() {
long id = 1;
return deptMapper.selectByPrimaryKey(id);
}
}
```
### 测试
http://localhost:8080/dept/getById

# 分页插件
boot
```xml
com.github.pagehelper
pagehelper-spring-boot-starter
1.4.7
```
```java
package com.neuedu.boot.mybatis.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.neuedu.boot.mybatis.mapper.DeptMapper;
import com.neuedu.boot.mybatis.po.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/219:47
*/
@RestController
@RequestMapping("/dept")
public class DeptController {
@Autowired
private DeptMapper deptMapper;
/**
* http://localhost:8080/dept/getById
* @return
*/
@RequestMapping("/getById")
Dept getById() {
long id = 1;
return deptMapper.selectByPrimaryKey(id);
}
@RequestMapping("/list")
List list() {
List depts = deptMapper.selectList();
return depts;
}
/**
* http://localhost:8080/dept/page?pageNum=1&pageSize=5
* @param pageNum
* @param pageSize
* @return
*/
@RequestMapping("/page")
List page(@RequestParam(defaultValue = "1") int pageNum ,@RequestParam(defaultValue = "5") int pageSize) {
//开启分页
//PageHelper.startPage(1页 , 5 条)
//PageHelper.startPage(2页 , 5 条)
Page page = PageHelper.startPage(pageNum, pageSize);
deptMapper.selectList();
System.out.println(page.toString());
System.out.println("page.getPages() = " + page.getPages());
System.out.println("page.getTotal() = " + page.getTotal());
System.out.println("page.getPageSize() = " + page.getPageSize());
System.out.println("page.getPageNum() = " + page.getPageNum());
System.out.println("page.getPages() = " + page.getPages());
List deptList = page.getResult();
return deptList;
}
}
```

- http://localhost:8080/dept/page
- http://localhost:8080/dept/page?pageNum=1&pageSize=5
- http://localhost:8080/dept/page?pageNum=5&pageSize=2

# 整合MyBaitsPlus
对MyBatis的封装
https://baomidou.com/getting-started/
- 准备数据库 his
- 创建springboot工程
- 添加依赖
- lombok
- mysql
- mybatis-plus-spring-boot3-starter
- starter-web
- 配置数据源
- 包扫描
- 编写实体
- @Data lombok
- 编写Mapper 继承 BaseMapper
- 测试
- 从容器中后去Mapper select方法
## 创建项目

## 添加依赖
已经有parent
```xml
boot-learn
com.neuedu.boot
1.0-SNAPSHOT
4.0.0
boot-07-mp
17
17
3.5.10.1
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
org.projectlombok
lombok
com.baomidou
mybatis-plus-spring-boot3-starter
${mp.version}
com.mysql
mysql-connector-j
```
## 创建Springboot的 启动类
```java
package com.neuedu.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2114:48
*/
@SpringBootApplication
public class MPApp {
public static void main(String[] args) {
SpringApplication.run(MPApp.class,args);
}
}
```
## 配置数据源
application.yaml
```yaml
logging:
level:
com.neuedu.boot.mapper: DEBUG
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/his?characterEncoding=utf-8
username: root
password: root
```
## 设置Mapper扫描注册代理对象
> ```
> @MapperScan("com.neuedu.boot.mapper")
> ```

## 编写实体类
```java
package com.neuedu.boot.po;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 部门
* @TableName dept
*/
@Data //自动生成 setter getter tostring
@TableName("dept") // dept 是数据库中 表的名字
public class Dept implements Serializable {
/**
* 部门ID
*/
private Long deptId;
/** * 部门名称 */
private String deptName;
/** * 办公地址 */
private String loc;
/** * 科室主任 */
private String leader;
/** * 是否有效 */
private String del;
/** * 创建时间 */
private Date createtime;
}
```
## 编写Mapper
`DeptMapper 继承 BaseMapper`
```java
package com.neuedu.boot.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.neuedu.boot.po.Dept;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2114:53
*/
public interface DeptMapper extends BaseMapper {
}
```
## 使用spirngboot的单元测试框架测试 Mapper
添加 startertest依赖
```xml
org.springframework.boot
spring-boot-starter-test
```
编写测试类
```java
package com.neuedu.boot.mapper;
import com.neuedu.boot.MPApp;
import com.neuedu.boot.po.Dept;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2114:55
*/
@SpringBootTest(classes = MPApp.class)
// @SpringBootTest
class DeptMapperTest {
@Autowired
private DeptMapper deptMapper;
@Test
public void test(){
List depts = deptMapper.selectList(null);
depts.forEach(System.out::println);
}
}
```

# MybatisPlus MP
## 自定义 SQL
跟Mybatis操作一样,需要定义接口和 xml文件, Mapper.xml 默认的位置 `classpath*: /mapper/**/*.xml`

自定义xml
```xml
```
```JAVA
package com.neuedu.boot.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.neuedu.boot.po.Dept;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2114:53
*/
public interface DeptMapper extends BaseMapper {
/**
* 查询总条数
* @return
*/
int myCount();
}
```
单元测试
```java
@Test
public void test2(){
int count = deptMapper.myCount();
System.out.println(count);
}
```
## 持久层接口
[IService](https://gitee.com/baomidou/mybatis-plus/blob/3.0/mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/service/IService.java) 是 MyBatis-Plus 提供的一个通用 Service 层接口,它封装了常见的 CRUD 操作,包括插入、删除、查询和分页等。通过继承 IService 接口,可以快速实现对数据库的基本操作,同时保持代码的简洁性和可维护性。
IService 接口中的方法命名遵循了一定的规范,如 get 用于查询单行,remove 用于删除,list 用于查询集合,page 用于分页查询,这样可以避免与 Mapper 层的方法混淆。
BaseMapper 是 Mybatis-Plus 提供的一个通用 Mapper 接口,它封装了一系列常用的数据库操作方法,包括增、删、改、查等。通过继承 BaseMapper,开发者可以快速地对数据库进行操作,而无需编写繁琐的 SQL 语句。
- 泛型 `T` 为任意实体对象
- 参数 `Serializable` 为任意类型主键 `Mybatis-Plus` 不推荐使用复合主键约定每一张表都有自己的唯一 `id` 主键
- 对象 `Wrapper` 为 [条件构造器](https://baomidou.com/guides/wrapper)
如何使用Service
- 编写接口 ` extends IService`
- 实现类 `extends ServiceImpl`
```java
public interface IDeptService extends IService {
}
```
```java
package com.neuedu.boot.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.neuedu.boot.mapper.DeptMapper;
import com.neuedu.boot.po.Dept;
import com.neuedu.boot.service.IDeptService;
import org.springframework.stereotype.Service;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2414:12
*/
@Service
public class DeptServiceImpl extends ServiceImpl implements IDeptService {
}
```
### 测试
```java
package com.neuedu.boot.service.impl;
import com.neuedu.boot.po.Dept;
import com.neuedu.boot.service.IDeptService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2414:20
*/
@SpringBootTest
class DeptServiceImplTest {
@Autowired
private IDeptService deptService;
//查询列表
@Test
public void queryList(){
List list = deptService.list();
list.forEach(System.out::println);
}
/**
* 查询一个 实体类的 主键属性上应该添加一个 @TableId
*/
@Test
public void getById(){
Long id = 1L;
Dept dept = deptService.getById(id);
System.out.println(dept);
}
}
```
```java
package com.neuedu.boot.po;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 部门
* @TableName dept
*/
@Data //自动生成 setter getter tostring
@TableName("dept") // dept 是数据库中 表的名字
public class Dept implements Serializable {
/**
* 部门ID
*/
@TableId
private Long deptId;
/** * 部门名称 */
private String deptName;
/** * 办公地址 */
private String loc;
/** * 科室主任 */
private String leader;
/** * 是否有效 */
private String del;
/** * 创建时间 */
private Date createtime;
}
```
主键生成策略
```java
/**
* 部门ID
* 通过type 类型 设置主键生成的策略
*/
@TableId(type = IdType.AUTO)
private Long deptId;
```
## 条件构造器
> Wrapper


### QueryWrapper
```java
@Test
public void queryWrapper() {
//用于构造条件的,
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("loc","201"); // WHERE (loc = 201)
queryWrapper.like("leader","111"); // leader like '%111%'
// queryWrapper.likeLeft("leader","111"); // leader like '%111'
// queryWrapper.likeRight("leader","111"); // leader like '111%'
// queryWrapper.gt() great than >
// queryWrapper.lt() less than <
// queryWrapper.le() less equals <=
// queryWrapper.ge() great equals >=
List list = deptService.list(queryWrapper);
list.forEach(System.out::println);
}
@Test
public void lambdaQueryWrapper() {
//用于构造条件的,
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq( Dept::getLoc,"201"); // WHERE (loc = 201)
queryWrapper.like( Dept::getLeader,"111"); // leader like '%111%'
List list = deptService.list(queryWrapper);
list.forEach(System.out::println);
}
```
### UpdateWrapper
```java
@Test
public void updateWrapper() {
// UpdateWrapper updateWrapper = new UpdateWrapper<>();
// updateWrapper.eq("loc","201");
LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(Dept::getLoc,"201");
Dept dept = new Dept();
dept.setLeader("统一修改2");
boolean b = deptService.update(dept,updateWrapper);
System.out.println("b = " + b);
}
```
## 分页插件
需要添加依赖 3.5.9+的 mybatisplus
```xml
com.baomidou
mybatis-plus-jsqlparser
${mp.version}
```
添加配置类
```java
package com.neuedu.boot.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2416:08
*/
@Configuration
public class MyBatisConfig {
/**
* MP的插件系统
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
//注册 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
```
测试分页
```java
@Test
public void page() {
int current = 3,size =5;
IPage page = Page.of(current,size);
deptService.page(page);
List records = page.getRecords();
System.out.println("page.getCurrent() = " + page.getCurrent());
System.out.println("page.getTotal() = " + page.getTotal());
System.out.println("page.getPages() = " + page.getPages());
System.out.println("page.getSize() = " + page.getSize());
records.forEach(System.out::println);
}
```
## 自动填充
MyBatis-Plus 提供了一个便捷的自动填充功能,用于在插入或更新数据时自动填充某些字段,如创建时间、更新时间等。以下是如何使用这一功能的详细说明。
准备了一个表
```sql
CREATE TABLE `his`.`student`(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100),
`create_by` VARCHAR(100),
`create_time` DATETIME,
`update_by` VARCHAR(100),
`update_time` DATETIME,
PRIMARY KEY (`id`)
);
```
编写 CRUD的 Mapper、Service
```java
package com.neuedu.boot.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 部门
* @TableName dept
*/
@Data
@TableName("student")
public class Student implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private String createBy;
private Date createTime;
private String updateBy;
private Date updateTime;
}
```
```java
package com.neuedu.boot.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.neuedu.boot.po.Dept;
import com.neuedu.boot.po.Student;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2114:53
*/
public interface StudentMapper extends BaseMapper {
}
```
```java
package com.neuedu.boot.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.neuedu.boot.mapper.DeptMapper;
import com.neuedu.boot.mapper.StudentMapper;
import com.neuedu.boot.po.Dept;
import com.neuedu.boot.po.Student;
import com.neuedu.boot.service.IDeptService;
import com.neuedu.boot.service.IStudentService;
import org.springframework.stereotype.Service;
/**
* @author 金山
* 项目:boot-learn
* site: https://blog.fulfill.com.cn
* 描述
* @data 2025/3/2414:12
*/
@Service
public class StudentServiceImpl extends ServiceImpl implements IStudentService {
}
```
实现自动填充
- 实体类中添加
- 实现全局的自动填充功能
```java
package com.neuedu.boot.po;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 部门
* @TableName dept
*/
@Data
@TableName("student")
public class Student implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
@TableField(value = "name")
private String name;
@TableField(fill = FieldFill.INSERT)
private String createBy;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private String updateBy;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
}
```
实现自动填充
```java
package com.neuedu.boot.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
// java example
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("开始插入填充...");
this.strictInsertFill(metaObject, "createBy", String.class, "admin");
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("开始更新填充...");
this.strictUpdateFill(metaObject, "updateBy", String.class, "root");
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}
}
```
## 逻辑删除
基于strudent表演示添加了一个表的字段 `delete_flag` 表示是否删除的, 0 未删除, 1 已删除
```sql
ALTER TABLE `his`.`student`
ADD COLUMN `delete_flag` INT DEFAULT 0 NULL COMMENT '是否删除,0 未删除,1 已删除' AFTER `update_time`;
```
正常的查询:
select * from student where delete_flag = 0
在实体类中 表字段对应的 属性
```java
//1 代表删除, 0 代表未删除
@TableField(value = "delete_flag")
@TableLogic(value="0" ,delval = "1")
private String deleteFlag;
```
测试删除方法时,通过sql观察到 并没有执行 delete 的sql,而是执行了update delete_flag变成 1
!

## 乐观锁
```sql
ALTER TABLE `his`.`student`
ADD COLUMN `age` INT NULL COMMENT '年龄' AFTER `name`;
```
在数据库中添加一个版本号
```sql
ALTER TABLE `his`.`student`
ADD COLUMN `version` INT DEFAULT 1 NULL COMMENT '乐观锁' AFTER `delete_flag`;
```



使用断点 启动两个更新, 观察76行 和87行查询完的version,添加乐观锁后,第二个更新会失败