22 KiB
22 KiB
Lane Carford 基础架构功能说明
🏗️ 架构概述
这是一个基于 Spring Boot 3.1.6 和 Java 21 的纯净架构模板,提供了完整的企业级应用基础设施,可以快速开发各种类型的业务应用。
📋 核心功能清单
1. 🛡️ 全局异常处理
功能描述: 统一处理应用程序中的各种异常,提供一致的错误响应格式
实现类: GlobalExceptionHandler
支持的异常类型:
- 业务异常 (
BusinessException) - 参数验证异常 (
MethodArgumentNotValidException) - 文件上传大小超限异常 (
MaxUploadSizeExceededException) - 数据库操作异常 (
DataAccessException,SQLException) - HTTP方法不支持异常 (
HttpRequestMethodNotSupportedException) - 404异常 (
NoHandlerFoundException) - 运行时异常 (
RuntimeException) - 其他通用异常
使用示例:
// 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>
使用示例:
@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>
使用示例:
@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
使用示例:
@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
使用示例:
// 无需额外配置,自动对所有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
使用示例:
// 无需额外配置,自动监控所有层的方法性能
@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
使用示例:
// 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
使用示例:
// 当前配置允许所有请求访问,可以根据需要自定义安全规则
@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
使用示例:
// 在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. 创建实体类
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("your_table")
public class YourEntity extends BaseEntity {
private String name;
private String description;
// 其他字段...
}
2. 创建Mapper接口
@Repository
public interface YourEntityMapper extends BaseMapper<YourEntity> {
// 自定义查询方法
}
3. 创建Service类
@Service
public class YourEntityService {
@Autowired
private YourEntityMapper mapper;
// 业务逻辑方法
}
4. 创建Controller类
@RestController
@RequestMapping("/api/your-entity")
public class YourEntityController {
@Autowired
private YourEntityService service;
// API接口方法
}
📝 配置说明
数据库配置
# MySQL数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/your_database
spring.datasource.username=your_username
spring.datasource.password=your_password
文件上传配置
# 文件上传大小限制
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=50MB
app.upload.dir=./uploads/
性能监控配置
# 性能警告阈值(毫秒)
app.performance.warning.controller=5000
app.performance.warning.service=3000
app.performance.warning.mapper=500
这个架构模板提供了完整的企业级应用基础设施,您可以在此基础上快速开发各种类型的业务应用!