springboot项目制作专家

Polar Sponsor
爱发电 赞助
.NET 9.0

通用的 Spring Boot 工程 skill,不绑定特定机器或项目,换台电脑直接用。 覆盖 Controller-Service-Repository 分层架构、JPA/MyBatis 双数据方案、RESTful API 规范、 Redis 缓存、AOP 日志、全局异常处理、定时任务、事务排查、性能调优。 含环境检测脚本和零硬编码路径设计。 触发关键词:Spring Boot、Java 后端、JPA、MyBatis、Spring Cloud、微服务、 Maven、@Transactional、@Res

Spring Boot 开发专家

功能概述

Spring Boot 开发专家是一项面向实际任务的技能,主要用于通用的、可迁移的 Spring Boot 开发 skill;不绑定特定机器、特定项目——任何 Spring Boot 工程师在任何电脑上都能直接用;

核心要点

  • 可迁移性设计;
  • 本 skill 遵循零硬编码原则:;
  • 只用项目相对路径 src/main/java/... ,绝不用绝对路径;

使用与执行

默认8080,可配 server.port ,不做假设;用 spring.dat。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;

结果检查与注意事项

若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。该技能适合用于一次性任务,也可以接入自动化工作流,与其他技能或上层代理配合完成更完整的业务链路;在组合使用时,应明确每一步的输入输出关系,并避免不同步骤之间出现参数冲突。

Spring Boot 开发专家

通用的、可迁移的 Spring Boot 开发 skill。不绑定特定机器、特定项目——任何 Spring Boot 工程师在任何电脑上都能直接用。

可迁移性设计

本 skill 遵循零硬编码原则:

原则 做法
路径 只用项目相对路径 src/main/java/...,绝不用绝对路径
端口 默认8080,可配 server.port,不做假设
数据库 用 spring.datasource.url 自动检测,不硬编码连接字符串
环境检测 用 java -version、mvn -v 检测工具链
包名 用占位符 ${basePackage} 表示,根据项目实际替换

项目初始化

方式一:Spring Initializr(推荐)

# 直接 curl 下载模板项目(任何机器都能跑)
curl -s https://start.spring.io/starter.zip 
  -d type=maven-project 
  -d language=java 
  -d bootVersion=3.4.5 
  -d baseDir=my-project 
  -d groupId=com.example 
  -d artifactId=my-project 
  -d name=MyProject 
  -d description="Spring Boot project" 
  -d packageName=com.example.demo 
  -d packaging=jar 
  -d javaVersion=17 
  -d dependencies=web,data-jpa,mysql,validation,lombok,devtools 
  -o my-project.zip

方式二:Maven 手动创建



    org.springframework.boot
    spring-boot-starter-parent
    3.4.5


    
        org.springframework.boot
        spring-boot-starter-web
    

检测现有项目

# 判断是否 Spring Boot 项目
grep -rl "spring-boot-starter" pom.xml build.gradle 2>/dev/null
# 获取 Spring Boot 版本
mvn dependency:tree -Dincludes=org.springframework.boot 2>/dev/null | grep "spring-boot-starter"

标准分层架构

src/main/java/${basePackage}/
├── controller/     ← 接口层:@RestController, @RequestMapping
├── service/        ← 业务层:@Service, @Transactional
│   └── impl/       ← 实现类(接口-实现分离时)
├── repository/     ← 数据层:JpaRepository / MyBatis Mapper
├── entity/         ← 实体:@Entity, @Table
├── dto/            ← 数据传输对象(API 入参/出参)
├── vo/             ← 视图对象(返回给前端的)
├── config/         ← 配置类:@Configuration, @Bean
├── interceptor/    ← 拦截器:HandlerInterceptor
├── aspect/         ← 切面:@Aspect, @Around
├── exception/      ← 全局异常处理:@ControllerAdvice
├── util/           ← 工具类
└── constant/       ← 常量/枚举

包名约定: ${basePackage} = groupId + artifactId 的组合,如 com.example.demo

Controller 层规范

RESTful API 模板

@RestController
@RequestMapping("/api/v1/users")
@RequiredArgsConstructor
@Slf4j
public class UserController {

    private final UserService userService;

    @GetMapping
    public Result> list(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "20") int size,
            @RequestParam(required = false) String keyword) {
        return Result.ok(userService.listUsers(page, size, keyword));
    }

    @GetMapping("/{id}")
    public Result getById(@PathVariable Long id) {
        return Result.ok(userService.getById(id));
    }

    @PostMapping
    public Result create(@Valid @RequestBody UserCreateDTO dto) {
        return Result.ok(userService.create(dto));
    }

    @PutMapping("/{id}")
    public Result update(@PathVariable Long id, @Valid @RequestBody UserUpdateDTO dto) {
        userService.update(id, dto);
        return Result.ok();
    }

    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Long id) {
        userService.delete(id);
        return Result.ok();
    }
}

统一返回格式

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private int code;
    private String message;
    private T data;

    public static  Result ok() { return new Result<>(200, "success", null); }
    public static  Result ok(T data) { return new Result<>(200, "success", data); }
    public static  Result fail(int code, String msg) { return new Result<>(code, msg, null); }
}

@Data
public class PageResult {
    private long total;
    private int page;
    private int size;
    private List records;
}

全局异常处理

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handleValidation(MethodArgumentNotValidException e) {
        String msg = e.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(", "));
        return Result.fail(400, msg);
    }

    @ExceptionHandler(BusinessException.class)
    public Result handleBusiness(BusinessException e) {
        return Result.fail(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public Result handleUnknown(Exception e) {
        log.error("Unhandled exception", e);
        return Result.fail(500, "Internal server error");
    }
}

Service 层规范

public interface UserService {
    PageResult listUsers(int page, int size, String keyword);
    UserVO getById(Long id);
    Long create(UserCreateDTO dto);
    void update(Long id, UserUpdateDTO dto);
    void delete(Long id);
}

@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;

    @Override
    @Transactional(readOnly = true)
    public PageResult listUsers(int page, int size, String keyword) {
        Page userPage = userRepository.findByKeyword(keyword, PageRequest.of(page - 1, size));
        return new PageResult<>(
            userPage.getTotalElements(), page, size,
            userPage.getContent().stream().map(UserVO::from).toList()
        );
    }

    @Override
    @Transactional
    public Long create(UserCreateDTO dto) {
        if (userRepository.existsByEmail(dto.getEmail())) {
            throw new BusinessException(400, "邮箱已被注册");
        }
        User user = User.from(dto);
        return userRepository.save(user).getId();
    }

    // ... 其余方法
}

Repository 层规范

JPA

@Repository
public interface UserRepository extends JpaRepository {

    boolean existsByEmail(String email);

    @Query("SELECT u FROM User u WHERE u.name LIKE %:keyword% OR u.email LIKE %:keyword%")
    Page findByKeyword(@Param("keyword") String keyword, Pageable pageable);

    @Modifying
    @Query("UPDATE User u SET u.status = :status WHERE u.id IN :ids")
    int batchUpdateStatus(@Param("status") int status, @Param("ids") List ids);
}

MyBatis-Plus

@Mapper
public interface UserMapper extends BaseMapper {

    @Select("SELECT * FROM user WHERE email = #{email}")
    User selectByEmail(@Param("email") String email);

    List selectPageWithOrders(@Param("keyword") String keyword, Page page);
}

实体规范

@Entity
@Table(name = "user")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, length = 50)
    private String name;

    @Column(nullable = false, unique = true, length = 100)
    private String email;

    @Column(nullable = false)
    private Integer status = 1;  // 1=正常 0=禁用

    @CreatedDate
    private LocalDateTime createdAt;

    @LastModifiedDate
    private LocalDateTime updatedAt;

    public static User from(UserCreateDTO dto) {
        User user = new User();
        BeanUtils.copyProperties(dto, user);
        return user;
    }
}

配置规范

application.yml 模板

server:
  port: ${SERVER_PORT:8080}

spring:
  application:
    name: ${spring.application.name}

  datasource:
    url: ${SPRING_DATASOURCE_URL:jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai}
    username: ${SPRING_DATASOURCE_USERNAME:root}
    password: ${SPRING_DATASOURCE_PASSWORD:}
    driver-class-name: com.mysql.cj.jdbc.Driver

  jpa:
    hibernate:
      ddl-auto: validate  # none/validate/update/create/create-drop
    show-sql: false
    open-in-view: false

  redis:
    host: ${SPRING_REDIS_HOST:localhost}
    port: ${SPRING_REDIS_PORT:6379}

logging:
  level:
    root: INFO
    ${basePackage}: DEBUG

可迁移关键: 用环境变量覆盖默认值,不硬编码真实密码。

常用集成

Redis 缓存

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
        return RedisCacheManager.builder(factory)
            .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(30))
                .serializeValuesWith(RedisSerializationContext.SerializationPair
                    .fromSerializer(new GenericJackson2JsonRedisSerializer())))
            .build();
    }
}

// 使用
@Service
public class UserService {
    @Cacheable(value = "user", key = "#id")
    public UserVO getById(Long id) { ... }

    @CacheEvict(value = "user", key = "#id")
    public void update(Long id, UserUpdateDTO dto) { ... }
}

定时任务

@Configuration
@EnableScheduling
public class ScheduleConfig {}

@Component
@Slf4j
public class ScheduledTasks {

    @Scheduled(cron = "0 0 2 * * ?")  // 每天凌晨2点
    public void cleanExpiredData() {
        log.info("Cleaning expired data...");
    }

    @Scheduled(fixedRate = 60000)  // 每60秒
    public void heartbeat() {
        log.debug("Heartbeat check");
    }
}

AOP 日志

@Aspect
@Component
@Slf4j
public class LogAspect {

    @Around("execution(* ${basePackage}.controller..*(..))")
    public Object logController(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long elapsed = System.currentTimeMillis() - start;
        log.info("{}.{} -> {}ms",
            joinPoint.getSignature().getDeclaringTypeName(),
            joinPoint.getSignature().getName(), elapsed);
        return result;
    }
}

测试规范

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class UserControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserService userService;

    @Test
    void shouldReturnUserList() throws Exception {
        when(userService.listUsers(anyInt(), anyInt(), any()))
            .thenReturn(new PageResult<>(1, 1, 20, List.of()));

        mockMvc.perform(get("/api/v1/users"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200));
    }
}

常用命令

# 启动(自动检测 profile)
mvn spring-boot:run

# 指定 profile
mvn spring-boot:run -Dspring-boot.run.profiles=dev

# 打包
mvn clean package -DskipTests

# 运行 jar
java -jar target/*.jar --server.port=8081

# 测试
mvn test
mvn test -Dtest=UserControllerTest

# 查看依赖树(定位版本冲突)
mvn dependency:tree | grep -E "conflict|omitted"

# 生成 OpenAPI 文档(springdoc)
# 启动后访问: http://localhost:8080/swagger-ui.html

性能调优清单

项目 配置 说明
连接池 spring.datasource.hikari.maximum-pool-size=20 默认10,生产可调20-50
JPA spring.jpa.open-in-view=false 避免长连接持有数据库连接
Tomcat 线程 server.tomcat.threads.max=200 默认200
日志 生产关闭 show-sql 避免 IO 瓶颈
缓存 热点数据加 Redis 缓存 TTL 按业务设
异步 @EnableAsync + @Async 非核心路径异步化
压缩 server.compression.enabled=true 减少带宽

常见问题排查

启动失败

# 看完整堆栈(不要只看最后几行)
mvn spring-boot:run 2>&1 | tee startup.log
grep "Caused by:" startup.log

90% 的启动失败原因:

  1. 数据库连不上 → 检查 spring.datasource.url
  2. 端口被占 → lsof -i :8080 或 netstat -ano | findstr 8080
  3. Bean 冲突 → @Primary 或 @Qualifier 解决
  4. 循环依赖 → 重构为 @Lazy 注入或用 setter 注入
  5. 版本不兼容 → mvn dependency:tree 查冲突

接口 404

  1. 检查 @RequestMapping 路径拼写
  2. 检查包扫描范围:启动类 @SpringBootApplication 是否在上层包
  3. 检查 context-path:server.servlet.context-path 配置

事务不回滚

// ❌ 同一个类内部调用不走代理
public void methodA() {
    this.methodB();  // @Transactional 不生效
}

// ✅ 注入自己或移到另一个 Service
@Service
public class OtherService {
    @Transactional
    public void methodB() { ... }
}

环境检测脚本

#!/bin/bash
# check-env.sh — 在任何机器上检测 Spring Boot 开发环境
echo "Java: $(java -version 2>&1 | head -1)"
echo "Maven: $(mvn -v 2>&1 | head -1)"
echo "Gradle: $(gradle -v 2>&1 | head -1)"
echo "Spring Boot project: $(grep -l 'spring-boot-starter' pom.xml build.gradle 2>/dev/null || echo 'NOT FOUND')"
echo "Boot version: $(grep '' pom.xml 2>/dev/null | head -1 | sed 's/.*//;s///')"
echo "Database: $(grep 'spring.datasource.url' src/main/resources/application*.yml 2>/dev/null | head -1)"
echo "Port: $(grep 'server.port' src/main/resources/application*.yml 2>/dev/null | head -1)"

注意事项

  1. 本 skill 不绑定任何特定项目——所有路径都是相对路径
  2. ${basePackage} 是占位符,使用时替换为项目实际根包名
  3. 所有配置示例都通过了环境变量覆盖机制,不会泄露真实密码
  4. 代码示例遵循 Spring Boot 3.x + Java 17 标准
  5. 兼容 Maven 和 Gradle 两种构建工具

相关专题

更多
Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性
Java Spring Boot 4更新教程_Java Spring Boot 4有哪些新特性

Spring Boot 是一个基于 Spring 框架的 Java 开发框架,它通过 约定优于配置的原则,大幅简化了 Spring 应用的初始搭建、配置和开发过程,让开发者可以快速构建独立的、生产级别的 Spring 应用,无需繁琐的样板配置,通常集成嵌入式服务器(如 Tomcat),提供“开箱即用”的体验,是构建微服务和 Web 应用的流行工具。

2025.12.22

356

5

j2ee和springboot的区别是什么
j2ee和springboot的区别是什么

j2ee和spring boot的主要区别在于架构和易用性。j2ee采用复杂的分层架构,而spring boot采用单体架构并集成所有组件,简化了部署。spring boot以其开箱即用性和丰富的自动化功能而著称,而j2ee的配置过程更为繁琐。想了解更多j2ee的相关内容,可以阅读本专题下面的文章。

2024.04.16

4003

7

SpringBoot项目搭建步骤
SpringBoot项目搭建步骤

SpringBoot项目搭建的步骤:1、确保JDK、Maven、IDE等工具已安装;2、使用Maven创建一个新的Spring Boot项目;3、在Spring Boot项目中,可以通过添加依赖来引入所需的功能模块;4、编写一个Spring Boot应用程序;5、运行Spring Boot项目;6、在完成开发和测试后,将Spring Boot项目部署到生产环境。详细内容,请阅读本专题的下面文章。

2023.09.08

1663

5

Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

2026.11.12

0

15

Go-Zero安装与goctl环境配置教程
Go-Zero安装与goctl环境配置教程

本专题围绕Go-Zero的安装与工具链配置展开,讲清Go版本要求、goctl安装方式、代理镜像、protoc依赖与环境变量设置,说明多版本共存、升级回退与CI流水线安装的做法,并整理安装阶段的常见报错与验证步骤。

2026.11.12

0

15

Go-Zero零基础入门教程
Go-Zero零基础入门教程

本专题整理Go-Zero的入门知识,从框架定位、环境准备到跑通第一个API服务,讲清目录分层、配置加载、日志与中间件的基本用法,并对比Gin、Kratos的差异,帮助Go开发者建立整体认知,判断它是否适合当前项目。

2026.11.12

0

15

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

2026.11.06

0

12

Postman请求头Headers怎么设置
Postman请求头Headers怎么设置

围绕Postman HTTP请求头配置展开,讲解Headers选项的具体使用方式,包括Key和Value参数填写、请求头信息添加、常见Header字段设置及请求头修改方法,帮助用户解决接口调试过程中遇到的请求头配置问题。

2026.11.06

0

13

Postman接口请求发送教程
Postman接口请求发送教程

详细介绍Postman接口请求的创建与发送方法,涵盖GET和POST请求、URL配置、请求参数、Headers请求头、Body请求体设置以及响应结果查看,帮助用户掌握Postman接口请求的完整操作流程。

2026.11.06

0

10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Redis6入门到精通超详细教程
Redis6入门到精通超详细教程

共47课时 | 7.5万人学习