# springboot-learn **Repository Path**: hrbu2023/springboot-learn ## Basic Information - **Project Name**: springboot-learn - **Description**: springboot-学习 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-24 - **Last Updated**: 2026-03-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # SpringBoot介绍 金山老师的笔记: https://blog.fulfill.com.cn/course/01-java/springboot/springboot-9.html Spring Boot 让你轻松创建独立的基于生产级别的 Spring 应用程序,这些应用程序你可以“只需运行”。我们对Spring平台和第三方库持独特观点,让你能轻松上手。大多数 Spring Boot 应用只需极少的 Spring 配置。如果你想了解某个特定版本的信息,或者如何从早期版本升级,可以查看我们维基上的[项目发布说明部分](https://github.com/spring-projects/spring-boot/wiki#release-notes)。 ## 特色 - 创建独立的 Spring 应用程序 - 直接嵌入Tomcat、Jetty或Undertow(无需部署WAR文件) - 提供有主见的“起始”依赖,简化你的构建配置 - 尽可能自动配置 Spring 和第三方库 - 提供生产准备的功能,如指标、健康检查和外部配置 - 完全不需要代码生成,也不需要XML配置 ## [文档](https://docs.spring.io/spring-boot/3.5/index.html) https://docs.spring.io/spring-boot/3.5/index.html # 开发工具 [Spring | Tools](https://spring.io/tools) ![image-20260325084639919](assets/image-20260325084639919.png) ![image-20260325084650541](assets/image-20260325084650541.png) ![image-20260325084710892](assets/image-20260325084710892.png) # 入门项目 ## 快速搭建springmvc ### 父项目 ![image-20260324133854024](assets/image-20260324133854024.png) ### 创建组合项目的子项目 ![image-20260324134918649](assets/image-20260324134918649.png) ### 添加依赖 [spring-boot-starter-web](https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web) 使用 Spring MVC 构建网页应用(包括 RESTful)的 Starter。使用 Tomcat 作为默认嵌入式容器(已被 spring-boot-starter-webmvc 取代) 在项目中引入 spring-boot-dependencies,让项目继承自`spring-boot-starter-parent` ```xml 4.0.0 org.springframework.boot spring-boot-starter-parent 3.5.12 com.neuedu.boot boot-01-helloworld jar boot-01-helloworld http://maven.apache.org UTF-8 org.springframework.boot spring-boot-starter-web ``` ### main方法 ```java package com.neuedu.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * Hello world! * */ @SpringBootApplication public class App { public static void main( String[] args ) { SpringApplication.run(App.class ,args ); } } ``` 测试Controller ```java package com.neuedu.boot.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class IndexController { @RequestMapping("/index") String index(){ return "success"; } } ``` ![image-20260324135538638](assets/image-20260324135538638.png) # 使用[Spring Initializr](https://start.spring.io/)创建项目 ![image-20260324140842789](assets/image-20260324140842789-1774332523091-1.png) ![image-20260324140936477](assets/image-20260324140936477.png) # 使用IDEA的插件 ![image-20260324141144904](assets/image-20260324141144904.png) ![image-20260324141237224](assets/image-20260324141237224.png) # 启动器 起始词是一组方便的依赖描述符,你可以在申请中包含。 你可以一站式获取所有 Spring 及相关技术,无需翻找样本代码和复制粘贴大量依赖描述符。 例如,如果你想开始使用 Spring 和 JPA 进行数据库访问,可以在项目中包含依赖关系。`spring-boot-starter-data-jpa` 起始程序包含了许多你需要快速启动项目并拥有一致且受控的可管理传递依赖所需的依赖。 | Name | Description | |:--------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `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.5/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.5/reference/using/build-systems.html#spring-boot-starter-data-jpa) or [`spring-boot-starter-jdbc`](https://docs.spring.io/spring-boot/3.5/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 | | 名称 | 描述 | |:--------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `spring-boot-starter` | 核心启动功能,包括自动配置支持、日志记录和 YAML | | `spring-boot-starter-activemq` | 使用 Apache ActiveMQ 进行 JMS 消息传递的入门 | | `spring-boot-starter-amqp` | 使用 Spring AMQP 和 Rabbit MQ 的入门程序 | | `spring-boot-starter-aop` | Spring AOP和AspectJ面向切面编程的入门程序 | | `spring-boot-starter-artemis` | 使用 Apache Artemis 的 JMS 消息发送入门 | | `spring-boot-starter-batch` | 使用春季批次的起始剂 | | `spring-boot-starter-cache` | 使用 Spring Framework 缓存支持的 Starter | | `spring-boot-starter-data-cassandra` | 用于使用 Cassandra 分布式数据库和 Spring Data Cassandra 的入门程序 | | `spring-boot-starter-data-cassandra-reactive` | 用于使用 Cassandra 分布式数据库和 Spring Data Cassandra Reactive 的入门工具 | | `spring-boot-starter-data-couchbase` | 用于使用 Couchbase 文档导向数据库和 Spring Data Couchbase 的 Starter | | `spring-boot-starter-data-couchbase-reactive` | 用于使用 Couchbase 文档导向数据库和 Spring Data Couchbase Reactive 的 Starter | | `spring-boot-starter-data-elasticsearch` | 用于使用 Elasticsearch 搜索和分析引擎以及 Spring Data Elasticsearch 的入门工具 | | `spring-boot-starter-data-jdbc` | 使用 Spring Data JDBC 的入门 | | `spring-boot-starter-data-jpa` | 使用 Spring Data JPA 搭配 Hibernate 的起始程序 | | `spring-boot-starter-data-ldap` | 使用 Spring Data LDAP 的起始码 | | `spring-boot-starter-data-mongodb` | 用于使用 MongoDB 文档导向数据库和 Spring Data MongoDB 的入门工具 | | `spring-boot-starter-data-mongodb-reactive` | 用于使用 MongoDB 文档导向数据库和 Spring Data MongoDB Reactive 的入门 | | `spring-boot-starter-data-neo4j` | 使用 Neo4j 图数据库和 Spring Data Neo4j 的起始程序 | | `spring-boot-starter-data-r2dbc` | 使用 Spring Data R2DBC 的起始程序 | | `spring-boot-starter-data-redis` | Starter 用于使用 Redis 键值数据存储,配合 Spring Data Redis 和 Lettuce 客户端 | | `spring-boot-starter-data-redis-reactive` | 使用 Redis 键值数据存储,配合 Spring Data Redis 反应式和 Lettuce 客户端 | | `spring-boot-starter-data-rest` | 使用 Spring Data REST 和 Spring MVC 在 REST 上暴露 Spring Data 仓库的起始程序 | | `spring-boot-starter-freemarker` | 用于使用 FreeMarker 视图构建 MVC 网络应用的 Starter | | `spring-boot-starter-graphql` | 用 Spring GraphQL 构建 GraphQL 应用的入门工具 | | `spring-boot-starter-groovy-templates` | 使用 Groovy 模板视图构建 MVC 网页应用的入门 | | `spring-boot-starter-hateoas` | 用于构建基于超媒体的RESTful网页应用的Spring MVC和Spring HATEOAS的入门程序 | | `spring-boot-starter-integration` | 使用 Spring 集成的起始程序 | | `spring-boot-starter-jdbc` | 使用 JDBC 搭配 HikariCP 连接池的入门 | | `spring-boot-starter-jersey` | 用于使用 JAX-RS 和 Jersey 构建 RESTful 网页应用的 Starter。[`spring-boot-starter-web`](https://docs.spring.io/spring-boot/3.5/reference/using/build-systems.html#spring-boot-starter-web) 的替代方案 | | `spring-boot-starter-jooq` | 用jOOQ访问JDBC的SQL数据库的入门工具。[`spring-boot-starter-data-jpa`](https://docs.spring.io/spring-boot/3.5/reference/using/build-systems.html#spring-boot-starter-data-jpa) 或 [`spring-boot-starter-jdbc`](https://docs.spring.io/spring-boot/3.5/reference/using/build-systems.html#spring-boot-starter-jdbc) 的替代方案 | | `spring-boot-starter-json` | 用于读写json的起始程序 | | `spring-boot-starter-mail` | 用于使用 Java Mail 和 Spring Framework 邮件发送支持的 Starter | | `spring-boot-starter-mustache` | 使用 Mustache 视图构建网页应用的 Starter | | `spring-boot-starter-oauth2-authorization-server` | 使用 Spring 授权服务器功能的起始工具 | | `spring-boot-starter-oauth2-client` | 用于使用 Spring Security OAuth2/OpenID Connect 客户端功能的入门 | | `spring-boot-starter-oauth2-resource-server` | 使用 Spring Security OAuth2 资源服务器功能的起始程序 | | `spring-boot-starter-pulsar` | 使用 Spring for Apache Pulsar 的入门工具 | | `spring-boot-starter-pulsar-reactive` | 使用 Apache Pulsar Reactive 的 Spring 起始器 | | `spring-boot-starter-quartz` | 使用 Quartz 调度器的起始程序 | | `spring-boot-starter-rsocket` | 构建 RSocket 客户端和服务器的入门程序 | | `spring-boot-starter-security` | 使用 Spring Security 的起始工具 | | `spring-boot-starter-test` | 用于测试包含 JUnit Jupiter、Hamcrest 和 Mockito 等库的 Spring Boot 应用的 Starter | | `spring-boot-starter-thymeleaf` | 用于使用 Thymeleaf 视图构建 MVC 网页应用的 Start。 | | `spring-boot-starter-validation` | 使用 Java Bean 验证与 Hibernate Validator 的入门 | | **`spring-boot-starter-web`** | 使用 Spring MVC 构建网页应用(包括 RESTful)的 Starter。默认嵌入式容器使用 Tomcat | | `spring-boot-starter-web-services` | 使用 Spring Web Services 的起始程序 | | `spring-boot-starter-webflux` | 使用 Spring Framework 的反应式网页支持构建 WebFlux 应用的起始程序 | | `spring-boot-starter-websocket` | 用于使用 Spring Framework 的 MVC WebSocket 支持构建 WebSocket 应用的 Starter | # 自动配置 ![image-20260324143225251](assets/image-20260324143225251.png) 通过加载 META-INF/spring.factories中定义的 自动配置类 ![image-20260324143859802](assets/image-20260324143859802.png) ![image-20260324144331597](assets/image-20260324144331597.png) 注册内嵌的Tomcat ```java /* * Copyright 2012-present the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.autoconfigure.web.servlet; import io.undertow.Undertow; import jakarta.servlet.Servlet; import org.apache.catalina.startup.Tomcat; import org.apache.coyote.UpgradeProtocol; import org.eclipse.jetty.ee10.webapp.WebAppContext; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.Loader; import org.xnio.SslClientAuthMode; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.SearchStrategy; import org.springframework.boot.autoconfigure.web.ServerProperties; import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer; import org.springframework.boot.web.embedded.tomcat.TomcatContextCustomizer; import org.springframework.boot.web.embedded.tomcat.TomcatProtocolHandlerCustomizer; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.undertow.UndertowBuilderCustomizer; import org.springframework.boot.web.embedded.undertow.UndertowDeploymentInfoCustomizer; import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Configuration classes for servlet web servers *

* Those should be {@code @Import} in a regular auto-configuration class to guarantee * their order of execution. * * @author Phillip Webb * @author Dave Syer * @author Ivan Sopov * @author Brian Clozel * @author Stephane Nicoll * @author Raheela Asalm * @author Sergey Serdyuk */ @Configuration(proxyBeanMethods = false) class ServletWebServerFactoryConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) static class EmbeddedTomcat { @Bean TomcatServletWebServerFactory tomcatServletWebServerFactory( ObjectProvider connectorCustomizers, ObjectProvider contextCustomizers, ObjectProvider> protocolHandlerCustomizers) { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); factory.getTomcatConnectorCustomizers().addAll(connectorCustomizers.orderedStream().toList()); factory.getTomcatContextCustomizers().addAll(contextCustomizers.orderedStream().toList()); factory.getTomcatProtocolHandlerCustomizers().addAll(protocolHandlerCustomizers.orderedStream().toList()); return factory; } } /** * Nested configuration if Jetty is being used. */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) static class EmbeddedJetty { @Bean JettyServletWebServerFactory jettyServletWebServerFactory( ObjectProvider serverCustomizers) { JettyServletWebServerFactory factory = new JettyServletWebServerFactory(); factory.getServerCustomizers().addAll(serverCustomizers.orderedStream().toList()); return factory; } } /** * Nested configuration if Undertow is being used. */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class }) @ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT) static class EmbeddedUndertow { @Bean UndertowServletWebServerFactory undertowServletWebServerFactory( ObjectProvider deploymentInfoCustomizers, ObjectProvider builderCustomizers) { UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(); factory.getDeploymentInfoCustomizers().addAll(deploymentInfoCustomizers.orderedStream().toList()); factory.getBuilderCustomizers().addAll(builderCustomizers.orderedStream().toList()); return factory; } @Bean UndertowServletWebServerFactoryCustomizer undertowServletWebServerFactoryCustomizer( ServerProperties serverProperties) { return new UndertowServletWebServerFactoryCustomizer(serverProperties); } } } ``` ## 自动配置DispatcherServlet ![image-20260324144116054](assets/image-20260324144116054.png) 不是所有的自动配置类都加载其自动配置的对象,包含条件才会自动配置,比如 `org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration` 需要包含数据源和驱动 ![image-20260324144619677](assets/image-20260324144619677.png) ![image-20260324144635464](assets/image-20260324144635464.png) 用不到 的包尽量先不要添加到依赖中,否则可能会出发自动配置(但是可能因为配置缺少导致报错) ## 排除自动配置 ```java @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) ``` ![image-20260324144850388](assets/image-20260324144850388.png) # SpringBoot的Maven插件 对Spring开发进行支持,比如说打包、热部署等 ```xml org.springframework.boot spring-boot-maven-plugin ``` 使用插件打的jar是可以直接运行的,而不使用插件则jar不能运行 ![image-20260325084404117](assets/image-20260325084404117.png) # Spring的配置 可以没有配置文件,默认有一些配置项,例如: - 默认的服务器 端口号 8080 - 上下文名称 "/" 使用application.properties 或者 application.yaml 常见的配置 [Common Application Properties :: Spring Boot](https://docs.spring.io/spring-boot/3.5/appendix/application-properties/index.html) - yaml格式 ```yaml #yaml 格式的 配置文件在运行的时候,底层会转换成 properties server: port: 7001 servlet: context-path: /boot ``` - properties ```properties server.port=9090 server.servlet.context-path=/boot ``` ## 日志开关 ![image-20260325092354294](assets/image-20260325092354294.png) ``` logging: level: com.neuedu.boot.controller.LogController: TRACE ``` ```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; @RestController public class LogController { Logger logger = LoggerFactory.getLogger(LogController.class); /** * http://127.0.0.1:7001/boot/doLog * @return */ @RequestMapping("/doLog") String doLog(){ logger.trace("trace"); logger.debug("debug ...."); logger.info("info"); logger.warn("warn"); logger.error("error"); return "success"; } } ``` ![image-20260325093223495](assets/image-20260325093223495.png) ![image-20260325093456684](assets/image-20260325093456684.png) springboot使用的是 上层SLF4J的库,调用其他日志框架,默认logback ![image-20260325093554667](assets/image-20260325093554667.png) ## 使用Lombok自动注册Log对象 添加依赖 ``` 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; @RestController @Slf4j public class LogController { //使用SLF4j工具 //Logger log = LoggerFactory.getLogger(LogController.class); /** * http://127.0.0.1:7001/boot/doLog * @return */ @RequestMapping("/doLog") String doLog(){ log.trace("trace"); log.debug("debug ...."); log.info("info"); log.warn("warn"); log.error("error"); return "success"; } } ``` ## 自定义配置 可以在application配置文件中定义属性,在Bean中使用@Value读取 ```yaml #自定义配置项目 jwt: # 生成JWT的秘钥 secret: JWT_S_123456 random: true ``` 使用@Value获取值 `@Value("${key:default}")` - key 就是 application中的key - default 则为 找不到可以的默认值 ``` package com.neuedu.boot.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController public class JWTController { @Value("${jwt.secret}") private String jwtSecret; @Value("${jwt.random}") private boolean random; @Value("${jwt.key:123456}") private String key; /** * http://127.0.0.1:7001/boot/jwt * @return */ @RequestMapping("/jwt") public Map getJwtSecret(){ Map map = new HashMap(); map.put("jwt.secret",jwtSecret); map.put("jwt.random",random); map.put("jwt.key",key); return map; } } ``` 如果key 没有配置,也没有默认值,则会抛出异常 ![image-20260325114820202](assets/image-20260325114820202.png) # jackson配置 无需引入jar ,已经传递依赖了, ``` #yaml 格式的 配置文件在运行的时候,底层会转换成 properties #server: # port: 8080 # servlet: # context-path: / # debug开关 debug: false spring: jackson: # 全局配置日期格式 date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 ``` 可以使用 @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") 覆盖全局的配置,实现个性化 # 热部署 - 不需要重启,自动更新发布 - 添加插件支持 ```xml 4.0.0 com.neuedu.boot springboot-learn 1.0 boot-04-json-support 1.0 jar boot-04-json-support UTF-8 org.springframework.boot spring-boot-starter-web org.projectlombok lombok org.springframework.boot spring-boot-devtools org.springframework.boot spring-boot-maven-plugin ``` 开启IDEA的支持 - 开启运行时自动编译 - File-Settings-Build,Execution...--Compiler ![image-20260325103314086](assets/image-20260325103314086.png) ![image-20260325103358248](assets/image-20260325103358248.png) ![image-20260325103804391](assets/image-20260325103804391.png) 当改动完IDEA的代码后,让IDEA失去焦点,会自动重新部署,不需要手动重启 # 测试支持 ```xml org.springframework.boot spring-boot-starter-test ``` ## 普通测试 ```java package com.neuedu.boot; import org.junit.jupiter.api.Test; public class JunitTest { @Test public void test01(){ System.out.println("hello junit"); } } ``` ## 使用容器获取Bean 需要添加注解 `@SpringBootTest` ```java package com.neuedu.boot.service; import com.neuedu.boot.App06; import com.neuedu.boot.po.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import static org.junit.jupiter.api.Assertions.*; //@SpringBootTest(classes = App04.class) @SpringBootTest class UserServiceTest { @Autowired private UserService userService; @Test void doService() { userService.doService(); } } ``` ## 对MVC进行测试(Mockit) 需要@SPringBootTest+@AutoConfigureMockMvc ```java package com.neuedu.boot.controller; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.web.context.WebApplicationContext; import static org.junit.jupiter.api.Assertions.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc //在容器中注册一个对象 MockMvc class UserControllerTest { @Autowired MockMvc mockMvc; @Test void list() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/user/list")) .andExpect(status().isOk()) .andDo(result -> System.out.println(result.getResponse().getContentAsString())); } } ``` # profile - application-dev.yaml ```yaml #开发的配置项目 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/boot?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8 username: root password: root ``` - application-prod.yaml ```yaml #生产的配置项目 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://192.168.0.100:3306/boot?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8 username: product password: production ``` - application.yaml ```yaml spring: application: name: ProfileAPP profiles: active: prod ``` ![image-20260325135211571](assets/image-20260325135211571.png) ## 在jar中通过命令行激活配置项 - java -jar xxxxx.jar 运行springboot的项目 额外携带参数 - 给虚拟机添加参数 ``` java -Dspring.profiles.active=dev -jar xxxxx.jar java -Dspring.profiles.active=prod -jar xxxxx.jar ``` - 给main方法添加额外的启动参数 ``` java -jar xxxxx.jar --spring.profiles.active=dev -- java -jar xxxxx.jar --spring.profiles.active=prod ``` # Banner ![image-20260325142208876](assets/image-20260325142208876.png) # 使用其他的Servlet服务器替代Tomcat 在pom文档中 排除 Tomcat部分,引入Jetty等starter ```xml 4.0.0 com.neuedu.boot springboot-learn 1.0 boot-05-profile jar boot-05-profile http://maven.apache.org UTF-8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-jetty org.springframework.boot spring-boot-starter-test org.projectlombok lombok org.springframework.boot spring-boot-devtools org.springframework.boot spring-boot-maven-plugin ``` # 异常处理器 Spring MVC已经支持了全局的异常处理器,SpringBoot将所有的错误,默认发送给 /error 的Handler ![image-20260325144311655](assets/image-20260325144311655.png) ![image-20260325144715221](assets/image-20260325144715221.png) ## 在Controller中添加异常处理 ```java package com.neuedu.boot.controller; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class IndexController { /** * http://127.0.0.1:8080/index?numa=10&numb=2 * @param numa * @param numb * @return */ @RequestMapping("/index") public String index(int numa,int numb) { return "result = ("+(numa/numb)+")"; } /** * 异常处理的方法 * http://127.0.0.1:8080/index?numa=10&numb=2 */ @ExceptionHandler(exception = Exception.class) public String handlerException(Exception ex) { ex.printStackTrace(); return "error"; } } ``` 使用ControllerAdvice,添加全局的异常处理器 ``` package com.neuedu.boot.advice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.resource.NoResourceFoundException; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class MyControllerExceptionHandler { /** * 异常处理的方法 * http://127.0.0.1:8080/index?numa=10&numb=2 *

* 默认的 @ControllerAdvice 的方法返回值,之试图 return 的之 应该是 error.html * RestControllerAdvice 的方法返回值, 直接响应给客户端 */ @ExceptionHandler(exception = Exception.class) public Map handlerException(Exception ex) { HashMap map = new HashMap<>(); if(ex instanceof NoResourceFoundException){ map.put("code",404); }else{ map.put("code",500); } map.put("msg",ex.getMessage()); map.put("data",null); return map; } } ``` ![image-20260325145520295](assets/image-20260325145520295.png)![image-20260325145611811](assets/image-20260325145611811.png) # 静态资源 如果需要再springboot项目中添加静态资源,可以放在Resources/static - /resources - /public - /static ![image-20260325153401931](assets/image-20260325153401931.png) ![image-20260325153419079](assets/image-20260325153419079.png) # 使用spring-starter-validation进行数据验证 添加依赖 在需要校验的Controller参数上添加@Valid ![image-20260325154330108](assets/image-20260325154330108.png) 添加校验规则 ![image-20260325154434232](assets/image-20260325154434232.png) ![image-20260325154528068](assets/image-20260325154528068.png) ## 接受错误消息,抛出异常 ```java package com.neuedu.boot.controller; import com.neuedu.boot.exception.ControllerException; import com.neuedu.boot.po.User; import jakarta.validation.Valid; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.*; @RestController @RequestMapping("/user") public class UserController { /** * http://127.0.0.1:8080/user/save?username=admin * @param user * @return */ @RequestMapping("/save") public boolean save(@Valid User user , BindingResult rs) throws ControllerException { System.out.println("模拟保存 user = " + user); List allErrors = rs.getAllErrors(); StringBuffer errormsg = new StringBuffer(); for (ObjectError allError : allErrors) { String defaultMessage = allError.getDefaultMessage(); String objectName = allError.getObjectName(); System.out.println("defaultMessage = " + defaultMessage); System.out.println("objectName = " + objectName); errormsg.append(defaultMessage); } if(errormsg.length()>0){ throw new ControllerException(errormsg.toString()); } return true; } } ``` ![image-20260325155116583](assets/image-20260325155116583.png) ## 使用全局异常处理器捕获异常 ``` package com.neuedu.boot.advice; import com.neuedu.boot.exception.ControllerException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.resource.NoResourceFoundException; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class MyControllerExceptionHandler { /** * 异常处理的方法 * http://127.0.0.1:8080/user/save?username=admin222222222222222222222222222222222 *

* 默认的 @ControllerAdvice 的方法返回值,之试图 return 的之 应该是 error.html * RestControllerAdvice 的方法返回值, 直接响应给客户端 */ @ExceptionHandler(exception = Exception.class) public Map handlerException(Exception ex) { HashMap map = new HashMap<>(); if(ex instanceof NoResourceFoundException){ map.put("code",404); }else if(ex instanceof ControllerException){ map.put("code",503); } else{ map.put("code",500); } map.put("msg",ex.getMessage()); map.put("data",null); return map; } } ``` # SpringJDBC [Using the JDBC Core Classes to Control Basic JDBC Processing and Error Handling :: Spring Framework](https://docs.spring.io/spring-framework/reference/6.2/data-access/jdbc/core.html#jdbc-JdbcTemplate) # 注册Servlet组件: 在SpringBoot中声明Servlet、Filter、Listener可以通过`@ServletComponentScan ` 去扫描 @WebServlet 、@WebFilter、@WebListener ```java package com.neuedu.boot.servletcomponent; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; @WebServlet(urlPatterns = "/oldServlet") public class OldServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.write("

原始的ServletAPI

"); out.flush(); out.close(); } } ``` ![image-20260326091017626](assets/image-20260326091017626.png) ## 使用@Bean注册三大组件 ```java package com.neuedu.boot; import com.neuedu.boot.servletcomponent.OldFilter; import com.neuedu.boot.servletcomponent.OldListener; import com.neuedu.boot.servletcomponent.OldServlet; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.servlet.ServletListenerRegistrationBean; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; /** * Hello world! */ @SpringBootApplication //@ServletComponentScan("com.neuedu.boot.servletcomponent") public class App08 { public static void main(String[] args) { //SpringApplication.run(App08.class, args); SpringApplication.run(App08.class, args); } //通过registion @Bean ServletRegistrationBean getServletRegistrationBean(){ ServletRegistrationBean registrationBean = new ServletRegistrationBean(); registrationBean.setServlet(new OldServlet()); registrationBean.addUrlMappings("/oldServlet"); return registrationBean; } @Bean FilterRegistrationBean getFilterRegistrationBean(){ FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new OldFilter()); registrationBean.addUrlPatterns("/oldServlet"); return registrationBean; } @Bean ServletListenerRegistrationBean getServletListenerRegistrationBean(){ ServletListenerRegistrationBean registrationBean = new ServletListenerRegistrationBean(); registrationBean.setListener(new OldListener()); return registrationBean; } } ``` # 跨域 ## 使用@CrossOrigin注解, ```java @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin @GetMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @DeleteMapping("/{id}") public void remove(@PathVariable Long id) { // ... } } ``` ```java @CrossOrigin(origins = "https://domain2.com", maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @GetMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @DeleteMapping("/{id}") public void remove(@PathVariable Long id) { // ... } } ``` ## 全局的配置 ### CORS Filter ```java @Bean FilterRegistrationBean corsFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("https://127.0.0.1");//前端的 URL浏览器的地址 config.addAllowedHeader("*"); config.addAllowedMethod("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); CorsFilter filter = new CorsFilter(source); registrationBean.setFilter(filter); registrationBean.addUrlPatterns("/*"); return registrationBean; } ``` ### 使用WebMvcConfigurer的实现类,重写addCorsMappings方法注册跨域 # 拦截器(MVC配置) ```java package com.neuedu.boot.interceptors; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; @Component public class LoginHandlerInteceptors implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("LoginHandlerInteceptors.preHandle=== 1 "); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); System.out.println("LoginHandlerInteceptors.preHandle=== 2 "); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("LoginHandlerInteceptors.preHandle=== 3 "); } } ``` ```java package com.neuedu.boot.config; import com.neuedu.boot.interceptors.LoginHandlerInteceptors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration //@EnableWebMvc springboot不需要编写 public class BootAppWebMvcConfiger implements WebMvcConfigurer { @Autowired LoginHandlerInteceptors loginHandlerInteceptors; @Override public void addInterceptors(InterceptorRegistry registry) { //registry.addInterceptor(new LoginHandlerInteceptors()) registry.addInterceptor(loginHandlerInteceptors) //拦截的请求 .addPathPatterns("/*/**") //不拦截的请求 .excludePathPatterns("/login"); } @Override public void addCorsMappings(CorsRegistry registry) { //注册跨域 registry.addMapping("/*/**") .allowedOrigins("https://127.0.0.1") .allowedMethods("*"); //.allowedHeaders("header1", "header2", "header3") //.exposedHeaders("header1", "header2") //.allowCredentials(true).maxAge(3600); } } ``` # 整合MyBatis ## 创建Boot的mvc项目 基础包:com.neuedu.mybatis - SpringBoot的启动类 - 测试的Controller ## 整合 在Boot中整合MyBatis 使用 starter`MyBatis Spring Boot Starter`:Spring Boot starter for MyBatis that simplifies integration of MyBatis SQL mapping framework in Spring Boot applications. - 添加依赖 - 配置数据源 url、username、password、dirverClassName - 使用工具生成 - Mapper.java - Mapper.xml - PO - 扫描 @MapperScan - - 测试 ### 依赖 ```xml org.mybatis.spring.boot mybatis-spring-boot-starter ${mybatis.version} compile com.mysql mysql-connector-j ``` 添加完依赖之后启动报错 ,因为引入mybatis-starter会自动配置数据源但是缺少url、username、password、driverClassname的配置,配之完数据源,因为依赖中有自动配置,所以无需额外注册SQLSessionFactory等,其中自动配置类 `MybatisAutoConfiguration`自动注册SQLSessionFactory ![image-20260326104523763](assets/image-20260326104523763.png) ![image-20260326104649316](assets/image-20260326104649316.png) ![image-20260326104742481](assets/image-20260326104742481.png) ### 配置数据源 - 在application.yaml ``` spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/his?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&&useSSL=false username: root password: root ``` ### 生成Mapper.java ,PO、Mapper.xml ![image-20260326105041180](assets/image-20260326105041180.png) ![image-20260326105104936](assets/image-20260326105104936.png) ![image-20260326105124610](assets/image-20260326105124610.png) ## 注册Mapper 在IOC容器中注册Mapper ![image-20260326105233852](assets/image-20260326105233852.png) ## 测试Mapper使用 ```java package com.neuedu.mybatis.mapper; import com.neuedu.mybatis.MyBatisApp; import com.neuedu.mybatis.po.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import static org.junit.jupiter.api.Assertions.*; //@SpringBootTest(classes = MyBatisApp.class) @SpringBootTest() class UserMapperTest { @Autowired private UserMapper userMapper; @Test void selectByPrimaryKey() { long id = 1; User user = userMapper.selectByPrimaryKey(id); System.out.println(user); } } ``` ![image-20260326105437408](assets/image-20260326105437408.png) # 使用Springboot+myabtis 实现crud 整合依赖,jwt、分页插件 ```xml 4.0.0 com.neuedu.boot springboot-learn 1.0 boot-09-mybatis jar boot-09-mybatis http://maven.apache.org UTF-8 3.0.5 4.5.0 6.1.1 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-validation org.springframework.boot spring-boot-starter-test org.projectlombok lombok org.springframework.boot spring-boot-devtools org.mybatis.spring.boot mybatis-spring-boot-starter ${mybatis.version} compile com.mysql mysql-connector-j com.auth0 java-jwt ${auth0.version} com.github.pagehelper pagehelper ${pagerhelper.version} org.springframework.boot spring-boot-maven-plugin ``` 复制Ret、JWTUtils、异常管理器、拦截器等,改下包名 ![image-20260326113256473](assets/image-20260326113256473.png) 配置拦截器 ```java package com.neuedu.mybatis.config; import com.neuedu.mybatis.interceptor.LoginInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class MvcConfig implements WebMvcConfigurer { /** * 配置拦截器 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .addPathPatterns("/*/**") .excludePathPatterns("/login"); } } ``` 全局的异常处理器 ```java package com.neuedu.mybatis.framework; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; @RestControllerAdvice public class BusinessHandlerExceptionResolver { @ExceptionHandler(Exception.class) public Ret resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { String message = ex.getMessage(); ObjectMapper objectMapper = new ObjectMapper(); //String userJson = objectMapper.writeValueAsString(users); Ret ret = Ret.fail(message != null ? message : "操作失败"); return ret; } } ``` # MyBatisPlus搭建 - **无侵入**:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑 - **损耗小**:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作 - **强大的 CRUD 操作**:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求 - **支持 Lambda 形式调用**:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错 - **支持主键自动生成**:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题 - **支持 ActiveRecord 模式**:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作 - **支持自定义全局通用操作**:支持全局通用方法注入( Write once, use anywhere ) - **内置代码生成器**:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用 - **内置分页插件**:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询 - **分页插件支持多种数据库**:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库 - **内置性能分析插件**:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询 - **内置全局拦截插件**:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作 ## 创建一个空的 Spring Boot 工程 添加依赖 ```xml 4.0.0 com.neuedu.boot springboot-learn 1.0 boot-10-mp jar boot-10-mp http://maven.apache.org UTF-8 4.5.0 3.5.15 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-validation org.springframework.boot spring-boot-starter-test org.projectlombok lombok org.springframework.boot spring-boot-devtools com.baomidou mybatis-plus-spring-boot3-starter ${mp.version} com.mysql mysql-connector-j com.auth0 java-jwt ${auth0.version} org.springframework.boot spring-boot-maven-plugin ``` 配置数据源 ```yaml spring: # 数据源的配置 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/his?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&&useSSL=false username: root password: root ``` ## 启动类添加MapperScan ```java package com.neuedu.boot; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * Hello world! * */ @SpringBootApplication @MapperScan("com.neuedu.boot.mapper") public class MPApp { public static void main( String[] args ) { SpringApplication.run(MPApp.class,args); } } ``` ## 实体类 User ```java package com.neuedu.boot.po; import lombok.Data; import java.io.Serializable; import java.util.Date; import com.baomidou.mybatisplus.annotation.TableName; /** * 用户表 * * @TableName user */ @Data @TableName("`user`") public class User implements Serializable { /** * 主键 */ private Long userId; /** * 用户名 */ private String username; /** * 密码 */ private String password; /** * 过期时间 */ private Date expire; /** * 最后一次登录四件 */ private Date lastLogin; /** * 真实姓名 */ private String realName; /** * 部门ID */ private Long deptId; /** * 部门名称 */ private String deptName; /** * 级别ID */ private Long levelId; /** * 创建时间 */ private Date createTime; private static final long serialVersionUID = 1L; @Override public boolean equals(Object that) { if (this == that) { return true; } if (that == null) { return false; } if (getClass() != that.getClass()) { return false; } User other = (User) that; return (this.getUserId() == null ? other.getUserId() == null : this.getUserId().equals(other.getUserId())) && (this.getUsername() == null ? other.getUsername() == null : this.getUsername().equals(other.getUsername())) && (this.getPassword() == null ? other.getPassword() == null : this.getPassword().equals(other.getPassword())) && (this.getExpire() == null ? other.getExpire() == null : this.getExpire().equals(other.getExpire())) && (this.getLastLogin() == null ? other.getLastLogin() == null : this.getLastLogin().equals(other.getLastLogin())) && (this.getRealName() == null ? other.getRealName() == null : this.getRealName().equals(other.getRealName())) && (this.getDeptId() == null ? other.getDeptId() == null : this.getDeptId().equals(other.getDeptId())) && (this.getDeptName() == null ? other.getDeptName() == null : this.getDeptName().equals(other.getDeptName())) && (this.getLevelId() == null ? other.getLevelId() == null : this.getLevelId().equals(other.getLevelId())) && (this.getCreateTime() == null ? other.getCreateTime() == null : this.getCreateTime().equals(other.getCreateTime())); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((getUserId() == null) ? 0 : getUserId().hashCode()); result = prime * result + ((getUsername() == null) ? 0 : getUsername().hashCode()); result = prime * result + ((getPassword() == null) ? 0 : getPassword().hashCode()); result = prime * result + ((getExpire() == null) ? 0 : getExpire().hashCode()); result = prime * result + ((getLastLogin() == null) ? 0 : getLastLogin().hashCode()); result = prime * result + ((getRealName() == null) ? 0 : getRealName().hashCode()); result = prime * result + ((getDeptId() == null) ? 0 : getDeptId().hashCode()); result = prime * result + ((getDeptName() == null) ? 0 : getDeptName().hashCode()); result = prime * result + ((getLevelId() == null) ? 0 : getLevelId().hashCode()); result = prime * result + ((getCreateTime() == null) ? 0 : getCreateTime().hashCode()); return result; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); sb.append(" ["); sb.append("Hash = ").append(hashCode()); sb.append(", userId=").append(userId); sb.append(", username=").append(username); sb.append(", password=").append(password); sb.append(", expire=").append(expire); sb.append(", lastLogin=").append(lastLogin); sb.append(", realName=").append(realName); sb.append(", deptId=").append(deptId); sb.append(", deptName=").append(deptName); sb.append(", levelId=").append(levelId); sb.append(", createTime=").append(createTime); sb.append(", serialVersionUID=").append(serialVersionUID); sb.append("]"); return sb.toString(); } } ``` ## 编写 Mapper 接口类 `UserMapper.java` 单表的CRUD 不需要额外写内容个 ```java public interface UserMapper extends BaseMapper { } ``` ## 添加测试类,进行功能测试: ```java package com.neuedu.boot.mapper; import com.neuedu.boot.MPApp; import com.neuedu.boot.po.User; 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.*; @SpringBootTest(classes = MPApp.class) class UserMapperTest { @Autowired private UserMapper userMapper; @Test public void testSelectByID(){ long id = 1L; User user = userMapper.selectById(id); System.out.println(user); } @Test public void test(){ List list = userMapper.selectList(null); System.out.println(list); } } ``` ## Service层接口的用法 跟Mapper层的区别是更新操作会携带事务 ```java package com.neuedu.boot.service; import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.neuedu.boot.mapper.UserMapper; import com.neuedu.boot.po.User; import org.springframework.stereotype.Service; @Service public class UserService extends ServiceImpl { } ``` ```java package com.neuedu.boot.service; import com.neuedu.boot.po.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest class UserServiceTest { @Autowired private UserService userService; /** * */ @Test public void testGetById(){ long id = 1L; User user = userService.getById(id); System.out.println(user); } } ``` # MP使用 持久层接口 - Mapper - Service ## Service层方法 service方法详见官网文档,[传送门](https://www.baomidou.com/guides/data-interface/) ```java package com.neuedu.boot.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.neuedu.boot.po.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.Date; import java.util.List; @SpringBootTest class UserServiceTest { @Autowired private UserService userService; @Test public void testList() { //全量查询 //List list = userService.list(); //list.forEach(System.out::println); //带条件查询 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.like("username", "a"); List list = userService.list(queryWrapper); list.forEach(System.out::println); } /** * */ @Test public void testGetById() { long id = 1L; User user = userService.getById(id); System.out.println(user); } @Test public void testSave() { User user = new User(); user.setUsername("mp-user"); user.setPassword("mp-123456"); user.setRealName("mp-管理员"); boolean success = userService.save(user); System.out.println(success); } //删除 @Test public void testRemove() { //根据主键删除 //long id = 20L; //boolean success = userService.removeById(id); //System.out.println(success); //根据条件删除 删除条件 QueryWrapper 条件构造器 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("username", "mp-user"); queryWrapper.like("password", "mp-123456"); boolean success = userService.remove(queryWrapper); System.out.println(success); } @Test public void testUpdate() { //User user = userService.getById(17L); //user.setRealName("使用MP更新"); // //boolean success = userService.updateById(user); //System.out.println(success); User user = new User(); user.setExpire(new Date()); //根据条件删除 删除条件 QueryWrapper 条件构造器 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("password", "123456"); boolean success = userService.update(user,queryWrapper); System.out.println(success); } } ``` ## Mapper分层方法 mapper层已经实现的方法 [传送门](https://www.baomidou.com/guides/data-interface/#mapper-interface) ```java package com.neuedu.boot.mapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.neuedu.boot.MPApp; import com.neuedu.boot.po.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.Date; import java.util.List; @SpringBootTest(classes = MPApp.class) class UserMapperTest { @Autowired private UserMapper userMapper; @Test public void testSelectByID() { long id = 1L; User user = userMapper.selectById(id); System.out.println(user); } @Test public void test() { List list = userMapper.selectList(null); System.out.println(list); } @Test public void testList() { //全量查询 //List list = userService.list(); //list.forEach(System.out::println); //带条件查询 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.like("username", "a"); List list = userMapper.selectList(queryWrapper); list.forEach(System.out::println); } /** * */ @Test public void testGetById() { long id = 1L; User user = userMapper.selectById(id); System.out.println(user); } @Test public void testSave() { User user = new User(); user.setUsername("mp-user-mapper"); user.setPassword("mp-123456-mapper"); user.setRealName("mp-管理员-mapper"); int count = userMapper.insert(user); System.out.println(count); } //删除 @Test public void testRemove() { //根据主键删除 //long id = 20L; //boolean success = userService.removeById(id); //System.out.println(success); //根据条件删除 删除条件 QueryWrapper 条件构造器 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("username", "mp-user"); queryWrapper.like("password", "mp-123456"); int count = userMapper.delete(queryWrapper); System.out.println(count); } @Test public void testUpdate() { //User user = userMapper.selectById(17L); //user.setRealName("使用MP更新"); // //int count = userMapper.updateById(user); //System.out.println(count); User user = new User(); user.setExpire(new Date()); //根据条件删除 删除条件 QueryWrapper 条件构造器 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("password", "123456"); int count = userMapper.update(user, queryWrapper); System.out.println(count); } } ``` ## 分页 ### 添加依赖 ```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; @Configuration public class MyBatisPlusConfig { /** * 添加分页插件 */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } } ``` ### 使用分页 ```java package com.neuedu.boot.service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.neuedu.boot.po.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.Date; import java.util.List; @SpringBootTest class UserServicePageTest { @Autowired private UserService userService; @Test public void testPage() { int current = 1; int size = 5; Page page = userService.page(new Page<>(current, size)); //总页数 long pages = page.getPages(); //总条数 long total = page.getTotal(); //分页数据 List records = page.getRecords(); System.out.println("current = " + current); System.out.println("size = " + size); System.out.println("pages = " + pages); System.out.println("total = " + total); System.out.println("records = " + records); current = 2; //size = 5; System.out.println("\r\n\r\n\r\n"); //第二页的数据 page = userService.page(new Page<>(current, size)); //总页数 pages = page.getPages(); //总条数 total = page.getTotal(); //分页数据 records = page.getRecords(); System.out.println("current = " + current); System.out.println("size = " + size); System.out.println("pages = " + pages); System.out.println("total = " + total); System.out.println("records = " + records); } } ``` ## LambdaQueryWarpper ### JDK1.8添加了一个Lambda的功能 ```java package com.neuedu; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; public class Runner { public static void main(String[] args) { List list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); //filter 的作用是过滤 Stream //Stream stream = list.stream().filter(new Predicate() { // @Override // public boolean test(Integer num) { // return num % 2 == 0; // } //}); // ////循环 //stream.forEach(new Consumer(){ // // @Override // public void accept(Integer integer) { // System.out.println(integer); // } //}); //filter 的作用是过滤 //Stream stream = list.stream().filter( (Integer num) ->{ // return num % 2 == 0; // } //); //lambda 过滤 Stream stream = list.stream().filter( num-> num % 2 == 0 ); //stream.forEach((Integer num)->{ // System.out.println( num); //}); //stream.forEach( num-> System.out.println( num) ); //方法 的传递 对象的方法发 stream.forEach( System.out::println ); //静态方法的传递 stream.forEach( Out::show ); //构造方法的传递 //Runnable aNew = Out::new; } } class Out{ public static void show(int a){ System.out.println(a); } } ``` ``` package com.neuedu.boot.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.neuedu.boot.po.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.Date; import java.util.List; @SpringBootTest class UserServiceLambdaQueryWrapperTest { @Autowired private UserService userService; @Test public void testList() { //全量查询 //List list = userService.list(); //list.forEach(System.out::println); //带条件查询 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.like(User::getUsername, "a"); List list = userService.list(queryWrapper); list.forEach(System.out::println); } } ``` ## 主键生成策略 ```java CREATE TABLE `his`.`mybatisplus`( `id` VARCHAR(50) NOT NULL COMMENT '主键', `name` VARCHAR(100) COMMENT '姓名', `age` int(100) COMMENT '年龄', PRIMARY KEY (`id`) ); ``` ```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 user */ @Data @TableName("`mybatisplus`") public class MyBaitsPlusPO implements Serializable { /** * 主键 */ @TableId(type = IdType.ASSIGN_UUID) private String id; //user_id private String name; //user_id private Integer age; //user_id } ``` ## 逻辑删除 ```sql ALTER TABLE `his`.`mybatisplus` ADD COLUMN `is_delete` VARCHAR(3) DEFAULT '0' NULL COMMENT '是否删除,0 正常,1 已删除' AFTER `age`; ``` ![image-20260327113849818](assets/image-20260327113849818.png)