SpringBoot3.x入门到精通系列:1.4 项目结构与核心注解
SpringBoot 3.x 项目结构与核心注解
🏗️ 标准项目结构
SpringBoot遵循"约定优于配置"的原则,推荐使用标准的项目结构:
src/
├── main/
│ ├── java/ # Java源代码
│ │ └── com/example/demo/
│ │ ├── DemoApplication.java # 主启动类
│ │ ├── controller/ # 控制器层
│ │ ├── service/ # 业务逻辑层
│ │ ├── repository/ # 数据访问层
│ │ ├── model/ # 数据模型
│ │ ├── dto/ # 数据传输对象
│ │ ├── config/ # 配置类
│ │ └── util/ # 工具类
│ └── resources/ # 资源文件
│ ├── static/ # 静态资源
│ ├── templates/ # 模板文件
│ ├── application.properties # 配置文件
│ └── application-{profile}.properties
└── test/ # 测试代码└── java/└── com/example/demo/└── DemoApplicationTests.java
📦 分层架构详解
1. Controller层 (控制器层)
负责处理HTTP请求,调用Service层处理业务逻辑。
package com.example.demo.controller;import com.example.demo.dto.UserDTO;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "*") // 跨域配置
public class UserController {@Autowiredprivate UserService userService;@GetMappingpublic ResponseEntity<List<UserDTO>> getAllUsers() {List<UserDTO> users = userService.getAllUsers();return ResponseEntity.ok(users);}@GetMapping("/{id}")public ResponseEntity<UserDTO> getUserById(@PathVariable Long id) {UserDTO user = userService.getUserById(id);return ResponseEntity.ok(user);}@PostMappingpublic ResponseEntity<UserDTO> createUser(@RequestBody @Valid UserDTO userDTO) {UserDTO createdUser = userService.createUser(userDTO);return ResponseEntity.status(201).body(createdUser);}@PutMapping("/{id}")public ResponseEntity<UserDTO> updateUser(@PathVariable Long id, @RequestBody @Valid UserDTO userDTO) {UserDTO updatedUser = userService.updateUser(id, userDTO);return ResponseEntity.ok(updatedUser);}@DeleteMapping("/{id}")public ResponseEntity<Void> deleteUser(@PathVariable Long id) {userService.deleteUser(id);return ResponseEntity.noContent().build();}
}
2. Service层 (业务逻辑层)
处理业务逻辑,调用Repository层进行数据操作。
package com.example.demo.service;import com.example.demo.dto.UserDTO;
import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;
import java.util.stream.Collectors;@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;public List<UserDTO> getAllUsers() {return userRepository.findAll().stream().map(this::convertToDTO).collect(Collectors.toList());}public UserDTO getUserById(Long id) {User user = userRepository.findById(id).orElseThrow(() -> new RuntimeException("用户不存在: " + id));return convertToDTO(user);}public UserDTO createUser(UserDTO userDTO) {User user = convertToEntity(userDTO);User savedUser = userRepository.save(user);return convertToDTO(savedUser);}public UserDTO updateUser(Long id, UserDTO userDTO) {User existingUser = userRepository.findById(id).orElseThrow(() -> new RuntimeException("用户不存在: " + id));existingUser.setName(userDTO.getName());existingUser.setEmail(userDTO.getEmail());existingUser.setAge(userDTO.getAge());User updatedUser = userRepository.save(existingUser);return convertToDTO(updatedUser);}public void deleteUser(Long id) {if (!userRepository.existsById(id)) {throw new RuntimeException("用户不存在: " + id);}userRepository.deleteById(id);}// DTO与Entity转换方法private UserDTO convertToDTO(User user) {return new UserDTO(user.getId(), user.getName(), user.getEmail(), user.getAge());}private User convertToEntity(UserDTO userDTO) {User user = new User();user.setName(userDTO.getName());user.setEmail(userDTO.getEmail());user.setAge(userDTO.getAge());return user;}
}
3. Repository层 (数据访问层)
负责数据持久化操作。
package com.example.demo.repository;import com.example.demo.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;import java.util.List;
import java.util.Optional;@Repository
public interface UserRepository extends JpaRepository<User, Long> {// 根据邮箱查找用户Optional<User> findByEmail(String email);// 根据姓名查找用户(忽略大小写)List<User> findByNameIgnoreCase(String name);// 根据年龄范围查找用户List<User> findByAgeBetween(Integer minAge, Integer maxAge);// 自定义查询@Query("SELECT u FROM User u WHERE u.age > :age")List<User> findUsersOlderThan(@Param("age") Integer age);// 原生SQL查询@Query(value = "SELECT * FROM users WHERE email LIKE %:domain%", nativeQuery = true)List<User> findUsersByEmailDomain(@Param("domain") String domain);
}
4. Model层 (数据模型)
定义数据实体。
package com.example.demo.model;import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;import java.time.LocalDateTime;@Entity
@Table(name = "users")
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;@Column(nullable = false, length = 100)@NotBlank(message = "姓名不能为空")@Size(min = 2, max = 100, message = "姓名长度必须在2-100个字符之间")private String name;@Column(nullable = false, unique = true, length = 255)@NotBlank(message = "邮箱不能为空")@Email(message = "邮箱格式不正确")private String email;@Column@Min(value = 0, message = "年龄不能小于0")@Max(value = 150, message = "年龄不能大于150")private Integer age;@CreationTimestamp@Column(name = "created_at", updatable = false)private LocalDateTime createdAt;@UpdateTimestamp@Column(name = "updated_at")private LocalDateTime updatedAt;// 构造函数public User() {}public User(String name, String email, Integer age) {this.name = name;this.email = email;this.age = age;}// Getter和Setter方法public Long getId() { return id; }public void setId(Long id) { this.id = id; }public String getName() { return name; }public void setName(String name) { this.name = name; }public String getEmail() { return email; }public void setEmail(String email) { this.email = email; }public Integer getAge() { return age; }public void setAge(Integer age) { this.age = age; }public LocalDateTime getCreatedAt() { return createdAt; }public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }public LocalDateTime getUpdatedAt() { return updatedAt; }public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }@Overridepublic String toString() {return "User{" +"id=" + id +", name='" + name + '\'' +", email='" + email + '\'' +", age=" + age +", createdAt=" + createdAt +", updatedAt=" + updatedAt +'}';}
}
5. DTO层 (数据传输对象)
用于前后端数据传输。
package com.example.demo.dto;import jakarta.validation.constraints.*;/*** 用户数据传输对象* 使用Java 17的Record特性*/
public record UserDTO(Long id,@NotBlank(message = "姓名不能为空")@Size(min = 2, max = 100, message = "姓名长度必须在2-100个字符之间")String name,@NotBlank(message = "邮箱不能为空")@Email(message = "邮箱格式不正确")String email,@Min(value = 0, message = "年龄不能小于0")@Max(value = 150, message = "年龄不能大于150")Integer age
) {// Record自动生成构造函数、getter、equals、hashCode、toString方法/*** 创建用户DTO的静态工厂方法*/public static UserDTO of(String name, String email, Integer age) {return new UserDTO(null, name, email, age);}/*** 检查是否为成年人*/public boolean isAdult() {return age != null && age >= 18;}
}
🏷️ 核心注解详解
1. 启动类注解
@SpringBootApplication
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}
@SpringBootApplication
是一个组合注解,等价于:
@SpringBootConfiguration // 标识配置类
@EnableAutoConfiguration // 启用自动配置
@ComponentScan // 启用组件扫描
2. Web层注解
注解 | 作用 | 示例 |
---|---|---|
@RestController | REST控制器 | @RestController |
@Controller | MVC控制器 | @Controller |
@RequestMapping | 请求映射 | @RequestMapping("/api") |
@GetMapping | GET请求 | @GetMapping("/users") |
@PostMapping | POST请求 | @PostMapping("/users") |
@PutMapping | PUT请求 | @PutMapping("/users/{id}") |
@DeleteMapping | DELETE请求 | @DeleteMapping("/users/{id}") |
@PathVariable | 路径变量 | @PathVariable Long id |
@RequestParam | 请求参数 | @RequestParam String name |
@RequestBody | 请求体 | @RequestBody UserDTO user |
@ResponseBody | 响应体 | @ResponseBody |
3. 业务层注解
@Service
@Transactional
public class UserService {// 业务逻辑
}
4. 数据层注解
@Repository
public interface UserRepository extends JpaRepository<User, Long> {// 数据访问方法
}
5. 配置类注解
@Configuration
@EnableJpaRepositories
@EntityScan
public class DatabaseConfig {@Bean@Primarypublic DataSource dataSource() {// 数据源配置}
}
6. 依赖注入注解
@Component
public class UserService {@Autowiredprivate UserRepository userRepository;// 或使用构造函数注入(推荐)public UserService(UserRepository userRepository) {this.userRepository = userRepository;}
}
📋 最佳实践
1. 包命名规范
com.company.project.module.layer
例如:com.example.demo.user.controller
2. 类命名规范
- Controller:
UserController
- Service:
UserService
- Repository:
UserRepository
- Model:
User
- DTO:
UserDTO
- Config:
DatabaseConfig
3. 依赖注入推荐方式
// 推荐:构造函数注入
@Service
public class UserService {private final UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}
}// 不推荐:字段注入
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;
}
🔗 下一篇
在下一篇文章中,我们将详细介绍SpringBoot的配置文件使用方法和最佳实践。
本文关键词: 项目结构, 分层架构, 核心注解, 最佳实践, MVC模式