ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SpringBoot零基础入门:从环境搭建到自动配置原理与实战

SpringBoot零基础入门:从环境搭建到自动配置原理与实战 1. 先搞清楚SpringBoot到底解决了什么问题1.1 从SSH/SSM时代说起在SpringBoot还没火起来的那几年Java后端开发的主流套路是SSMSpring SpringMVC MyBatis或者更早的SSHStruts Spring Hibernate。那时候每搭一个新项目我先要干的事几乎一模一样去官网下载各种依赖jar包手动扔到WEB-INF/lib目录下写web.xml把Spring的ApplicationContext配进去再配SpringMVC的DispatcherServlet配数据源配事务管理器配日志框架……整套流程走下来不熟悉的人折腾一整天都是正常的。更让人崩溃的是版本冲突——Spring 4.x和MyBatis 3.x的某个小版本不兼容报的错可能完全看不懂最后只能靠百度一个个搜。这种状态持续了很长时间直到SpringBoot出现才真正把Java后端开发的体验拉到了开箱即用的层面。它并不是要替代Spring而是在Spring的基础上做了一次彻底的自动化封装把那些重复的、繁琐的、容易出错的配置全部收敛掉。核心就一句话约定大于配置。你不需要告诉SpringBoot我要用SpringMVC只要引入spring-boot-starter-web它就知道你要做Web项目自动帮你把DispatcherServlet、内嵌Tomcat、Jackson序列化这些全部配好。1.2 SpringBoot的核心价值拆解我经常跟刚入门的朋友说理解SpringBoot可以从三个关键词入手第一个关键词是自动配置AutoConfiguration。这是SpringBoot的灵魂。它通过EnableAutoConfiguration注解配合META-INF/spring.factories文件里声明的自动配置类在项目启动时根据classpath下的依赖、已有的Bean、配置文件里的属性智能地帮你创建好那些你过去需要手写的Bean。举个例子你引入了spring-boot-starter-data-redisSpringBoot检测到classpath里有RedisTemplate相关的类就会自动帮你创建连接工厂和RedisTemplate你只需要在application.yml里写上redis的host和port就能直接用了。第二个关键词是starter机制。简单理解就是一套场景化依赖打包方案。以前你引入一个功能得自己找五六七八个依赖还得担心版本兼容性。现在spring-boot-starter-xxx直接帮你把该场景下的所有依赖、版本、默认配置都打包好了。你引入spring-boot-starter-web它连带把spring-webmvc、spring-web、jackson、tomcat-embed-core全都拉进来版本还经过官方测试不会出现莫名其妙的不兼容。第三个关键词是内嵌容器。SpringBoot默认内置Tomcat、Jetty或Undertow你的应用启动后就是一个可执行的jar包java -jar直接运行不需要再单独安装Tomcat、部署war包。这对开发和部署都是革命性的简化。尤其是现在微服务、容器化的场景下一个服务打成一个jar扔进Docker镜像比传统方式不知道省了多少事。解决了什么问题一句话总结把Java后端开发的入门门槛和开发效率一次性拉到及格线以上。适合谁看零基础想学Java后端的同学、刚转SpringBoot的开发人员、以及想系统梳理SpringBoot知识点的中级开发这篇内容都覆盖了。2. 零基础环境搭建JDK、Maven、IDEA一次到位2.1 JDK安装与环境变量配置网上很多教程一上来就写代码结果新手连环境都没搭好跑起来全是报错。环境这关必须走扎实。先说JDK。现在SpringBoot 3.x强制要求JDK 17以上SpringBoot 2.x则支持JDK 8。我个人的建议是学习阶段直接用SpringBoot 2.7.x JDK 8原因很简单——目前公司存量项目大量还是这个组合面试聊的项目经验也大多基于此等上手了再切JDK 17也不迟。当然如果是全新项目直接上SpringBoot 3.x JDK 17是更好的选择。JDK安装本身不复杂去Oracle官网或使用开源的Adoptium也就是Eclipse Temurin下载对应系统的安装包。Windows下建议直接下载.msi安装包一路Next就行。重点说环境变量配置这一步很多人栽跟头。配置三个环境变量JAVA_HOME指向JDK安装目录比如C:\Program Files\Java\jdk1.8.0_202。注意不要配到bin目录要配到JDK的根目录。PATH在最前面追加%JAVA_HOME%\bin这样在任意目录下执行java、javac命令都能被找到。CLASSPATH配置为.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar。最前面的.代表当前目录这很关键。配置完成后打开命令行窗口输入java -version如果能正常输出版本信息说明JDK安装成功。这一步验证很重要别跳。注意配置环境变量后如果命令行窗口是之前打开的需要关掉重新打开才会生效。Windows下修改系统环境变量后已打开的cmd窗口不会自动刷新。2.2 Maven安装与镜像配置Maven是Java项目的构建管理工具SpringBoot项目依赖的下载、打包、依赖管理全靠它。安装Maven同样简单去Apache Maven官网下载二进制压缩包解压到一个不带中文和空格的目录然后配置环境变量MAVEN_HOME指向解压目录PATH里追加%MAVEN_HOME%\bin。命令行输入mvn -v验证。但真正影响开发体验的是Maven的镜像配置。默认情况下Maven从中央仓库下载依赖国内网络环境下载速度极慢有时候一个依赖卡几分钟。解决办法是修改Maven安装目录conf/settings.xml在里面配置阿里云镜像mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror配置完镜像后再新建项目时依赖下载速度会有一个质的提升。另外建议在settings.xml里设置本地仓库路径默认是在C:\Users\用户名.m2\repository时间长了会占用大量C盘空间。我习惯把它改到D盘localRepositoryD:/maven-repo/localRepository2.3 IDEA的下载、配置与常用插件IDE这里我推荐IntelliJ IDEA社区版就够学习和单体项目使用了如果你用Ultimate版会更顺手。装好之后有一项关键配置IDEA默认会使用自己内置的Maven但那个版本可能跟你命令行安装的不一致最好把IDEA的Maven指向自己安装的版本。操作路径File - Settings - Build, Execution, Deployment - Build Tools - Maven。在Maven home path里选择你安装的Maven目录在User settings file里勾选Override并选择conf/settings.xmlLocal repository会自动读取settings.xml里的配置。还要检查两个地方一是Project SDK要选对JDK版本在File - Project Structure里设置二是设置编译级别确保与JDK版本匹配。配置完成后可以用IDEA的Maven面板执行mvn clean compile测试一下确保环境通了再往下走。提示学习阶段不要急着装一堆插件。SpringAssistant原Spring Assistant、Lombok、MyBatisX这几个插件前期够用了。插件装多了反而影响IDEA启动速度也容易让你分心。3. 第一个SpringBoot项目从创建到跑起来3.1 使用IDEA快速创建项目环境准备好之后创建第一个SpringBoot项目就非常简单了。在IDEA里选择File - New - Project左侧选Spring Initializr这就是Spring官方提供的项目生成工具。SDK选择你配置好的JDK版本点击Next后会让你选择项目坐标Group一般填公司域名反写比如com.exampleArtifact填项目名比如demo。关键一步在Dependencies选择界面。学习阶段我建议只勾选两个依赖Spring Web和Spring Boot DevTools。DevTools是开发热部署工具改完代码自动重启不用手动重启项目能明显提升开发效率。不要贪多先让项目跑起来再说后面用到什么加什么。点击Finish后IDEA会自动帮你从Maven中心仓库下载所有依赖。首次下载可能需要几分钟下载完成后你会看到项目结构已经生成好了。3.2 项目结构拆解创建完成的SpringBoot项目核心结构是这样的demo/ ├── pom.xml ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/example/demo/ │ │ │ └── DemoApplication.java │ │ └── resources/ │ │ ├── static/ │ │ ├── templates/ │ │ └── application.properties │ └── test/ │ └── java/重点是这几个pom.xml是Maven的核心配置文件里面声明了项目坐标、父依赖、所有starter依赖和构建插件。SpringBoot项目会自动继承spring-boot-starter-parent这个父依赖好处是所有SpringBoot的依赖版本都已经被官方统一定义好了你在pom.xml里引入spring-boot-starter-xxx时不需要写版本号父依赖会统一管理。DemoApplication.java是启动类上面有三个关键注解SpringBootApplication、EnableAutoConfiguration、ComponentScan。其中SpringBootApplication是一个组合注解它把SpringBootConfiguration、EnableAutoConfiguration、ComponentScan三个注解组合到了一起。也就是说你只要写了SpringBootApplicationSpringBoot就自动帮你完成了配置加载、自动配置和组件扫描三件事。resources目录下application.properties是配置文件static目录放静态资源templates目录放模板引擎的页面比如Thymeleaf模板。3.3 核心代码与启动验证启动类默认的代码就几行SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }直接右键运行DemoApplication的main方法控制台看到类似 Spring Boot Started 的日志就说明项目启动成功了。默认端口是8080浏览器访问http://localhost:8080此时会返回一个Whitelabel错误页面——别慌这是正常的因为你还没有写任何接口。写一个最简单的接口来验证Web功能新建一个Controller类RestController public class HelloController { GetMapping(/hello) public String hello() { return Hello SpringBoot!; } }重启项目浏览器访问http://localhost:8080/hello能看到页面输出Hello SpringBoot!你的第一个SpringBoot应用就正式跑通了。到这里你已经跨过了最难的“环境项目搭建”门槛后面就是不断往项目里加东西的过程。注意启动类必须放在所有Controller、Service、Mapper包的最外层。因为SpringBootApplication默认扫描的是启动类所在包及其子包。很多新手把启动类放在com.example.demo根包下却在com.example.controller建Controller然后发现扫描不到就是这个原因。4. 核心原理自动配置与starter机制拆解4.1 SpringBootApplication背后的组合逻辑很多初学者用SpringBoot写接口很容易但要问一句SpringBoot为什么能自动配置就卡住了。面试的时候这个问题也是高频中的高频值得搞明白。SpringBootApplication是个组合注解点进去看源码会发现它上面标了三个核心注解SpringBootConfiguration本质是Configuration标明当前类是配置类。EnableAutoConfiguration启用自动配置这是最核心的。ComponentScan开启组件扫描默认扫描当前包及其子包。其中EnableAutoConfiguration点进去会看到它导入了一个AutoConfigurationImportSelector类。这个类做的事情是从classpath下的META-INF/spring.factories文件中读取所有以org.springframework.boot.autoconfigure.EnableAutoConfiguration为key配置的自动配置类全限定名然后按条件逐个判断是否启用。重点来了——判断条件被封装成了一系列Conditional注解。比如ConditionalOnClass表示classpath下存在指定类才生效ConditionalOnMissingBean表示不存在指定Bean才生效ConditionalOnProperty表示配置了指定属性才生效。这些条件组合起来实现了有需要就自动配不需要就不配的智能逻辑。4.2 starter机制为什么引入依赖就能用starter是SpringBoot里另一个非常重要的概念。每个starter本质上就是一个空项目的jar包但它通过pom.xml声明了一组关联依赖这样你引入一个starter就能一次性拿到该场景下的所有依赖。拿spring-boot-starter-web举例。你只用写一行依赖但它会传递引入这些jar包spring-webmvcSpringMVC的核心spring-webWeb开发的基础支持spring-boot-starter-jsonJSON序列化支持spring-boot-starter-tomcat内嵌Tomcat容器spring-boot-starterSpringBoot的核心自动配置更关键的是这些依赖的版本都由spring-boot-starter-parent统一锁定你不需要关心它们之间的兼容性官方已经帮你测好了。这就解决了过去SSM时代最恼火的版本冲突问题。4.3 常用注解速查与使用场景SpringBoot的注解体系本质上还是Spring那套只是增加了一些默认行为和便捷封装。我整理一份初学者必须掌握的清单注解作用典型使用位置SpringBootApplication组合注解标记启动类启动类RestControllerController ResponseBody返回JSON控制层RequestMapping / GetMapping / PostMapping映射HTTP请求路径和方法控制层方法Service标记业务层Bean服务层实现类Repository / Mapper标记数据访问层BeanMapper接口Autowired / Resource依赖注入字段/setter/构造器ConfigurationProperties绑定配置文件的属性到Bean配置类Value注入单个配置属性值任意BeanTransactional声明式事务Service方法ControllerAdvice全局异常处理/全局数据绑定全局处理类4.4 自动配置的避坑心得自动配置虽然省事但也带来一个典型问题有时候你并不想让SpringBoot的默认配置生效想手动覆盖。比如SpringBoot默认的JSON序列化组件是Jackson你项目里用的是Fastjson2那就要做好排除。排除的方式有两种。一种是在启动类上标注exclude属性SpringBootApplication(exclude {RedisAutoConfiguration.class}) public class DemoApplication { ... }另一种是在application.yml里配置excludespring: autoconfigure: exclude: org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration我踩过的坑是某些自动配置类在项目启动时就执行了连接逻辑一旦你不想用它但又没排除项目会启动失败。比如你引入了Redis的starter但本地还没装Redis启动时就会报连接拒绝。这时候别急着怀疑代码先看一眼自动配置有没有做排除又或者把Redis装上。5. 配置管理application.yml的高阶玩法5.1 从properties到yaml的转变SpringBoot的配置文件默认是application.properties但在实际项目中绝大多数团队已经改用application.yml了。原因很简单YAML格式层次分明、易于阅读不需要写重复的前缀对复杂的嵌套结构支持特别好。对比一下。properties格式spring.datasource.urljdbc:mysql://localhost:3306/demo?useUnicodetruecharacterEncodingutf8 spring.datasource.usernameroot spring.datasource.password123456yaml格式spring: datasource: url: jdbc:mysql://localhost:3306/demo?useUnicodetruecharacterEncodingutf8 username: root password: 123456明显yaml要清爽得多。有一点必须注意YAML对缩进非常敏感子配置必须比父配置多缩进两个空格且同一层级要对齐。新手最常犯的错就是tab键和空格混用导致启动时yaml解析报错。5.2 多环境配置与profile切换真实项目里开发、测试、生产环境的数据库连接、日志级别、缓存地址通常都不一样。你不可能每次部署都去改配置文件标准做法是使用多profile配置。SpringBoot支持用application-{profile}.yml来区分环境。常见的三个文件application.yml主配置放公共配置application-dev.yml开发环境application-prod.yml生产环境主配置文件里通过spring.profiles.active来激活某套环境spring: profiles: active: dev切换环境只需要改active的值就行比如部署到生产时用jar包启动参数指定java -jar demo.jar --spring.profiles.activeprod命令行参数的优先级高于配置文件所以部署时无需改任何文件直接在启动命令里指定环境即可。这个习惯请务必从学习阶段就养成它能避免很多生产事故。5.3 通过ConfigurationProperties实现配置绑定当配置项多了之后用Value一个个注入是很累的。SpringBoot提供了ConfigurationProperties注解可以把一组配置直接绑定到一个JavaBean上。这也是很多公司项目里常见的做法。先在application.yml里定义一组自定义配置app: name: 用户服务 version: 1.0.0 authors: - 张三 - 李四再写一个配置类来对应Component ConfigurationProperties(prefix app) public class AppConfig { private String name; private String version; private ListString authors; // getter和setter方法不能省略 }这里有个关键点ConfigurationProperties的类里面getter和setter方法必须写全。因为SpringBoot是通过setter方法完成属性赋值的少一个setter就会导致该属性为null。另外如果在IDEA里使用SpringBoot插件配置绑定后写配置文件时会有代码提示非常方便。5.4 配置优先级总结SpringBoot的配置来源非常多优先级从高到低大致是命令行参数Java系统属性System.getProperties()操作系统环境变量application-{profile}.yml配置application.yml配置项目代码中的PropertySource注解指定配置记住前四个基本够用。实际开发中最常见的场景是开发本地用application-dev.yml里的配置生产环境通过命令行参数或者环境变量覆盖关键配置。既不改文件又能灵活切换。6. 整合MyBatis从零实现增删改查6.1 依赖引入与数据源配置SpringBoot项目里操作数据库最主流的方案是MyBatis。整合起来非常快先引入依赖在pom.xml里加上dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.2/version /dependency dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency注意第一行的groupId是org.mybatis.spring.boot而不是org.mybatis这是一个独立的starter专门为SpringBoot适配的。如果写错了要么下载不到要么注入不了Mapper。接下来配置数据源。在application.yml里配置spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/demo?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 123456 mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.demo.entity configuration: map-underscore-to-camel-case: true说几个容易踩坑的细节。url里的serverTimezoneAsia/Shanghai是必须的因为新版MySQL驱动要求显式指定时区否则会报时区相关的异常。password用双引号包起来是为了防止yaml解析时把123456这种数字字符串当成数字类型。map-underscore-to-camel-case设置为true能自动把数据库的user_name字段映射为Java的userName属性省去大量写resultMap的时间。6.2 编写Mapper与XML映射文件有了数据源配置接下来是三层结构Controller - Service - Mapper。Mapper是一个接口负责定义数据库操作方法。用一个最简单的用户表来做示例Mapper public interface UserMapper { User findById(Long id); ListUser findAll(); int insert(User user); int update(User user); int deleteById(Long id); }对应的XML映射文件写在resources/mapper/UserMapper.xml里?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.demo.mapper.UserMapper select idfindById resultTypecom.example.demo.entity.User select * from user where id #{id} /select insert idinsert parameterTypecom.example.demo.entity.User useGeneratedKeystrue keyPropertyid insert into user(name, age) values(#{name}, #{age}) /insert /mapper这里有个常见的坑XML文件的namespace必须和Mapper接口的全限定名保持一致select标签的id必须和接口方法名一致否则启动时会报BindingException。另外XML文件放在resources目录下时如果构建后target目录里找不到这个文件主项目会报Invalid bound statement (not found)。解决办法是在pom.xml的build节点里加一行资源声明resources resource directorysrc/main/resources/directory includes include**/*.xml/include /includes /resource /resources6.3 分页插件的用法分页是日常开发怎么也绕不开的需求MyBatis的分页插件PageHelper是使用最广的方案。引入依赖dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version1.4.7/version /dependency用法非常简洁在查询之前调用PageHelper.startPage即可public PageInfoUser getUserPage(int pageNum, int pageSize) { PageHelper.startPage(pageNum, pageSize); ListUser userList userMapper.findAll(); return new PageInfo(userList); }PageHelper.startPage的原理是基于MyBatis的拦截器机制它在执行后续第一条SQL之前自动将SQL改写成带LIMIT的分页查询同时执行一条COUNT查询统计总记录数。两条SQL的结果封装到PageInfo对象里就能拿到当前页数据、总记录数、总页数等信息。但这个插件有一个非常隐蔽的坑startPage方法只对紧接着的第一条查询生效。如果你在startPage和查询之间做了其他数据库操作或者查询了两次插件的工作方式会与预期不符。所以业务代码里startPage和Mapper查询必须紧挨着写中间别穿插其他逻辑。6.4 事务管理SpringBoot使用事务非常简单在Service方法上加Transactional注解即可Service public class UserServiceImpl implements UserService { Autowired private UserMapper userMapper; Override Transactional(rollbackFor Exception.class) public void transfer(Long fromId, Long toId, int amount) { userMapper.reduceBalance(fromId, amount); userMapper.addBalance(toId, amount); } }说几个事务使用的心得。第一在SpringBoot 2.x中事务默认只在遇到RuntimeException时回滚如果业务方法抛出的是受检异常checked exceptionspring会认为事务已正常提交。所以要在Transactional上加rollbackFor Exception.class让所有异常都触发回滚。第二Transactional注解加在public方法上才生效加在private方法上不生效因为Spring的事务是基于动态代理实现的private方法无法被代理。7. 实战进阶全局过滤器处理上传PDF时的XSS攻击7.1 为什么需要过滤器这个场景来自我遇到的一个真实需求。项目中有一个文件上传功能接受PDF格式文件。但是经常有人在文件名、文件描述或者表单的其他文本字段里塞入JavaScript脚本比如在文件名里写入 。如果后端不做任何处理这个脚本一旦回显到页面就会在用户的浏览器里执行带来XSS跨站脚本攻击风险。轻则弹窗骚扰重则窃取用户Cookie、钓鱼、篡改页面。XSS攻击的本质是未信任的用户输入被当作代码执行了。防御的核心思路其实很简单对输入进行过滤对输出进行转义。过滤就是把危险字符清除掉转义就是把危险字符变成无害的HTML实体。7.2 用Filter实现统一请求参数清洗SpringBoot里做统一过滤首选是Servlet的Filter过滤器。它的执行时机在请求进入Controller之前可以对每个请求的请求体做一次统一处理。这里我分享一种基于包装请求体RequestWrapper的方案。先说核心思路请求进入Filter后我们把request对象包装成自定义的XssRequestWrapper这个包装类在读取参数值时统一做XSS过滤然后把包装后的request对象传回过滤器链。后续Controller拿到的参数就都是过滤过的了。实现分三步。第一步写一个XSS过滤的工具类负责清理危险字符public class XssUtil { public static String clean(String value) { if (value null || value.isEmpty()) { return value; } // 统一转为小写 String cleaned value.toLowerCase(); // 过滤常见的XSS危险标签和关键词 cleaned cleaned.replaceAll(script[^]*, ) .replaceAll(/script, ) .replaceAll(javascript:, ) .replaceAll(onerror, ) .replaceAll(onclick, ) .replaceAll(onload, ) .replaceAll(expression\\(, ); return cleaned; } }第二步写请求包装类重写getParameter方法public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { public XssHttpServletRequestWrapper(HttpServletRequest request) { super(request); } Override public String getParameter(String name) { String value super.getParameter(name); return XssUtil.clean(value); } Override public String[] getParameterValues(String name) { String[] values super.getParameterValues(name); if (values null) { return null; } String[] cleanedValues new String[values.length]; for (int i 0; i values.length; i) { cleanedValues[i] XssUtil.clean(values[i]); } return cleanedValues; } }第三步写过滤器在所有请求进来时做包装Component Order(1) public class XssFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest (HttpServletRequest) request; XssHttpServletRequestWrapper wrapper new XssHttpServletRequestWrapper(httpRequest); chain.doFilter(wrapper, response); } }7.3 处理PDF文件时的特殊考量这里必须指出一个关键点上面这个方案处理文本参数没问题但如果请求是multipart/form-data格式文件上传的标准格式只重写getParameter方法是不生效的因为文件上传时字段和文件内容都在请求体里需要另行读取输入流并解析。处理PDF上传场景我的建议是这样的过滤器只负责清洗普通的文本表单字段比如上传人、文件描述对于PDF文件本身不要在大流量场景下做深度内容清洗因为PDF是二进制文件不是纯文本你不需要也不能简单地在InputStream上做字符串replace。正确的做法是文件上传后上传文件名和描述信息用过滤器统一清洗PDF文件本体通过后端将其重新渲染或至少做格式校验来规避脚本注入风险。纯用过滤器处理PDF文件的全部内容性能开销很大而且容易把合法PDF弄坏。还有一种情况必须注意如果你用Wrapper去重写getInputStream方法很多教程会这样做来清洗JSON请求体文件上传的场景下一定要判断ContentType。只有application/json的表单内容才适合读取输入流做文本替换multipart/form-data的文件流不应该按文本处理否则文件内容会被破坏上传的PDF直接打不开。注意XSS过滤不是万能的。过滤规则再完善也难以覆盖所有攻击变体。更稳妥的方案是输入过滤输出转义双管齐下前端展示用户内容时使用Thymeleaf模板或Vue的插值语法它们天然会做HTML转义能有效避免存储型XSS的二次触发。7.4 全局过滤器与拦截器的分工很多初学者分不清Filter和Interceptor拦截器的区别我在这里一并讲清楚。Filter是Servlet规范定义的由Web容器管理它的执行时机最早能拦截所有请求甚至包括静态资源它拿不到Controller方法的信息比如哪个方法被调用。Interceptor是SpringMVC提供的只拦截进入SpringMVC的方法调用可以拿到方法名、参数注解等信息适合做登录鉴权、权限校验。它们的执行顺序是Filter - DispatcherServlet - Interceptor - Controller。所以如果你要做的是请求参数统一清洗跨域处理日志记录用Filter要做登录状态校验接口权限控制用Interceptor。两者各管一摊不要混淆。8. 高频面试题与常见问题排查8.1 SpringBoot高频面试题整理这段时间面了不少候选人我发现SpringBoot相关的面试题翻来覆去就是那几个方向。我把高频题目整理成一张速查表每个问题都给出核心答题思路面试题核心答题要点什么是SpringBoot它的优缺点核心是自动化配置和开箱即用优点简化配置、内嵌容器、快速启动缺点依赖大量starter版本升级迁移成本高SpringBoot自动配置的原理EnableAutoConfiguration - 读取spring.factories - Conditional条件判断 - 装配BeanSpringBoot支持哪些内嵌容器Tomcat默认、Jetty、Undertow通过修改依赖排除和引入实现切换如何修改SpringBoot的默认端口application.yml里配置server.port或使用命令行参数--server.portSpringBoot中如何处理全局异常ControllerAdvice ExceptionHandler注解如何实现热部署引入spring-boot-devtools修改代码后自动重启SpringBoot的启动原理SpringApplication.run() - 准备环境 - 创建ApplicationContext - 执行自动配置 - 启动内嵌容器Spring Boot 2.x与3.x的区别3.x基于JDK17使用Jakarta EE命名空间javax改为jakarta底层Spring Framework 6其中SpringBoot的启动原理是面试官最爱深挖的一个问题。核心就是SpringApplication.run方法做了四件事推断应用类型普通Web还是响应式Web、加载所有自动配置类并做条件判断、刷新Spring容器完成Bean的创建和依赖注入、启动内嵌的Web容器。8.2 新手最常见的5个报错及解决我在带新人的过程中有几个报错属于每天都能见到级别的这里整理出来。报错一Failed to configure a DataSource: url attribute is not specified这个问题几乎每个新手都遇过。原因是classpath下有数据源相关的依赖比如mybatis starter但配置文件里没有配置数据源连接信息。要么把配置补上要么如果当前项目根本不需要数据库可以把自动配置排除掉spring: autoconfigure: exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration报错二Port 8080 was already in use端口被占用。最常见的是上一个项目进程没有结束或者是开发工具默认占了8080。解决关掉占用进程或者改端口。在application.yml里加server.port: 8081即可。报错三Consider defining a bean of type xxxMapper in your configurationMapper接口没有注入成功。排查思路一看启动类有没有加MapperScan注解或者Mapper接口上有没有加Mapper注解二看IDEA里target目录下有没有编译出对应的类三看依赖有没有引入正确。报错四Invalid bound statement (not found)Mapper接口找到了但XML映射文件没找到。检查mapper-locations路径和XML文件的namespace、id是否匹配再检查target里有没有XML文件。如果没有就是pom.xml里缺少资源声明。报错五Cannot resolve symbol xxxIDEA提示找不到类。先执行Maven的reimportFile - Maven - Reload Project让IDEA重新拉取依赖。如果还不行执行mvn clean install把本地仓库的依赖重新构建一遍。大多数情况是依赖没有下载完整导致的。8.3 版本选择建议最后给一个版本选择的实操建议。SpringBoot版本这东西不是越新越好关键看项目需求和生态兼容性。学习阶段SpringBoot 2.7.x JDK 8资料最多网上遇到的问题基本都能搜到答案MyBatis等中间件兼容性也最好。新项目技术栈较新SpringBoot 3.x JDK 17长期支持Spring生态的后续功能跟进最快。注意SpringBoot 3.x的groupId里javax.servlet已经改为jakarta.servlet很多老代码迁移过来要改包名这些细节建议提前了解。我个人的体会是学习SpringBoot最重要的不是背下所有注解而是先建立自动配置帮我省了什么、遇到问题去哪里排查的心智模型。等你理解了自动配置的原理后面学SpringCloud、学各种中间件整合项目时思路会顺畅得多。这篇内容从环境搭建、核心原理、配置管理、数据库集成到安全防护把零基础到入门的完整路径串了一遍。最后再分享一个小技巧遇到报错先看堆栈第一行别急着复制整个错误去搜索理清楚是配置问题、依赖问题还是代码问题再动手改效率会高很多。
返回列表