入門指南:從環(huán)境搭建到項目上線)
上個月一個讀者私信我說自己看了一個月的 Java 基礎(chǔ)卻連一個能跑起來的 Web 項目都搭不出來。翻遍教程要么是十幾年前的 SSH 老古董要么上來就甩一堆 XML 配置把人勸退。我跟他說直接學(xué) Spring Boot別繞彎路。Spring Boot 把 Java Web 開發(fā)里那些繁瑣的配置、復(fù)雜的依賴管理、麻煩的部署流程全部簡化掉了你只要把業(yè)務(wù)流程寫清楚剩下的框架幫你兜底。這篇指南就是給真正零基礎(chǔ)的人準(zhǔn)備的我盡量用大白話把 Spring Boot 從環(huán)境搭建到項目上線的完整路徑講透你跟著一步步做半天時間就能體驗到用 Java 做 Web 開發(fā)的爽感。1. 項目概述Spring Boot 到底解決什么問題1.1 從傳統(tǒng) SSM 到 Spring Boot省掉的到底是什么很多老教程還在講 SSMSpring SpringMVC MyBatis這套組合。不是說它不對而是它對新手太不友好了。當(dāng)年我學(xué) SSM 的時候光是 spring-config.xml、spring-mvc.xml、mybatis-config.xml 這幾個配置文件就能熬掉兩個通宵。你還沒寫一行業(yè)務(wù)代碼先要搞清楚 Bean 怎么裝配、事務(wù)管理器怎么配、Mapper 掃描路徑怎么填稍不留神就是 XML 里少寫一個 namespace啟動直接報錯。Spring Boot 的思路完全不同。它的核心理念是約定優(yōu)于配置框架把常見的配置都預(yù)設(shè)好了你只要在 pom.xml 里引入對應(yīng)的依賴它就能自動幫你完成初始化和裝配。這就好比以前你開一家餐館得自己搭灶臺、接水管、裝油煙機現(xiàn)在 Spring Boot 直接給你一個精裝鋪面你只需要決定菜單賣什么。1.2 為什么零基礎(chǔ)新手應(yīng)該直接上手 Spring Boot有人會擔(dān)心不學(xué) Spring 直接學(xué) Spring Boot會不會根基不穩(wěn)。我的看法是Spring Boot 本身就是 Spring 生態(tài)的一部分你學(xué) Spring Boot 的過程天然就在接觸 Spring 的核心概念比如依賴注入、AOP、事務(wù)管理。只是它把這些概念從手動配置變成了自動裝配你反而能更輕松地理解它們。更重要的是Spring Boot 能讓你在最短時間內(nèi)獲得正反饋。第一天就能跑起一個帶 RESTful API 的項目還能接上數(shù)據(jù)庫做增刪改查這種成就感是支撐你繼續(xù)深入學(xué)習(xí)的最大動力。我見過不少從 SSM 入門的同學(xué)挫敗感太強直接轉(zhuǎn)行了反而是先上手 Spring Boot 的后來回去補 Spring 原理時輕松很多。1.3 這篇全指南的適用范圍這篇文章適合完全沒接觸過 Spring Boot、甚至 Java 基礎(chǔ)都薄弱的讀者。我會帶你完成以下目標(biāo)搭建本地 Java 開發(fā)環(huán)境搞定 JDK、IDE、Maven通過 Spring Initializr 創(chuàng)建第一個 Spring Boot 項目理解項目結(jié)構(gòu)和啟動流程開發(fā)一個帶數(shù)據(jù)庫的完整 RESTful API 項目掌握打包、運行和多環(huán)境配置整個過程我都用最直白的語言解釋代碼該有的注釋一條不少。2. 核心思路拆解先跑通再理解最后改造2.1 三步走學(xué)習(xí)策略我給初學(xué)者的建議永遠(yuǎn)是先讓項目跑起來再回頭理解原理最后動手改造。第一步是跑通。你不用管背后發(fā)生了什么照著下面的步驟把項目啟動起來訪問到頁面就算贏。這一步的目的是建立感性認(rèn)識知道 Java Web 開發(fā)是怎么回事。第二步是理解。當(dāng)你跑通了 Hello World再回頭去看項目結(jié)構(gòu)、看啟動類、看自動配置的機制之前的疑問會自然解開。因為此時你的腦子已經(jīng)有一個運行的系統(tǒng)在支撐想象而不是面對一堆靜態(tài)文件空想。第三步是改造。把 Hello World 改成自己的業(yè)務(wù)場景比如做一個待辦事項管理、一個學(xué)生信息查詢、一個博客文章發(fā)布。改造的過程中你會遇到真實的問題解決這些問題的過程才是真正的學(xué)習(xí)。2.2 為什么用 Maven 而不是 Gradle國內(nèi)絕大多數(shù)企業(yè)級 Java 項目用的是 MavenSpring Boot 官方文檔也默認(rèn)以 Maven 為主。雖然 Gradle 在構(gòu)建速度上更快但 Maven 的約定優(yōu)于配置風(fēng)格更適合新手它的 pom.xml 結(jié)構(gòu)清晰依賴聲明簡單直接。另一個現(xiàn)實因素是排查問題方便。你搜Maven 依賴下載失敗能搜到的解決方案比 Gradle 多一個數(shù)量級。遇到問題能快速找到答案對新手來說比性能更重要。2.3 為什么先選 H2 數(shù)據(jù)庫而不是 MySQL很多教程上來就讓新手裝 MySQL還得配賬號密碼、建庫建表這一套流程對小白來說又是一道坎。H2 是一個內(nèi)嵌的內(nèi)存數(shù)據(jù)庫你只要引入依賴不需要安裝任何東西項目啟動時自動創(chuàng)建數(shù)據(jù)庫項目停止時數(shù)據(jù)自動釋放。對于學(xué)習(xí)階段來說H2 能讓你專注在 Spring Boot 本身的業(yè)務(wù)邏輯上而不是在數(shù)據(jù)庫配置上消耗精力。等你的項目成長起來再切換成 MySQL 也只是改一行配置的事。Spring Data JPA 屏蔽了底層數(shù)據(jù)庫的差異這就是分層設(shè)計帶來的好處。3. 環(huán)境準(zhǔn)備JDK、IDE、Maven一個都不能缺3.1 JDK 版本怎么選Spring Boot 3.x 要求 JDK 17 起步Spring Boot 2.x 支持 JDK 8 到 21。我的建議是直接上 JDK 17因為 Spring Boot 3.x 已經(jīng)發(fā)布多年社區(qū)生態(tài)和排錯資料都很成熟而且 JDK 17 是長期支持版本技能棧更貼合當(dāng)下主流。下載 JDK 后一定要配置環(huán)境變量。Windows 下新建 JAVA_HOME 變量指向 JDK 安裝目錄然后把 %JAVA_HOME%\bin 追加到 Path 中。配置完成后打開命令行窗口輸入以下命令驗證java -version如果能看到版本信息說明 JDK 配置成功。這一步卡住的人不少常見癥狀是命令找不到幾乎都是環(huán)境變量沒配上或者配錯路徑。3.2 IDE 選擇IntelliJ IDEA 社區(qū)版就夠了現(xiàn)在開發(fā) Java 基本默認(rèn) IntelliJ IDEA。社區(qū)版免費功能上對于學(xué)習(xí) Spring Boot 完全夠用。不要覺得社區(qū)版低人一等你日常用到的編碼輔助、Git 集成、Maven 面板它都有跟專業(yè)版的核心差異主要在 Spring 專屬的圖形化支持上比如依賴提示之類的便利功能對學(xué)習(xí)階段可以不用那么講究。打開 IDEA 后把 Maven 的配置指到你本地的 settings.xml。這一步是在設(shè)置里搜索 Maven修改 User settings file 為實際路徑。如果你沒改過IDEA 會用內(nèi)置的 Maven也可以繼續(xù)用。3.3 Maven 鏡像加速阿里云鏡像配置國內(nèi)直接訪問 Maven 中央倉庫那個速度下載一個 Spring Boot 相關(guān)依賴能等五分鐘。建議修改 Maven 的 settings.xml 文件把鏡像切換成國內(nèi)源。在 .m2 目錄下找到 settings.xml沒有就新建一個加入以下內(nèi)容mirrors mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共倉庫/name urlhttps://maven.aliyun.com/repository/public/url /mirror /mirrors配置完成后重啟 IDE再創(chuàng)建項目時依賴下載速度會有質(zhì)的提升。這個細(xì)節(jié)能讓你少等好幾個小時。4. 創(chuàng)建第一個 Spring Boot 項目4.1 用 Spring Initializr 生成項目骨架打開 IDEA選擇 New Project左側(cè)選擇 Spring Initializr。這一步的關(guān)鍵是讓你理解腳手架的概念等熟悉了以后你完全可以手動寫配置創(chuàng)建項目但初期用這個工具能省掉很多手寫錯誤。關(guān)鍵配置項說明Project 選擇 MavenLanguage 選擇 JavaSpring Boot 版本選默認(rèn)的穩(wěn)定版本Group 填 com.exampleArtifact 填 demoJava 版本選擇 17依賴這一欄第一次創(chuàng)建只需要勾選 Spring Web因為我們的目標(biāo)是先把接口跑起來。之后再勾選 Spring Data JPA 和 H2 Database用于后續(xù)數(shù)據(jù)庫操作。點擊 Create 后等待依賴下載完成第一個 Spring Boot 項目就創(chuàng)建好了。4.2 項目目錄結(jié)構(gòu)逐層拆解生成的項目結(jié)構(gòu)是這樣的demo ├── pom.xml └── src ├── main │ ├── java │ │ └── com/example/demo │ │ └── DemoApplication.java │ └── resources │ └── application.properties └── test └── javapom.xml 是 Maven 的配置文件相當(dāng)于項目的清單聲明了所有依賴和插件。resources 目錄放配置文件比如 application.properties 就是 Spring Boot 的全局配置。java 目錄下放源代碼。DemoApplication.java 是啟動類帶著 SpringBootApplication 注解main 方法就是整個應(yīng)用的入口。4.3 啟動類上那三個注解的含義SpringBootApplication 是一個組合注解它等價于 Configuration、EnableAutoConfiguration、ComponentScan 三個注解加在一起。Configuration 表示當(dāng)前類可以作為配置來源EnableAutoConfiguration 是 Spring Boot 最核心的能力來源它負(fù)責(zé)開啟自動配置ComponentScan 則告訴 Spring 從哪里掃描組件。記住一點主類必須放在包的根目錄上也就是所有其他代碼的上級目錄。否則 Spring 掃描不到你寫的 Controller接口請求就全部 404。4.4 第一個 RESTful 接口三分鐘見到效果在 DemoApplication 同層的目錄下新建一個 controller 包然后創(chuàng)建 HelloController 類RestController RequestMapping(/api) public class HelloController { GetMapping(/hello) public String sayHello() { return Hello, Spring Boot!; } }運行 DemoApplication 的 main 方法控制臺會打印出 Spring Boot 啟動成功的日志同時告訴你內(nèi)嵌 Tomcat 的端口是 8080。瀏覽器里訪問 http://localhost:8080/api/hello就能看到返回的字符串。這就是內(nèi)嵌服務(wù)器帶來的便利。以前你需要單獨裝 Tomcat再把項目打成 war 包丟進(jìn)去現(xiàn)在 main 方法一跑Web 服務(wù)器直接內(nèi)嵌啟動。這也是第一個能給你帶來沖擊感的點。5. 自動配置原理Spring Boot 的魔法到底是什么5.1 自動配置的底層機制我前面用了魔法這個詞但其實它一點也不神秘。Spring Boot 啟動時會掃描依賴中所有 jar 包里的 META-INF/spring/... 配置文件里面記錄了一堆配置類的全限定名。然后 EnableAutoConfiguration 通過 SpringFactoriesLoader 機制加載這些配置類再配合 ConditionalOnClass、ConditionalOnMissingBean 等條件注解根據(jù)你當(dāng)前引入的依賴和配置動態(tài)決定要不要生效。舉個例子你引入了 spring-boot-starter-web自動配置類就會檢測到 Servlet 相關(guān)的類存在于 classpath 上于是自動創(chuàng)建一個 Spring MVC 的 DispatcherServlet 和內(nèi)嵌 Tomcat。等你引入了 spring-boot-starter-data-jpa它又會自動配置數(shù)據(jù)源、EntityManagerFactory、事務(wù)管理器。這些自動配置類的加載過程你可以通過一個簡單的開關(guān)偷窺到。在 application.properties 里添加debugtrue啟動時控制臺會打印一份自動配置報告里面用 Positive matches 和 Negative matches 分別列出了生效和未生效的自動配置項。我建議你把這個報告好好翻一遍這是理解 Spring Boot 最直觀的窗口。5.2 Starter 依賴背后的聚合邏輯Spring Boot Starter 的本質(zhì)是一個依賴集合。spring-boot-starter-web 這個坐標(biāo)引入后會自動把 spring-web、spring-webmvc、spring-boot-starter-tomcat、jackson-databind 等十幾個依賴一起拉進(jìn)來。這樣你就不用一個個去聲明版本號也避免了多個框架版本沖突的問題。通過 Maven 面板展開 External Libraries你可以看到一個 starter 下面掛了哪些具體 jar 包。這里面有個實用技巧當(dāng)你需要排查某個依賴沖突時可以用 IDEA 的 Maven Helper 插件查看依賴樹找到?jīng)_突點直接 exclude 掉不需要的傳遞依賴。5.3 依賴注入的三種姿勢Spring Boot 里最常遇到的就是依賴注入。所謂依賴注入就是 Spring 容器把實例化的對象自動送到需要的地方你不需要自己 new。最常見的三種方式字段注入直接加注解Autowired private UserService userService;構(gòu)造器注入則是把依賴放在構(gòu)造方法參數(shù)里public UserController(UserService userService) { this.userService userService; }Setter 注入通過 setter 方法實現(xiàn)。我的建議是優(yōu)先使用構(gòu)造器注入。它有幾個現(xiàn)實好處第一依賴關(guān)系在創(chuàng)建對象時就必須確立避免運行時空指針第二依賴關(guān)系一目了然測試時往里傳 mock 對象很容易第三Spring 官方團隊也更推薦這種方式。6. 實操環(huán)節(jié)開發(fā)一個完整的待辦事項管理 API6.1 項目需求說明光跑通 Hello World 還不夠我們做一個實際能用的小系統(tǒng)待辦事項管理。功能就三個查詢所有待辦事項、新增一個待辦事項、刪除一個待辦事項。麻雀雖小但覆蓋了 Controller、Service、Repository、Entity 的完整分層結(jié)構(gòu)。我先在 pom.xml 里補上數(shù)據(jù)訪問相關(guān)的依賴dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scoperuntime/scope /dependency6.2 實體類對應(yīng)數(shù)據(jù)庫表的結(jié)構(gòu)創(chuàng)建一個 Todo 實體類Entity Table(name todos) public class Todo { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; NotBlank private String title; private boolean completed; // 省略 getter / setter }Entity 標(biāo)記這是一個 JPA 實體Spring Boot 啟動時會自動在 H2 里建表。Id 表示主鍵GeneratedValue 表示主鍵自增。如果你沒加 Table 指定表名Hibernate 默認(rèn)用類名作為表名但表名大小寫在某些數(shù)據(jù)庫上會踩坑所以我一律手動指定。6.3 數(shù)據(jù)訪問層Spring Data JPA 的魔力接著寫 Repository 接口。這是 Spring Data JPA 最有魔力的地方你只需要聲明一個接口框架會在運行時自動生成實現(xiàn)類public interface TodoRepository extends JpaRepositoryTodo, Long { }JpaRepository 已經(jīng)提供了 findAll、findById、save、deleteById 這些內(nèi)置方法你可以在 Service 里直接用。如果你要自定義查詢比如按標(biāo)題模糊搜索只需要聲明方法簽名ListTodo findAllByTitleContaining(String keyword);Spring Data JPA 會根據(jù)方法名自動解析 SQL省掉寫一大堆 XML 映射文件的功夫。6.4 業(yè)務(wù)層與控制器分層到底分在哪里Service 層寫業(yè)務(wù)邏輯。這里放一個簡單的列表查詢加新增方法Service public class TodoService { private final TodoRepository todoRepository; public TodoService(TodoRepository todoRepository) { this.todoRepository todoRepository; } public ListTodo getAllTodos() { return todoRepository.findAll(); } public Todo createTodo(Todo todo) { return todoRepository.save(todo); } public void deleteTodo(Long id) { todoRepository.deleteById(id); } }Controller 層負(fù)責(zé)接收請求和返回響應(yīng)。注意這里的返回對象就是實體類本身對于學(xué)習(xí)項目沒問題但在真實項目中規(guī)范做法是單獨建 DTO避免直接暴露實體內(nèi)所有字段。RestController RequestMapping(/api/todos) public class TodoController { private final TodoService todoService; public TodoController(TodoService todoService) { this.todoService todoService; } GetMapping public ListTodo listTodos() { return todoService.getAllTodos(); } PostMapping public Todo createTodo(RequestBody Valid Todo todo) { return todoService.createTodo(todo); } DeleteMapping(/{id}) public ResponseEntityVoid deleteTodo(PathVariable Long id) { todoService.deleteTodo(id); return ResponseEntity.noContent().build(); } }這塊代碼看著不大背后卻發(fā)生了非常多事。RequestBody 將請求體里的 JSON 轉(zhuǎn)成 Todo 對象PathVariable 從 URL 路徑里取出 idValid 觸發(fā)參數(shù)校驗RestController 自動把返回值序列化成 JSON。6.5 在 application.properties 里配置 H2為了讓 H2 更好用在 application.properties 里加幾行配置spring.datasource.urljdbc:h2:mem:testdb spring.datasource.driver-class-nameorg.h2.Driver spring.datasource.usernamesa spring.datasource.password spring.jpa.hibernate.ddl-autoupdate spring.h2.console.enabledtruespring.jpa.hibernate.ddl-autoupdate 的意思是每次啟動時如果實體類和表結(jié)構(gòu)不一致就自動更新表結(jié)構(gòu)。學(xué)習(xí)階段非常方便但生產(chǎn)環(huán)境千萬要改成 validate防止 Hibernate 給你亂改表結(jié)構(gòu)。spring.h2.console.enabledtrue 開啟了 H2 的 Web 控制臺訪問 http://localhost:8080/h2-console 可以直觀查看數(shù)據(jù)JDBC URL 填 jdbc:h2:mem:testdb 就能登錄。6.6 用 IDEA 的 HTTP Client 做接口測試啟動項目后你可以在 IDEA 里直接新建一個 .http 文件測試接口### 查詢所有待辦事項 GET http://localhost:8080/api/todos ### 新增待辦事項 POST http://localhost:8080/api/todos Content-Type: application/json { title: 學(xué)完 Spring Boot 基礎(chǔ), completed: false } ### 刪除待辦事項 DELETE http://localhost:8080/api/todos/1這個工具比 Postman 更輕量直接把請求保存成文件還能納入 Git 版本管理。測試的樂趣在于當(dāng)你 POST 一條數(shù)據(jù)后再 GET 一次發(fā)現(xiàn)數(shù)據(jù)真的存進(jìn)去了那種成就感比看一百個教學(xué)視頻都強。7. 打包、運行與多環(huán)境配置7.1 可執(zhí)行 jar 包的構(gòu)建流程開發(fā)階段一直用 main 方法啟動沒問題但真正部署的時候我們需要把項目打包成一個可執(zhí)行的 jar 包。在 IDEA 右側(cè)的 Maven 面板里找到 Lifecycle雙擊 packageMaven 就會先執(zhí)行測試再打包。如果不希望測試階段阻塞打包可以執(zhí)行 mvn package -DskipTests。打包完成后target 目錄下會生成 demo-0.0.1-SNAPSHOT.jar。在命令行進(jìn)入 target 目錄執(zhí)行java -jar demo-0.0.1-SNAPSHOT.jar應(yīng)用就啟動起來了效果跟 IDE 里跑 main 方法一模一樣。這個 jar 包非常干凈包含了你引入的所有依賴和默認(rèn)配置你只需要裝有 JDK 17 的運行環(huán)境就能跑。7.2 多環(huán)境配置dev、test、prod 的切換方法真實項目一定會有多套環(huán)境。開發(fā)環(huán)境用 H2 或本地 MySQL生產(chǎn)環(huán)境用云數(shù)據(jù)庫。Spring Boot 通過 profiles 機制處理這個問題。在 resources 目錄里新建 application-dev.properties 和 application-prod.properties然后在 application.properties 里激活spring.profiles.activedev啟動時加上 --spring.profiles.activeprod 則臨時切換到生產(chǎn)環(huán)境。這就像給同一個項目準(zhǔn)備了多套鑰匙選哪套開門完全由配置文件決定。7.3 端口配置和上下文路徑默認(rèn)端口是 8080如果被占用在配置里改server.port9090 server.servlet.context-path/api改了 context-path 之后所有接口的訪問路徑都會加前綴。如果你給前端出接口加一個統(tǒng)一的 context-path 是常規(guī)做法后續(xù)版本迭代時便于路徑統(tǒng)一管理。8. 常見問題與排查技巧實錄8.1 啟動失敗端口被占用啟動時看到 Port 8080 is already in use 這行日志說明端口被其他程序占了。解決方法是換端口或者在命令行殺掉占用進(jìn)程。Windows 下用 netstat -ano | findstr 8080 查看占用端口的 PID然后 taskkill /PID /F 殺掉進(jìn)程。8.2 Lombok 注解不生效這個幾乎每個人都遇到。代碼里寫了 Data但 getter 和 setter 全部報錯。原因多數(shù)是 IDE 里沒有安裝 Lombok 插件或者沒有開啟 annotation processing。在 IDEA 的 Settings 里搜索 annotation processing勾選 Enable annotation processing問題立刻解決。8.3 更新的 JSON 請求一直解析失敗POST 接口里加了 RequestBody結(jié)果一調(diào)接口就報 HttpMessageNotReadableException。八成是因為請求頭缺失 Content-Type: application/json。IDEA 的 HTTP Client 里記得加上請求頭Postman 里要選 Body 的類型為 raw JSON。8.4 Bean 注入失敗找不到類型的處理方式啟動時拋 UnsatisfiedDependencyException后面跟著 No qualifying bean of type。這說明 Spring 容器里找不到你聲明的依賴對象。排查順序有三步第一確認(rèn)類上是否加了 Service、Repository、Component 這類注解第二確認(rèn)類是否在主類的同級包或子包下面不在掃描范圍內(nèi)直接注入失敗第三有多個實現(xiàn)類的時候用 Primary 或 Qualifier 指定用哪一個。8.5 常見問題一句話速查表癥狀常見原因快速解決端口被占用8080被其他程序使用改端口或殺進(jìn)程中文亂碼字符編碼未統(tǒng)一數(shù)據(jù)庫連接加上 characterEncodingutf8依賴下載超時默認(rèn)源太慢配置阿里云鏡像接口404Controller不在掃描路徑檢查包目錄結(jié)構(gòu)數(shù)據(jù)沒有保存沒加 Transactional事務(wù)注解標(biāo)注到Service層方法對象屬性為nullJSON字段名不匹配確認(rèn)前端傳來的是約定后的字段名打包后無法運行缺少主屬性配置確認(rèn) pom.xml 里打了 spring-boot-maven-plugin9. 后續(xù)可以繼續(xù)深入的方向?qū)懙竭@里你已經(jīng)把 Spring Boot 的完整開發(fā)流程走通了。從環(huán)境搭建到接口開發(fā)從數(shù)據(jù)庫操作再到打包部署這條路雖然不算長但每一步都走得扎實。如果你這個項目全部跑通了我建議你下一步做三件事。第一回去把 Spring 的核心原理補一補尤其是 IoC 容器和 AOP。你有了實戰(zhàn)體驗再回頭學(xué)原理理解深度完全不一樣。第二把 H2 換成 MySQL答案就在配置文件里改幾個參數(shù)但你會經(jīng)歷驅(qū)動加載、建庫授權(quán)這些真實項目必須面對的流程。第三嘗試給這個待辦事項項目加上 Spring Security實現(xiàn)一個最簡單的登錄鑒權(quán)哪怕只是概念驗證也能讓你對 Web 開發(fā)的完整鏈路有更立體的認(rèn)識。最后分享我在帶新手時反復(fù)強調(diào)的一句話不要沉迷于看視頻一定要親手把代碼敲出來、把錯誤踩一遍、把日志讀一遍。Spring Boot 的設(shè)計已經(jīng)足夠友好剩下的只是你愿不愿意邁出第一步。