Files
lanecarford_back/ARCHITECTURE.md
2025-10-20 16:13:39 +08:00

708 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lane Carford 基础架构功能说明
## 🏗️ 架构概述
这是一个基于 **Spring Boot 3.1.6****Java 21** 的纯净架构模板,提供了完整的企业级应用基础设施,可以快速开发各种类型的业务应用。
## 📋 核心功能清单
### 1. 🛡️ 全局异常处理
**功能描述**: 统一处理应用程序中的各种异常,提供一致的错误响应格式
**实现类**: `GlobalExceptionHandler`
**支持的异常类型**:
- 业务异常 (`BusinessException`)
- 参数验证异常 (`MethodArgumentNotValidException`)
- 文件上传大小超限异常 (`MaxUploadSizeExceededException`)
- 数据库操作异常 (`DataAccessException`, `SQLException`)
- HTTP方法不支持异常 (`HttpRequestMethodNotSupportedException`)
- 404异常 (`NoHandlerFoundException`)
- 运行时异常 (`RuntimeException`)
- 其他通用异常
**使用示例**:
```java
// 1. 创建自定义业务异常
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ApiResponse<User> createUser(@Valid @RequestBody CreateUserRequest request) {
// 业务逻辑验证
if (userService.existsByEmail(request.getEmail())) {
throw new BusinessException("USER_EXISTS", "用户邮箱已存在");
}
User user = userService.createUser(request);
return ApiResponse.success("用户创建成功", user);
}
@GetMapping("/{id}")
public ApiResponse<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
if (user == null) {
throw new BusinessException("USER_NOT_FOUND", "用户不存在");
}
return ApiResponse.success(user);
}
}
// 2. 参数验证异常自动处理
public class CreateUserRequest {
@NotBlank(message = "用户名不能为空")
@Size(min = 2, max = 20, message = "用户名长度必须在2-20个字符之间")
private String username;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@NotNull(message = "年龄不能为空")
@Min(value = 18, message = "年龄不能小于18岁")
@Max(value = 100, message = "年龄不能大于100岁")
private Integer age;
}
// 异常响应格式示例:
{
"success": false,
"code": "VALIDATION_ERROR",
"message": "参数验证失败",
"timestamp": 1640995200000,
"path": "/api/users",
"errors": {
"username": "用户名不能为空",
"email": "邮箱格式不正确"
}
}
```
### 2. 📤 统一API响应格式
**功能描述**: 提供标准化的API响应格式确保前后端接口的一致性
**实现类**: `ApiResponse<T>`
**使用示例**:
```java
@RestController
@RequestMapping("/api/products")
public class ProductController {
// 成功响应 - 返回数据
@GetMapping("/{id}")
public ApiResponse<Product> getProduct(@PathVariable Long id) {
Product product = productService.findById(id);
return ApiResponse.success("查询成功", product);
}
// 成功响应 - 无数据
@DeleteMapping("/{id}")
public ApiResponse<Void> deleteProduct(@PathVariable Long id) {
productService.deleteById(id);
return ApiResponse.success("删除成功");
}
// 分页查询响应
@GetMapping
public ApiResponse<PageResult<Product>> getProducts(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
PageResult<Product> result = productService.findByPage(page, size);
return ApiResponse.success("查询成功", result);
}
// 错误响应
@PostMapping
public ApiResponse<Product> createProduct(@Valid @RequestBody CreateProductRequest request) {
if (productService.existsByName(request.getName())) {
return ApiResponse.businessError("PRODUCT_EXISTS", "产品名称已存在");
}
Product product = productService.create(request);
return ApiResponse.success("创建成功", product);
}
}
// 响应格式示例:
{
"success": true,
"code": "SUCCESS",
"message": "查询成功",
"data": {
"id": 1,
"name": "产品名称",
"price": 99.99
},
"timestamp": 1640995200000
}
```
### 3. 📊 分页查询支持
**功能描述**: 提供标准化的分页查询结果封装
**实现类**: `PageResult<T>`
**使用示例**:
```java
@Service
public class ProductService {
@Autowired
private ProductMapper productMapper;
public PageResult<Product> findByPage(int page, int size) {
// 使用MyBatis-Plus分页
Page<Product> pageParam = new Page<>(page, size);
Page<Product> result = productMapper.selectPage(pageParam, null);
return PageResult.<Product>builder()
.records(result.getRecords())
.total(result.getTotal())
.current(result.getCurrent())
.size(result.getSize())
.pages(result.getPages())
.build();
}
// 带条件的分页查询
public PageResult<Product> findByCondition(ProductQueryRequest request) {
Page<Product> pageParam = new Page<>(request.getPage(), request.getSize());
QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
if (StringUtils.hasText(request.getName())) {
queryWrapper.like("name", request.getName());
}
if (request.getMinPrice() != null) {
queryWrapper.ge("price", request.getMinPrice());
}
if (request.getMaxPrice() != null) {
queryWrapper.le("price", request.getMaxPrice());
}
Page<Product> result = productMapper.selectPage(pageParam, queryWrapper);
return PageResult.fromPage(result);
}
}
```
### 4. 🔄 Bean转换工具
**功能描述**: 提供对象之间的转换功能简化DTO和Entity之间的转换
**实现类**: `BeanUtil`
**使用示例**:
```java
@Service
public class UserService {
// 单个对象转换
public UserDTO convertToDTO(User user) {
return BeanUtil.convert(user, UserDTO.class);
}
// 列表转换
public List<UserDTO> convertToDTOList(List<User> users) {
return BeanUtil.convertList(users, UserDTO.class);
}
// 使用Supplier转换适用于复杂对象
public UserDetailDTO convertToDetailDTO(User user) {
return BeanUtil.convert(user, () -> {
UserDetailDTO dto = new UserDetailDTO();
// 可以在这里设置默认值
dto.setStatus("ACTIVE");
return dto;
});
}
// 忽略null值的属性复制
public void updateUser(Long id, UpdateUserRequest request) {
User existingUser = findById(id);
// 只复制非null的属性避免覆盖现有数据
BeanUtil.copyPropertiesIgnoreNull(request, existingUser);
userMapper.updateById(existingUser);
}
}
// 实体类示例
@Data
@TableName("users")
public class User extends BaseEntity {
private String username;
private String email;
private String phone;
private Integer age;
private String avatar;
}
// DTO示例
@Data
public class UserDTO {
private Long id;
private String username;
private String email;
private String phone;
private Integer age;
private String avatar;
private LocalDateTime createdTime;
}
```
### 5. 📝 日志切面
**功能描述**: 自动记录Controller方法的调用日志包括请求参数和响应结果
**实现类**: `LoggingAspect`
**使用示例**:
```java
// 无需额外配置自动对所有Controller方法生效
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@PostMapping
public ApiResponse<Order> createOrder(@RequestBody CreateOrderRequest request) {
// 自动记录日志:
// [INFO] 开始执行方法: OrderController.createOrder
// [INFO] 请求参数: {"productId":1,"quantity":2,"address":"北京市朝阳区"}
Order order = orderService.createOrder(request);
// [INFO] 方法执行完成: OrderController.createOrder, 耗时: 150ms
// [INFO] 响应结果: {"success":true,"data":{"id":1,"orderNo":"ORD20240101001"}}
return ApiResponse.success("订单创建成功", order);
}
@GetMapping("/{id}")
public ApiResponse<Order> getOrder(@PathVariable Long id) {
// 自动记录日志,包括路径参数
Order order = orderService.findById(id);
return ApiResponse.success(order);
}
}
// 日志输出示例:
// 2024-01-01 10:30:15.123 [http-nio-8080-exec-1] INFO c.a.l.aspect.LoggingAspect - 开始执行方法: OrderController.createOrder
// 2024-01-01 10:30:15.124 [http-nio-8080-exec-1] INFO c.a.l.aspect.LoggingAspect - 请求参数: [{"productId":1,"quantity":2}]
// 2024-01-01 10:30:15.275 [http-nio-8080-exec-1] INFO c.a.l.aspect.LoggingAspect - 方法执行完成: OrderController.createOrder, 耗时: 151ms
// 2024-01-01 10:30:15.276 [http-nio-8080-exec-1] INFO c.a.l.aspect.LoggingAspect - 响应结果: {"success":true,"code":"SUCCESS"}
```
### 6. ⚡ 性能监控切面
**功能描述**: 监控Controller、Service、Mapper层方法的执行性能超过阈值时发出警告
**实现类**: `PerformanceAspect`
**使用示例**:
```java
// 无需额外配置,自动监控所有层的方法性能
@Service
public class ProductService {
@Autowired
private ProductMapper productMapper;
public List<Product> findExpensiveProducts() {
// 如果这个方法执行超过5秒会自动记录警告日志
return productMapper.selectExpensiveProducts();
}
public void batchUpdateProducts(List<Product> products) {
// 批量操作可能耗时较长,会被监控
for (Product product : products) {
productMapper.updateById(product);
}
}
}
@Repository
public interface ProductMapper extends BaseMapper<Product> {
// 复杂查询可能耗时较长,会被监控
@Select("SELECT * FROM products WHERE price > 1000 ORDER BY price DESC")
List<Product> selectExpensiveProducts();
}
// 性能监控日志示例:
// 2024-01-01 10:30:15.123 [http-nio-8080-exec-1] WARN c.a.l.aspect.PerformanceAspect - [性能警告] Service层方法执行缓慢: ProductService.findExpensiveProducts, 耗时: 6543ms (阈值: 5000ms)
// 2024-01-01 10:30:15.124 [http-nio-8080-exec-1] INFO c.a.l.aspect.PerformanceAspect - [性能监控] Mapper层方法执行: ProductMapper.selectExpensiveProducts, 耗时: 234ms
// 配置性能阈值 (application.properties):
app.performance.warning.controller=5000 # Controller层警告阈值5秒
app.performance.warning.service=3000 # Service层警告阈值3秒
app.performance.warning.mapper=500 # Mapper层警告阈值500毫秒
```
### 7. 🗄️ MyBatis-Plus集成
**功能描述**: 提供强大的ORM功能包括基础CRUD、分页查询、条件构造器等
**实现类**: `BaseMapper<T>`, `BaseEntity`
**使用示例**:
```java
// 1. 实体类继承BaseEntity
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("products")
public class Product extends BaseEntity {
@TableField("name")
private String name;
@TableField("description")
private String description;
@TableField("price")
private BigDecimal price;
@TableField("category_id")
private Long categoryId;
@TableField("stock")
private Integer stock;
@TableField("status")
private Integer status; // 0-下架, 1-上架
}
// 2. Mapper接口继承BaseMapper
@Repository
public interface ProductMapper extends BaseMapper<Product> {
// 自定义查询方法
@Select("SELECT * FROM products WHERE category_id = #{categoryId} AND status = 1")
List<Product> findByCategoryAndActive(@Param("categoryId") Long categoryId);
// 复杂查询
@Select("SELECT p.*, c.name as category_name FROM products p " +
"LEFT JOIN categories c ON p.category_id = c.id " +
"WHERE p.price BETWEEN #{minPrice} AND #{maxPrice}")
List<ProductVO> findByPriceRange(@Param("minPrice") BigDecimal minPrice,
@Param("maxPrice") BigDecimal maxPrice);
}
// 3. Service层使用示例
@Service
public class ProductService {
@Autowired
private ProductMapper productMapper;
// 基础CRUD操作
public Product save(Product product) {
productMapper.insert(product); // 自动填充创建时间
return product;
}
public Product findById(Long id) {
return productMapper.selectById(id);
}
public void deleteById(Long id) {
productMapper.deleteById(id); // 逻辑删除
}
public Product update(Product product) {
productMapper.updateById(product); // 自动更新修改时间
return product;
}
// 条件查询
public List<Product> findByCondition(String name, BigDecimal minPrice, Integer status) {
QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
if (StringUtils.hasText(name)) {
queryWrapper.like("name", name);
}
if (minPrice != null) {
queryWrapper.ge("price", minPrice);
}
if (status != null) {
queryWrapper.eq("status", status);
}
return productMapper.selectList(queryWrapper);
}
// 分页查询
public PageResult<Product> findByPage(int page, int size, String keyword) {
Page<Product> pageParam = new Page<>(page, size);
QueryWrapper<Product> queryWrapper = new QueryWrapper<>();
if (StringUtils.hasText(keyword)) {
queryWrapper.and(wrapper -> wrapper
.like("name", keyword)
.or()
.like("description", keyword)
);
}
queryWrapper.eq("status", 1); // 只查询上架商品
queryWrapper.orderByDesc("created_time");
Page<Product> result = productMapper.selectPage(pageParam, queryWrapper);
return PageResult.fromPage(result);
}
// 批量操作
public void batchInsert(List<Product> products) {
// MyBatis-Plus会自动优化批量插入
for (Product product : products) {
productMapper.insert(product);
}
}
}
```
### 9. 🔒 Spring Security集成
**功能描述**: 提供基础的安全配置,支持认证和授权
**配置类**: `SecurityConfig`
**使用示例**:
```java
// 当前配置允许所有请求访问,可以根据需要自定义安全规则
@Configuration
@EnableWebSecurity
public class CustomSecurityConfig {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authz -> authz
// 公开接口
.requestMatchers("/api/auth/**", "/api/public/**").permitAll()
.requestMatchers("/actuator/**", "/api-docs/**", "/swagger-ui/**").permitAll()
// 需要认证的接口
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.requestMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
)
.formLogin(form -> form
.loginPage("/login")
.loginProcessingUrl("/api/auth/login")
.successHandler(authenticationSuccessHandler())
.failureHandler(authenticationFailureHandler())
)
.logout(logout -> logout
.logoutUrl("/api/auth/logout")
.logoutSuccessHandler(logoutSuccessHandler())
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(1)
.maxSessionsPreventsLogin(false)
);
return http.build();
}
// 认证成功处理器
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return (request, response, authentication) -> {
response.setContentType("application/json;charset=UTF-8");
ApiResponse<UserInfo> result = ApiResponse.success("登录成功", getUserInfo(authentication));
response.getWriter().write(JSON.toJSONString(result));
};
}
}
// 用户认证Controller
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@PostMapping("/login")
public ApiResponse<UserInfo> login(@RequestBody LoginRequest request, HttpServletRequest httpRequest) {
// Spring Security会自动处理认证
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserInfo userInfo = getUserInfo(authentication);
return ApiResponse.success("登录成功", userInfo);
}
@PostMapping("/logout")
public ApiResponse<Void> logout(HttpServletRequest request) {
SecurityContextHolder.clearContext();
request.getSession().invalidate();
return ApiResponse.success("退出成功");
}
@GetMapping("/current")
public ApiResponse<UserInfo> getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return ApiResponse.error("UNAUTHORIZED", "未登录");
}
UserInfo userInfo = getUserInfo(authentication);
return ApiResponse.success(userInfo);
}
}
```
### 10. 📚 Swagger API文档
**功能描述**: 自动生成API文档支持在线测试
**配置类**: `SwaggerConfig`
**使用示例**:
```java
// 在Controller中添加Swagger注解
@RestController
@RequestMapping("/api/products")
@Tag(name = "商品管理", description = "商品相关的API接口")
public class ProductController {
@Operation(summary = "创建商品", description = "创建一个新的商品")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "创建成功"),
@ApiResponse(responseCode = "400", description = "参数错误"),
@ApiResponse(responseCode = "500", description = "服务器错误")
})
@PostMapping
public ApiResponse<Product> createProduct(
@Parameter(description = "商品信息", required = true)
@Valid @RequestBody CreateProductRequest request) {
Product product = productService.createProduct(request);
return ApiResponse.success("创建成功", product);
}
@Operation(summary = "获取商品详情", description = "根据商品ID获取商品详细信息")
@GetMapping("/{id}")
public ApiResponse<Product> getProduct(
@Parameter(description = "商品ID", required = true, example = "1")
@PathVariable Long id) {
Product product = productService.findById(id);
return ApiResponse.success(product);
}
@Operation(summary = "商品列表查询", description = "分页查询商品列表,支持关键词搜索")
@GetMapping
public ApiResponse<PageResult<Product>> getProducts(
@Parameter(description = "页码", example = "1")
@RequestParam(defaultValue = "1") int page,
@Parameter(description = "每页大小", example = "10")
@RequestParam(defaultValue = "10") int size,
@Parameter(description = "搜索关键词")
@RequestParam(required = false) String keyword) {
PageResult<Product> result = productService.findByPage(page, size, keyword);
return ApiResponse.success("查询成功", result);
}
}
// DTO类添加Swagger注解
@Data
@Schema(description = "创建商品请求")
public class CreateProductRequest {
@Schema(description = "商品名称", example = "iPhone 15 Pro", required = true)
@NotBlank(message = "商品名称不能为空")
private String name;
@Schema(description = "商品描述", example = "最新款iPhone手机")
private String description;
@Schema(description = "商品价格", example = "8999.00", required = true)
@NotNull(message = "商品价格不能为空")
@DecimalMin(value = "0.01", message = "商品价格必须大于0")
private BigDecimal price;
@Schema(description = "商品分类ID", example = "1", required = true)
@NotNull(message = "商品分类不能为空")
private Long categoryId;
@Schema(description = "库存数量", example = "100", required = true)
@NotNull(message = "库存数量不能为空")
@Min(value = 0, message = "库存数量不能为负数")
private Integer stock;
}
// 访问Swagger UI: http://localhost:8080/swagger-ui.html
// 访问API文档JSON: http://localhost:8080/api-docs
```
## 🚀 快速开始
### 1. 创建实体类
```java
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("your_table")
public class YourEntity extends BaseEntity {
private String name;
private String description;
// 其他字段...
}
```
### 2. 创建Mapper接口
```java
@Repository
public interface YourEntityMapper extends BaseMapper<YourEntity> {
// 自定义查询方法
}
```
### 3. 创建Service类
```java
@Service
public class YourEntityService {
@Autowired
private YourEntityMapper mapper;
// 业务逻辑方法
}
```
### 4. 创建Controller类
```java
@RestController
@RequestMapping("/api/your-entity")
public class YourEntityController {
@Autowired
private YourEntityService service;
// API接口方法
}
```
## 📝 配置说明
### 数据库配置
```properties
# MySQL数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/your_database
spring.datasource.username=your_username
spring.datasource.password=your_password
```
### 文件上传配置
```properties
# 文件上传大小限制
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=50MB
app.upload.dir=./uploads/
```
### 性能监控配置
```properties
# 性能警告阈值(毫秒)
app.performance.warning.controller=5000
app.performance.warning.service=3000
app.performance.warning.mapper=500
```
这个架构模板提供了完整的企业级应用基础设施,您可以在此基础上快速开发各种类型的业务应用!