# 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 ![image-20250319133942419](imgs/image-20250319133942419.png) # 创建spirngboot 快速搭建spirngmvc ## 使用 Spirng initiaizr ### 创建项目 ![image-20250319134209132](imgs/image-20250319134209132.png) ### 选择启动器 ![image-20250319134245862](imgs/image-20250319134245862.png) ### 编写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) ``` ### 访问测试 ![image-20250319134509828](imgs/image-20250319134509828.png) ## 手动创建 boot项目 根据官网 :https://docs.spring.io/spring-boot/3.3/tutorial/first-application/index.html - boot-02-helloworld - 添加 parent - 添加 starter-web的依赖 - APP -> main - @SpringBootApplicaiton - Controller ### 创建项目 ![image-20250319143700935](imgs/image-20250319143700935.png) ### 设置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!"; } } ``` ![image-20250319144155914](imgs/image-20250319144155914.png) # 热部署 - 热部署配置 - 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 ``` - 自动编译 ![image-20250320085530955](imgs/image-20250320085530955.png) ![](imgs/image-20250320090223389.png) # 独立运行jar 将spirngboot 打包之后可以直接运行 无需额外的 tomncat 添加一个 spring-boot-maven-plugin插件 ```xml org.springframework.boot spring-boot-maven-plugin ``` ![image-20250320094009192](imgs/image-20250320094009192.png) ![image-20250320093633274](imgs/image-20250320093633274.png) 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"; } } ``` ![image-20250320104236679](imgs/image-20250320104236679.png) ## 使用lombok应用日志 在pom.xml中添加lombok ```xml org.projectlombok lombok ``` ![image-20250320110127304](imgs/image-20250320110127304.png) ```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 ![image-20250320115004139](imgs/image-20250320115004139.png) ``` 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 ``` ![image-20250320115346916](imgs/image-20250320115346916.png) ![image-20250320115418765](imgs/image-20250320115418765.png) 加载所有jar中 META-INF/spring.factories ![image-20250320115455057](imgs/image-20250320115455057.png) ![image-20250320115600727](imgs/image-20250320115600727.png) SpringBoot内置了很多 自动配置类 ``` DataSourceAutoConfiguration ``` ![image-20250320134312626](imgs/image-20250320134312626.png) ![image-20250320134350615](imgs/image-20250320134350615.png) ![image-20250320134452947](imgs/image-20250320134452947.png) 当不需要自动配置生效的时候可以使用 exclude排除 自动配置类 ``` @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) ``` ![image-20250320140113731](imgs/image-20250320140113731.png) boot项目中定义的 mysql ![image-20250320140252675](imgs/image-20250320140252675.png) # 返回值类型 PO DO DTO 等 https://zhuanlan.zhihu.com/p/396192444 - 返回字符串 - 返回pojo对象 - 返回集合对象 - 返回Map对象 ## 日期格式 - 响应 Date--String 使用什么格式 - 接受参数 ### 响应 Date--String 使用什么格式 ![image-20250320143535688](imgs/image-20250320143535688.png) 使用 配置全局的格式化 方式 ```properties spring.jackson.date-format=yyyy-MM-dd HH:mm:ss ``` 个性化的可以使用@JSONFormat ![image-20250320143856801](imgs/image-20250320143856801.png) ![image-20250320143927776](imgs/image-20250320143927776.png) 解决时间序列化 差8个小时的问题 添加jackson 时区 ![image-20250320144058845](imgs/image-20250320144058845.png) ## 接收日期类型 ![image-20250320145838430](imgs/image-20250320145838430.png) ![image-20250320145856804](imgs/image-20250320145856804.png) # 需要自定义 转换器 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 "保存成功"; } } ``` ![image-20250321091234470](imgs/image-20250321091234470.png) # 整合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"; } } ``` ![image-20250321094938628](imgs/image-20250321094938628.png) ## myatis ### 依赖 依赖 - mybatis-spring-starter(自动配置 声明 SqlSessionFactory Mapper) - 数据库驱动 mysql mysql-connecter-j ![image-20250321095802271](imgs/image-20250321095802271.png) ```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 ![image-20250321100001292](imgs/image-20250321100001292.png) ![image-20250321100026899](imgs/image-20250321100026899.png) ![image-20250321100131492](imgs/image-20250321100131492.png) ![image-20250321100159318](imgs/image-20250321100159318.png) 生成之后的效果 ![image-20250321100304396](imgs/image-20250321100304396.png) ### 容器中配置 Mapper代理对象 在App上 添加MyBaits的接口包扫描 ``` @MapperScan("com.neuedu.boot.mybatis.mapper") ``` ![image-20250321102734866](imgs/image-20250321102734866.png) 配置 数据源信息 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 ![image-20250321104114620](imgs/image-20250321104114620.png) # 分页插件 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; } } ``` ![image-20250321115557038](imgs/image-20250321115557038.png) - http://localhost:8080/dept/page - http://localhost:8080/dept/page?pageNum=1&pageSize=5 - http://localhost:8080/dept/page?pageNum=5&pageSize=2 ![image-20250321115541851](imgs/image-20250321115541851.png) # 整合MyBaitsPlus 对MyBatis的封装 https://baomidou.com/getting-started/ - 准备数据库 his - 创建springboot工程 - 添加依赖 - lombok - mysql - mybatis-plus-spring-boot3-starter - starter-web - 配置数据源 - 包扫描 - 编写实体 - @Data lombok - 编写Mapper 继承 BaseMapper - 测试 - 从容器中后去Mapper select方法 ## 创建项目 ![image-20250321144215939](imgs/image-20250321144215939.png) ## 添加依赖 已经有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") > ``` ![image-20250321144958437](imgs/image-20250321144958437.png) ## 编写实体类 ```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); } } ``` ![image-20250321145812866](imgs/image-20250321145812866.png) # MybatisPlus MP ## 自定义 SQL 跟Mybatis操作一样,需要定义接口和 xml文件, Mapper.xml 默认的位置 `classpath*: /mapper/**/*.xml` ![image-20250324134813445](imgs/image-20250324134813445.png) 自定义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 ![ ](imgs/image-20250324154236726.png) ![image-20250324154316601](imgs/image-20250324154316601.png) ### 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 !![image-20250325093128361](imgs/image-20250325093128361.png) ![image-20250325093150911](imgs/image-20250325093150911.png) ## 乐观锁 ```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`; ``` ![image-20250325104156227](imgs/image-20250325104156227.png) ![image-20250325104207226](imgs/image-20250325104207226.png) ![![image-20250325104555398](imgs/image-20250325104555398.png) 使用断点 启动两个更新, 观察76行 和87行查询完的version,添加乐观锁后,第二个更新会失败