Spring Boot实战:从零搭建电商订单系统,告别配置地狱
Spring Boot实战:从零搭建电商订单系统,告别配置地狱
一、开篇:一个真实的业务痛点
还记得我刚入行时,接到第一个电商项目的场景:
"小王,下周要上线一个订单系统,你负责把Spring框架搭起来。"
我满怀信心地打开IDE,准备大展身手。结果...
- 配置Spring MVC:写了一堆xml,改了三天才发现
<context:component-scan>路径写错了 - 配置数据库连接池:HikariCP、Druid各种参数调来调去,启动报错看不懂
- 配置日志框架:Log4j和Logback冲突,控制台一片红
- 集成MyBatis:mapper文件放错位置,扫描不到接口
一周过去了,系统还在报错启动中。项目经理看着我欲言又止...
如果你也有过类似的经历,那么这篇文章就是为你准备的。
今天我们通过一个电商订单系统的实战案例,带你彻底搞懂Spring Boot,让你从"配置地狱"中解脱出来。
二、什么是Spring Boot?
2.1 通俗理解
想象一下,你要组装一台电脑:
传统Spring开发就像买散件组装:
- 你需要自己选CPU、主板、内存、显卡
- 自己买线缆、螺丝
- 自己研究接线图、驱动兼容性
- 组装完可能还点不亮,需要排查哪个地方没接好
Spring Boot就像买品牌整机:
- 厂家已经帮你搭配好兼容的硬件
- 开箱即用,插上电源就能启动
- 如果你想升级某个部件,也有标准接口
- 省去繁琐的组装过程,专注于使用电脑
2.2 官方定义
Spring Boot是基于Spring框架的"约定优于配置"(Convention over Configuration)的开发框架,它通过自动配置大大简化了Spring应用的初始搭建和开发过程。
核心思想:
- 自动配置:根据你引入的依赖,自动配置好Spring应用
- 起步依赖:把常用的依赖打包在一起,避免版本冲突
- 内嵌服务器:直接运行main方法就能启动,无需部署到Tomcat
- 生产就绪:提供健康检查、监控等开箱即用的功能
三、为什么要用Spring Boot?
3.1 传统Spring开发的痛点
让我们看看传统Spring开发需要做哪些配置:
<!-- web.xml 配置DispatcherServlet -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml</param-value>
</init-param>
</servlet>
<!-- spring-mvc.xml 配置 -->
<context:component-scan base-package="com.example"/>
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- applicationContext.xml 配置数据源 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/order_db"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
痛点总结:
- 配置繁琐:一个简单的web应用需要多个xml文件
- 依赖地狱:需要自己管理各个依赖的版本兼容性
- 部署麻烦:需要安装Tomcat,打包war包部署
- 学习曲线陡峭:新手不知道该配什么、怎么配
3.2 Spring Boot的优势
同样的功能,Spring Boot只需要:
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
优势总结:
- 零配置启动:一个注解搞定所有配置
- 依赖管理简单:starter自动管理版本兼容性
- 内嵌服务器:直接运行main方法
- 快速开发:专注于业务逻辑,而不是配置
四、怎么用Spring Boot?
4.1 项目初始化
方式一:使用Spring Initializr(推荐)
- 访问 https://start.spring.io/
- 选择:Maven Project、Java、Spring Boot 2.7.x
- 添加依赖:Spring Web、MyBatis Framework、MySQL Driver、Lombok
- 点击Generate下载项目
方式二:IDEA创建
New Project -> Spring Initializr -> 后续步骤同上
4.2 完整代码示例:电商订单系统
4.2.1 项目结构
order-system/
├── src/main/java/com/example/order/
│ ├── OrderApplication.java # 启动类
│ ├── controller/
│ │ └── OrderController.java # 订单控制器
│ ├── service/
│ │ ├── OrderService.java # 订单服务接口
│ │ └── impl/
│ │ └── OrderServiceImpl.java # 订单服务实现
│ ├── mapper/
│ │ └── OrderMapper.java # 订单Mapper
│ ├── entity/
│ │ └── Order.java # 订单实体
│ └── dto/
│ ├── OrderCreateRequest.java # 创建订单请求
│ └── OrderResponse.java # 订单响应
├── src/main/resources/
│ ├── application.yml # 配置文件
│ └── mapper/
│ └── OrderMapper.xml # MyBatis映射文件
└── pom.xml # Maven配置
4.2.2 pom.xml 依赖配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
</parent>
<groupId>com.example</groupId>
<artifactId>order-system</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Web开发核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis持久层框架 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 参数校验 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.2.3 application.yml 配置文件
# 服务器端口配置
server:
port: 8080
servlet:
context-path: /api
# 应用名称
spring:
application:
name: order-system
# 数据源配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/order_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
# HikariCP连接池配置
hikari:
minimum-idle: 5
maximum-pool-size: 20
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
# MyBatis配置
mybatis:
# mapper文件位置
mapper-locations: classpath:mapper/*.xml
# 实体类别名包路径
type-aliases-package: com.example.order.entity
configuration:
# 开启驼峰命名转换
map-underscore-to-camel-case: true
# 打印SQL日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4.2.4 订单实体类
package com.example.order.entity;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 订单实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Order {
/**
* 订单ID
*/
private Long id;
/**
* 订单编号
*/
private String orderNo;
/**
* 用户ID
*/
private Long userId;
/**
* 商品名称
*/
private String productName;
/**
* 商品数量
*/
private Integer quantity;
/**
* 订单金额
*/
private BigDecimal amount;
/**
* 订单状态:0-待支付,1-已支付,2-已发货,3-已完成,4-已取消
*/
private Integer status;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 更新时间
*/
private LocalDateTime updateTime;
}
4.2.5 DTO类
package com.example.order.dto;
import lombok.Data;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
/**
* 创建订单请求
*/
@Data
public class OrderCreateRequest {
/**
* 用户ID
*/
@NotNull(message = "用户ID不能为空")
private Long userId;
/**
* 商品名称
*/
@NotNull(message = "商品名称不能为空")
@Size(min = 1, max = 100, message = "商品名称长度在1-100之间")
private String productName;
/**
* 商品数量
*/
@NotNull(message = "商品数量不能为空")
@Positive(message = "商品数量必须大于0")
private Integer quantity;
/**
* 订单金额
*/
@NotNull(message = "订单金额不能为空")
@Positive(message = "订单金额必须大于0")
private BigDecimal amount;
}
package com.example.order.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 订单响应
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrderResponse {
private Long id;
private String orderNo;
private Long userId;
private String productName;
private Integer quantity;
private BigDecimal amount;
private Integer status;
private String statusDesc;
private LocalDateTime createTime;
}
4.2.6 Mapper接口
package com.example.order.mapper;
import com.example.order.entity.Order;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* 订单Mapper接口
*/
@Mapper
public interface OrderMapper {
/**
* 插入订单
*/
int insert(Order order);
/**
* 根据ID查询订单
*/
Order selectById(@Param("id") Long id);
/**
* 根据订单编号查询订单
*/
Order selectByOrderNo(@Param("orderNo") String orderNo);
/**
* 更新订单状态
*/
int updateStatus(@Param("id") Long id, @Param("status") Integer status);
}
4.2.7 Mapper XML文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.order.mapper.OrderMapper">
<!-- 结果映射 -->
<resultMap id="BaseResultMap" type="com.example.order.entity.Order">
<id column="id" property="id"/>
<result column="order_no" property="orderNo"/>
<result column="user_id" property="userId"/>
<result column="product_name" property="productName"/>
<result column="quantity" property="quantity"/>
<result column="amount" property="amount"/>
<result column="status" property="status"/>
<result column="create_time" property="createTime"/>
<result column="update_time" property="updateTime"/>
</resultMap>
<!-- 插入订单 -->
<insert id="insert" parameterType="com.example.order.entity.Order"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO t_order (
order_no, user_id, product_name, quantity, amount, status, create_time, update_time
) VALUES (
#{orderNo}, #{userId}, #{productName}, #{quantity}, #{amount},
#{status}, #{createTime}, #{updateTime}
)
</insert>
<!-- 根据ID查询 -->
<select id="selectById" resultMap="BaseResultMap">
SELECT * FROM t_order WHERE id = #{id}
</select>
<!-- 根据订单号查询 -->
<select id="selectByOrderNo" resultMap="BaseResultMap">
SELECT * FROM t_order WHERE order_no = #{orderNo}
</select>
<!-- 更新状态 -->
<update id="updateStatus">
UPDATE t_order SET status = #{status}, update_time = NOW()
WHERE id = #{id}
</update>
</mapper>
4.2.8 Service层
package com.example.order.service;
import com.example.order.dto.OrderCreateRequest;
import com.example.order.dto.OrderResponse;
/**
* 订单服务接口
*/
public interface OrderService {
/**
* 创建订单
*/
OrderResponse createOrder(OrderCreateRequest request);
/**
* 根据ID查询订单
*/
OrderResponse getOrderById(Long id);
/**
* 根据订单号查询订单
*/
OrderResponse getOrderByOrderNo(String orderNo);
/**
* 支付订单
*/
boolean payOrder(Long id);
/**
* 取消订单
*/
boolean cancelOrder(Long id);
}
package com.example.order.service.impl;
import com.example.order.dto.OrderCreateRequest;
import com.example.order.dto.OrderResponse;
import com.example.order.entity.Order;
import com.example.order.mapper.OrderMapper;
import com.example.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
/**
* 订单服务实现类
*/
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderMapper orderMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public OrderResponse createOrder(OrderCreateRequest request) {
log.info("开始创建订单,请求参数:{}", request);
// 1. 构建订单实体
Order order = new Order();
order.setOrderNo(generateOrderNo());
order.setUserId(request.getUserId());
order.setProductName(request.getProductName());
order.setQuantity(request.getQuantity());
order.setAmount(request.getAmount());
order.setStatus(0); // 待支付
order.setCreateTime(LocalDateTime.now());
order.setUpdateTime(LocalDateTime.now());
// 2. 保存订单
int rows = orderMapper.insert(order);
if (rows <= 0) {
throw new RuntimeException("订单创建失败");
}
log.info("订单创建成功,订单ID:{},订单号:{}", order.getId(), order.getOrderNo());
// 3. 返回响应
return buildOrderResponse(order);
}
@Override
public OrderResponse getOrderById(Long id) {
log.info("查询订单,订单ID:{}", id);
Order order = orderMapper.selectById(id);
if (order == null) {
throw new RuntimeException("订单不存在");
}
return buildOrderResponse(order);
}
@Override
public OrderResponse getOrderByOrderNo(String orderNo) {
log.info("查询订单,订单号:{}", orderNo);
Order order = orderMapper.selectByOrderNo(orderNo);
if (order == null) {
throw new RuntimeException("订单不存在");
}
return buildOrderResponse(order);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean payOrder(Long id) {
log.info("支付订单,订单ID:{}", id);
// 1. 查询订单
Order order = orderMapper.selectById(id);
if (order == null) {
throw new RuntimeException("订单不存在");
}
// 2. 校验订单状态
if (order.getStatus() != 0) {
throw new RuntimeException("订单状态异常,当前状态:" + order.getStatus());
}
// 3. 更新订单状态
int rows = orderMapper.updateStatus(id, 1); // 已支付
if (rows <= 0) {
throw new RuntimeException("支付失败");
}
log.info("订单支付成功,订单ID:{}", id);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean cancelOrder(Long id) {
log.info("取消订单,订单ID:{}", id);
// 1. 查询订单
Order order = orderMapper.selectById(id);
if (order == null) {
throw new RuntimeException("订单不存在");
}
// 2. 校验订单状态(只有待支付订单可以取消)
if (order.getStatus() != 0) {
throw new RuntimeException("订单状态异常,当前状态:" + order.getStatus());
}
// 3. 更新订单状态
int rows = orderMapper.updateStatus(id, 4); // 已取消
if (rows <= 0) {
throw new RuntimeException("取消订单失败");
}
log.info("订单取消成功,订单ID:{}", id);
return true;
}
/**
* 生成订单号
*/
private String generateOrderNo() {
// 格式:时间戳 + 随机数
String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
String random = String.valueOf((int)(Math.random() * 10000));
return "ORD" + timestamp + String.format("%04d", Integer.parseInt(random));
}
/**
* 构建订单响应
*/
private OrderResponse buildOrderResponse(Order order) {
OrderResponse response = new OrderResponse();
BeanUtils.copyProperties(order, response);
response.setStatusDesc(getStatusDesc(order.getStatus()));
return response;
}
/**
* 获取订单状态描述
*/
private String getStatusDesc(Integer status) {
switch (status) {
case 0: return "待支付";
case 1: return "已支付";
case 2: return "已发货";
case 3: return "已完成";
case 4: return "已取消";
default: return "未知";
}
}
}
4.2.9 Controller层
package com.example.order.controller;
import com.example.order.dto.OrderCreateRequest;
import com.example.order.dto.OrderResponse;
import com.example.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 订单控制器
*/
@Slf4j
@RestController
@RequestMapping("/orders")
@Validated
public class OrderController {
@Autowired
private OrderService orderService;
/**
* 创建订单
* POST /api/orders
*/
@PostMapping
public ResponseEntity<OrderResponse> createOrder(
@Validated @RequestBody OrderCreateRequest request) {
log.info("收到创建订单请求:{}", request);
OrderResponse response = orderService.createOrder(request);
return ResponseEntity.ok(response);
}
/**
* 根据ID查询订单
* GET /api/orders/{id}
*/
@GetMapping("/{id}")
public ResponseEntity<OrderResponse> getOrderById(@PathVariable Long id) {
log.info("收到查询订单请求,订单ID:{}", id);
OrderResponse response = orderService.getOrderById(id);
return ResponseEntity.ok(response);
}
/**
* 根据订单号查询订单
* GET /api/orders/orderNo/{orderNo}
*/
@GetMapping("/orderNo/{orderNo}")
public ResponseEntity<OrderResponse> getOrderByOrderNo(@PathVariable String orderNo) {
log.info("收到查询订单请求,订单号:{}", orderNo);
OrderResponse response = orderService.getOrderByOrderNo(orderNo);
return ResponseEntity.ok(response);
}
/**
* 支付订单
* PUT /api/orders/{id}/pay
*/
@PutMapping("/{id}/pay")
public ResponseEntity<Boolean> payOrder(@PathVariable Long id) {
log.info("收到支付订单请求,订单ID:{}", id);
boolean result = orderService.payOrder(id);
return ResponseEntity.ok(result);
}
/**
* 取消订单
* PUT /api/orders/{id}/cancel
*/
@PutMapping("/{id}/cancel")
public ResponseEntity<Boolean> cancelOrder(@PathVariable Long id) {
log.info("收到取消订单请求,订单ID:{}", id);
boolean result = orderService.cancelOrder(id);
return ResponseEntity.ok(result);
}
}
4.2.10 启动类
package com.example.order;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 订单系统启动类
*/
@SpringBootApplication
@MapperScan("com.example.order.mapper")
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
System.out.println("========================================");
System.out.println("订单系统启动成功!");
System.out.println("访问地址:http://localhost:8080/api");
System.out.println("========================================");
}
}
4.2.11 数据库建表SQL
-- 创建数据库
CREATE DATABASE IF NOT EXISTS order_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE order_db;
-- 创建订单表
CREATE TABLE IF NOT EXISTS t_order (
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '订单ID',
order_no VARCHAR(32) NOT NULL UNIQUE COMMENT '订单编号',
user_id BIGINT NOT NULL COMMENT '用户ID',
product_name VARCHAR(100) NOT NULL COMMENT '商品名称',
quantity INT NOT NULL COMMENT '商品数量',
amount DECIMAL(10,2) NOT NULL COMMENT '订单金额',
status TINYINT NOT NULL DEFAULT 0 COMMENT '订单状态:0-待支付,1-已支付,2-已发货,3-已完成,4-已取消',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
INDEX idx_order_no (order_no),
INDEX idx_user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
4.3 测试接口
使用Postman或curl测试接口:
# 1. 创建订单
curl -X POST http://localhost:8080/api/orders \
-H "Content-Type: application/json" \
-d '{
"userId": 1001,
"productName": "iPhone 15 Pro",
"quantity": 1,
"amount": 7999.00
}'
# 2. 查询订单
curl http://localhost:8080/api/orders/1
# 3. 支付订单
curl -X PUT http://localhost:8080/api/orders/1/pay
# 4. 取消订单
curl -X PUT http://localhost:8080/api/orders/1/cancel
五、实战踩坑总结
坑1:启动报错 Field xxx could not be found
现象:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field orderMapper in com.example.order.service.impl.OrderServiceImpl required a bean of type 'com.example.order.mapper.OrderMapper' that could not be found.
原因:
- 忘记在Mapper接口上添加
@Mapper注解 - 或者忘记在启动类上添加
@MapperScan注解
解决方案:
// 方式一:在每个Mapper接口上添加@Mapper
@Mapper
public interface OrderMapper {
// ...
}
// 方式二:在启动类上添加@MapperScan(推荐)
@SpringBootApplication
@MapperScan("com.example.order.mapper")
public class OrderApplication {
// ...
}
坑2:数据库连接失败 Communications link failure
现象:
java.sql.SQLNonTransientConnectionException: Could not create connection to database server
原因:
- MySQL服务未启动
- 数据库地址、端口、用户名、密码配置错误
- 数据库不存在
解决方案:
- 检查MySQL服务是否启动:
systemctl status mysql - 检查配置文件中的数据库连接信息
- 确认数据库已创建:
CREATE DATABASE order_db; - 测试连接:
mysql -h localhost -u root -p
坑3:MyBatis找不到Mapper XML文件
现象:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
原因:
- Mapper XML文件路径配置错误
- Maven编译时没有将XML文件复制到target目录
解决方案:
# application.yml中正确配置mapper路径
mybatis:
mapper-locations: classpath:mapper/*.xml
<!-- pom.xml中添加资源文件配置 -->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
坑4:事务不回滚
现象:
- 抛出异常后,数据库数据仍然被修改
原因:
- 默认只回滚
RuntimeException和Error - 方法修饰符不是
public - 同类内部方法调用
解决方案:
// 1. 明确指定回滚异常类型
@Transactional(rollbackFor = Exception.class)
public void someMethod() {
// ...
}
// 2. 确保方法是public
@Transactional(rollbackFor = Exception.class)
public void someMethod() {
// ...
}
// 3. 避免同类内部调用(通过注入自己调用)
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderService self; // 注入自己
public void methodA() {
self.methodB(); // 通过代理调用
}
@Transactional
public void methodB() {
// ...
}
}
坑5:端口被占用 Web server failed to start
现象:
Web server failed to start. Port 8080 was already in use.
原因:
- 8080端口已被其他程序占用
解决方案:
# 方式一:修改配置文件端口
server:
port: 8081
# 方式二:启动时指定端口
java -jar order-system.jar --server.port=8081
# 方式三:查找并关闭占用端口的程序
# Windows
netstat -ano | findstr :8080
taskkill /PID <进程ID> /F
# Linux/Mac
lsof -i :8080
kill -9 <进程ID>
六、延伸阅读
恭喜你!到这里你已经掌握了Spring Boot的基础用法。接下来你可以继续学习:
6.1 进阶方向
| 方向 | 推荐技术 | 学习路径 | |------|---------|---------| | 持久层进阶 | Spring Data JPA、多数据源、读写分离 | JPA基础 -> 复杂查询 -> 性能优化 | | 缓存技术 | Redis、Spring Cache、Caffeine | 缓存原理 -> Spring Cache集成 -> 分布式缓存 | | 消息队列 | RabbitMQ、Kafka、RocketMQ | 消息队列基础 -> Spring Boot集成 -> 异步处理 | | 微服务 | Spring Cloud、Nacos、Gateway | 微服务架构 -> 服务注册发现 -> 网关路由 | | 安全框架 | Spring Security、JWT、OAuth2 | 认证授权 -> JWT集成 -> 单点登录 | | 监控运维 | Actuator、Prometheus、Grafana | 健康检查 -> 指标收集 -> 可视化监控 |
6.2 推荐资源
- 官方文档:https://spring.io/projects/spring-boot
- Spring Boot实战(书籍)
- Baeldung:https://www.baeldung.com/spring-boot
- Spring中文社区:https://springcloud.cn/
6.3 练手项目建议
- 用户管理系统:CRUD + 权限控制
- 博客系统:文章管理 + 评论 + 标签
- 秒杀系统:高并发 + 缓存 + 消息队列
- 在线商城:商品 + 订单 + 支付
七、总结
通过本文的学习,你应该已经掌握:
✅ Spring Boot是什么:约定优于配置的开发框架 ✅ 为什么要用:简化配置、快速开发、提高效率 ✅ 怎么使用:通过电商订单系统实战,掌握完整开发流程 ✅ 常见坑点:提前避坑,少走弯路
记住: Spring Boot不是魔法,它只是帮你做了很多繁琐的配置工作。作为开发者,你仍然需要理解Spring的核心原理(IoC、AOP),这样才能在遇到问题时快速定位和解决。
最后的话:
学习技术就像爬山,一开始觉得陡峭难行,但每爬一步,看到的风景就更美。Spring Boot只是Java生态的冰山一角,保持好奇心,持续学习,你会成为一名优秀的Java开发者!
如果这篇文章对你有帮助,欢迎点赞、收藏、转发!有问题欢迎在评论区交流~
作者:技术大牛带徒弟 发布时间:2024年 适用人群:Java初学者、1-3年经验开发者
更多推荐




所有评论(0)