Day5学习--SpringBoot详解
Day5学习–SpringBoot详解SpringBoot的核心作用Spring Boot 是基于 Spring 框架的“快速开发脚手架”它的核心设计理念是**“约定优于配置”**。它并不是用来替代 Spring 的而是为了解决传统 Spring 开发中存在的痛点告别繁琐配置摒弃了传统 Spring 大量的 XML 配置通过自动化配置和默认约定实现零配置或极简配置即可启动项目。开箱即用内置了 Tomcat、Jetty 等 Web 服务器项目可以直接打包成 Jar 包运行无需再单独部署到外部服务器。简化依赖管理提供了一系列“起步依赖Starter”将常用技术栈的依赖整合在一起自动解决版本冲突问题。自动配置原理Spring Boot 能够实现“开箱即用”的核心在于自动配置Auto-Configuration。其核心入口是项目启动类上的SpringBootApplication注解。SpringBootApplication是一个组合注解主要包含以下三个核心部分SpringBootConfiguration标识当前类是一个配置类。ComponentScan自动扫描并注册当前启动类所在包及其子包下的 Bean。EnableAutoConfiguration开启自动配置的灵魂。底层加载逻辑EnableAutoConfiguration底层通过Import导入了AutoConfigurationImportSelector类。在 Spring Boot 2.x 中它会读取META-INF/spring.factories文件。在 Spring Boot 3.x 中改为读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件。加载到全量自动配置类后Spring Boot 会通过Conditional系列条件注解如ConditionalOnClass、ConditionalOnMissingBean进行过滤。只有当类路径下存在特定的类例如引入了 Web 依赖且容器中不存在该 Bean 时对应的默认配置才会生效最终将组件实例注册到 Spring 容器中。快速创建项目与依赖引入目前创建 Spring Boot 项目最主流的方式是使用Spring Initializr可以通过 IDEA 内置或官网 https://start.spring.io/ 访问。它能自动生成符合规范的项目结构和pom.xml文件。Spring Boot 通过Starter起步依赖把常用依赖封装为一个坐标避免了手动管理版本冲突。例如引入spring-boot-starter-web就能自动集成 Tomcat、Spring MVC 和 JSON 转换器。pom.xml文件示例!-- 继承 Spring Boot 父工程利用其版本仲裁机制 --parentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.2.5/version/parentdependencies!-- 引入 Web 起步依赖开箱即用 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency/dependenciesYML配置文件与端口配置企业级开发中更推荐使用.yml格式代替传统的.properties文件。YML 采用树形层级结构可读性更强且支持复杂的数据结构。修改默认端口Spring Boot 内置的 Tomcat 默认端口是 8080。如果发生端口占用可以直接在配置文件中修改。application.yml示例server:port:8081# 修改默认启动端口为 8081servlet:context-path:/api# 配置项目的访问路径前缀日志配置LoggingSpring Boot 默认使用SLF4J作为日志门面Logback作为底层实现。默认的日志级别是INFO这意味着只会打印INFO、WARN和ERROR级别的日志。日志级别从低到高依次为TRACEDEBUGINFOWARNERROR在开发阶段为了排查问题我们通常需要开启DEBUG级别的日志。logging:level:root:INFO# 全局日志级别com.arguan:DEBUG# 将我们自己的项目包路径设置为 DEBUG 级别自定义参数配置与读取除了框架自带的配置我们经常需要在配置文件中定义一些业务参数如第三方接口的密钥、系统名称等。# 自定义业务参数my-app:name:SpringBoot-Testingversion:1.0.0max-retry:3在 Java 代码中读取自定义参数可以使用Value注解将配置文件中的值注入到属性中。RestControllerRequestMapping(/test)publicclassConfigController{// 读取自定义配置Value(${my-app.name})privateStringappName;Value(${my-app.max-retry:5})// 如果配置文件中没有默认值为 5privateIntegermaxRetry;GetMapping(/info)publicStringgetConfig(){return应用名称appName最大重试次数maxRetry;}}项目分层架构MVC思想在企业级开发中为了保证代码的高内聚、低耦合以及良好的可维护性通常采用经典的四层架构。每一层都有其明确的职责严禁跨层调用。Entity实体层也称为 POJO 或 Domain 层。它的作用是映射数据库中的表结构一个实体类对应一张数据表。通常只包含属性、Getter/Setter 方法不包含任何业务逻辑。Mapper持久层也称为 DAOData Access Object层。它的作用是直接与数据库交互负责数据的增删改查CRUD。在 Spring Boot 中通常使用 MyBatis 或 JPA 来实现。Service业务层系统的“大脑”负责处理核心业务逻辑如参数校验、事务控制、复杂计算等。Controller 层接收请求后会调用 Service 层来处理具体业务Service 层再调用 Mapper 层操作数据库。Controller控制层系统的“门面”负责接收前端发来的 HTTP 请求解析参数调用 Service 层获取结果并最终将响应数据返回给前端。请求接收与参数绑定Spring Boot 提供了非常便捷的注解来接收前端传递的不同类型的参数。以下是开发中最常用的三种参数绑定方式PathVariable路径参数用于接收 URL 路径中的参数常用于 RESTful 风格的接口比如根据 ID 查询或删除某个资源。示例GET /users/101接收 ID101。RequestParam查询参数用于接收 URL 问号?后面的键值对参数如?name张三age18。常用于分页查询、条件搜索等简单参数的传递。RequestBodyJSON 对象参数用于接收前端请求体Request Body中的 JSON 格式数据。常用于新增POST或修改PUT操作可以将复杂的 JSON 对象直接映射为后端的 Java 实体对象。本人在自学网课过程中开发了一个智能学习辅助系统所以我将使用系统中实现过的代码来演示三种请求接收参数删除部门–使用RequestParam注解在系统中比如要对一个部门进行部门管理其中有一个功能是删除部门那么访问数据库时的语句就需要根据部门的ID进行删除这时候我们就需要接收ID这个参数。/** * 删除部门 使用RequestParam注解 * 注意事项一旦声明了RequestParam注解该参数在请求时必须传递如果不传递将会报错 * param id * return */DeleteMapping(/depts)publicResultdelete(RequestParam(id)Integerid){System.out.println(根据ID删除部门id);returnResult.success();}获取部门信息–使用PathVariable注解如果想在一个部门列表中针对某一个部门去获取他的信息时我们也需要去获取他的ID从而到数据库中进行查询返回所需的部门信息我们可以使用路径参数来获取。/** * 获取部门信息 * param id * return */GetMapping(/{id})publicResultget(PathVariableIntegerid){System.out.println(查询部门IDid);DeptdeptdeptService.findById(id);returnResult.success(dept);}添加部门–使用RequestBody注解需要添加部门时系统需要接收一个部门的所有信息这时候我们可以接受一个部门类的请求体使用JSON格式封装数据它会自动映射成后端在实体类中所定义的部门类的对象实现参数接收。/** * 添加部门 * param dept * return */PostMappingpublicResultadd(RequestBodyDeptdept){System.out.println(添加部门dept.getName());deptService.addDept(dept);returnResult.success();}响应返回与统一结果封装在前后端分离的开发模式下为了降低前端的解析成本后端所有接口必须返回统一的数据格式。通常我们会封装一个泛型类ResultT包含状态码code、提示信息msg和业务数据data。publicclassResultT{privateIntegercode;// 状态码200表示成功500表示失败privateStringmsg;// 提示信息privateTdata;// 业务数据泛型可适应任意类型// 省略构造方法、Getter 和 Setter// 成功响应publicstaticTResultTsuccess(Tdata){returnnewResult(200,操作成功,data);}// 失败响应publicstaticTResultTerror(Stringmsg){returnnewResult(500,msg,null);}}简单接口开发实战新增与查询)结合上述的分层架构参数绑定和统一相应格式我实现了一个简单的接口开发代码Entity层用户实体类publicclassUser{privateLongid;privateStringusername;privateIntegerage;// 省略 Getter 和 Setter}Mapper 层模拟数据库操作MapperpublicinterfaceUserMapper{// 模拟插入用户intinsert(Useruser);// 模拟根据ID查询用户UserselectById(Longid);}Service 层处理业务逻辑ServicepublicclassUserService{AutowiredprivateUserMapperuserMapper;publicUsersaveUser(Useruser){// todo... 业务逻辑比如校验用户名是否重复userMapper.insert(user);returnuser;}publicUsergetUserById(Longid){returnuserMapper.selectById(id);}}Controller 层对外暴露接口RestControllerRequestMapping(/api/users)publicclassUserController{AutowiredprivateUserServiceuserService;// 接口1新增用户使用 RequestBody 接收 JSON 参数PostMapping(/add)publicResultUseraddUser(RequestBodyUseruser){UsersavedUseruserService.saveUser(user);returnResult.success(savedUser);}// 接口2查询用户使用 PathVariable 接收路径参数GetMapping(/{id})publicResultUsergetUser(PathVariableLongid){UseruseruserService.getUserById(id);if(user!null){returnResult.success(user);}returnResult.error(用户不存在);}// 接口3返回统一结果测试无参接口GetMapping(/hello)publicResultStringsayHello(){returnResult.success(你好高冠林);}}学习中的问题依赖冲突在引入第三方依赖时如果遇到版本冲突可以利用 Maven 的依赖树mvn dependency:tree查看冲突情况并使用exclusion标签排除不需要的依赖版本。Spring Boot 的父工程Parent已经帮我们管理了绝大多数常用依赖的版本尽量优先使用 Starter。端口占用启动项目时如果报错Port 8080 was already in use说明 8080 端口被其他程序或上一次未正常关闭的项目占用。最快的解决方法是在application.yml中修改server.port: 8081或者在命令行中查出占用端口的进程 PID 并将其强制结束。