一,整体结构(全景图)my-project/├── src/main/java/│ └── com/example/demo/ # 主代码包│ ├── DemoApplication.java # Spring Boot启动类 ★核心│ ││ ├── controller/ # 控制器层Web层│ │ ├── StudentController.java # 处理HTTP请求│ │ └── CourseController.java│ ││ ├── service/ # 服务层业务逻辑层│ │ ├── StudentService.java # 业务接口定义契约│ │ ├── StudentServiceImpl.java # 业务实现具体逻辑│ │ ├── CourseService.java│ │ └── CourseServiceImpl.java│ ││ ├── repository/ # 数据访问层DAO层│ │ ├── StudentRepository.java # 数据库操作接口│ │ ├── CourseRepository.java│ │ └── entity/ # 实体类包│ │ ├── Student.java # 数据库表对应类│ │ └── Course.java│ ││ ├── dto/ # 数据传输对象层│ │ ├── StudentDTO.java # 前端传数据用的对象│ │ └── CourseDTO.java│ ││ ├── config/ # 配置类│ │ ├── SecurityConfig.java # 安全配置│ │ └── WebConfig.java # Web配置│ ││ └── exception/ # 异常处理│ ├── GlobalExceptionHandler.java│ └── StudentNotFoundException.java│├── src/main/resources/ # 资源文件│ ├── application.properties # 配置文件 ★重要│ ├── application-dev.properties # 开发环境配置│ ├── application-prod.properties # 生产环境配置│ ├── static/ # 静态资源CSS/JS/图片│ │ ├── css/│ │ ├── js/│ │ └── images/│ └── templates/ # 模板文件HTML页面│ └── index.html│├── src/test/java/ # 测试代码│ └── com/example/demo/│ ├── controller/│ │ └── StudentControllerTest.java│ ├── service/│ │ └── StudentServiceTest.java│ └── repository/│ └── StudentRepositoryTest.java│├── pom.xml # Maven配置文件Java项目配置└── target/ # 编译输出目录自动生成二,逐层详细讲解第1层:启动类(项目入口)// src/main/java/com/example/demo/DemoApplication.javapackagecom.example.demo;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication// 核心注解启用Spring Boot自动配置publicclassDemoApplication{publicstaticvoidmain(String[]args){// 启动Spring Boot应用SpringApplication.run(DemoApplication.class,args);}}作用程序的入口点就像main方法的Java程序SpringBootApplication告诉Spring从这里开始扫描第2层:实体类(Entity) -数据库表映射// src/main/java/com/example/demo/repository/entity/Student.javapackagecom.example.demo.repository.entity;importjavax.persistence.*;importjava.time.LocalDate;Entity// 标记为数据库实体Table(namestudents)// 对应数据库表名publicclassStudent{Id// 主键GeneratedValue(strategyGenerationType.IDENTITY)// 自增privateLongid;Column(namestudent_name,nullablefalse,length50)// 列定义privateStringname;Column(nullablefalse)privateIntegerage;Column(uniquetrue)// 唯一约束privateStringemail;privateLocalDatebirthday;// 必须有无参构造方法publicStudent(){}// 有参构造方法publicStudent(Stringname,Integerage,Stringemail){this.namename;this.ageage;this.emailemail;}// Getter和Setter方法省略实际用Lombok的DatapublicLonggetId(){returnid;}publicvoidsetId(Longid){this.idid;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.namename;}// ... 其他getter/setter}作用对应数据库的一张表每个属性对应表的一个字段是数据在Java中的表现形式第3层数据访问层Repository - 操作数据库// src/main/java/com/example/demo/repository/StudentRepository.javapackagecom.example.demo.repository;importcom.example.demo.repository.entity.Student;importorg.springframework.data.jpa.repository.JpaRepository;importorg.springframework.stereotype.Repository;importjava.util.List;importjava.util.Optional;Repository// 标记为数据访问组件publicinterfaceStudentRepositoryextendsJpaRepositoryStudent,Long{// 继承JpaRepository就自动有了CRUD方法// 不用写实现Spring Data JPA会自动生成// 自定义查询方法按命名规则ListStudentfindByName(Stringname);// 自动生成SELECT * FROM students WHERE name ?ListStudentfindByAgeGreaterThan(Integerage);// 条件查询OptionalStudentfindByEmail(Stringemail);// 返回单个// 复杂查询用Query注解Query(SELECT s FROM Student s WHERE s.name LIKE %:keyword% OR s.email LIKE %:keyword%)ListStudentsearch(Param(keyword)Stringkeyword);}为什么是接口Spring Data JPA会根据方法名自动生成实现我们只定义要做什么不写怎么做实现了解耦便于测试第4层服务层Service - 业务逻辑// 1. 先定义接口契约// src/main/java/com/example/demo/service/StudentService.javapackagecom.example.demo.service;importcom.example.demo.repository.entity.Student;importjava.util.List;publicinterfaceStudentService{// 接口定义要做什么StudentgetStudentById(Longid);ListStudentgetAllStudents();StudentcreateStudent(Studentstudent);StudentupdateStudent(Longid,Studentstudent);voiddeleteStudent(Longid);ListStudentsearchStudents(Stringkeyword);}// 2. 再写实现类具体实现// src/main/java/com/example/demo/service/StudentServiceImpl.javapackagecom.example.demo.service;importcom.example.demo.repository.StudentRepository;importcom.example.demo.repository.entity.Student;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.util.List;Service// 标记为业务组件Transactional// 方法在事务中执行publicclassStudentServiceImplimplementsStudentService{// 实现接口privatefinalStudentRepositorystudentRepository;// 构造器注入推荐AutowiredpublicStudentServiceImpl(StudentRepositorystudentRepository){this.studentRepositorystudentRepository;}OverridepublicStudentgetStudentById(Longid){// 业务逻辑如果找不到抛异常returnstudentRepository.findById(id).orElseThrow(()-newStudentNotFoundException(学生不存在ID: id));}OverridepublicListStudentgetAllStudents(){returnstudentRepository.findAll();// 调用Repository}OverridepublicStudentcreateStudent(Studentstudent){// 业务验证if(student.getEmail()null||!student.getEmail().contains()){thrownewIllegalArgumentException(邮箱格式错误);}returnstudentRepository.save(student);// 保存到数据库}// ... 其他方法实现}为什么分接口和实现接口定义契约告诉外界我有什么功能实现具体怎么做这些功能好处可以随时换实现比如从数据库换成内存实现第5层控制器层Controller - 接收HTTP请求// src/main/java/com/example/demo/controller/StudentController.javapackagecom.example.demo.controller;importcom.example.demo.repository.entity.Student;importcom.example.demo.service.StudentService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.HttpStatus;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.*;importjava.util.List;RestController// REST API控制器RequestMapping(/api/students)// 基础路径publicclassStudentController{privatefinalStudentServicestudentService;AutowiredpublicStudentController(StudentServicestudentService){this.studentServicestudentService;}// GET /api/studentsGetMappingpublicResponseEntityListStudentgetAllStudents(){ListStudentstudentsstudentService.getAllStudents();returnResponseEntity.ok(students);// 返回200 OK}// GET /api/students/{id}GetMapping(/{id})publicResponseEntityStudentgetStudentById(PathVariableLongid){StudentstudentstudentService.getStudentById(id);returnResponseEntity.ok(student);}// POST /api/studentsPostMappingpublicResponseEntityStudentcreateStudent(RequestBodyStudentstudent){StudentcreatedstudentService.createStudent(student);returnResponseEntity.status(HttpStatus.CREATED).body(created);// 返回201 Created}// PUT /api/students/{id}PutMapping(/{id})publicResponseEntityStudentupdateStudent(PathVariableLongid,RequestBodyStudentstudent){StudentupdatedstudentService.updateStudent(id,student);returnResponseEntity.ok(updated);}// DELETE /api/students/{id}DeleteMapping(/{id})publicResponseEntityVoiddeleteStudent(PathVariableLongid){studentService.deleteStudent(id);returnResponseEntity.noContent().build();// 返回204 No Content}}作用处理HTTP请求调用Service层返回HTTP响应是前后端的桥梁第6层数据传输对象DTO - 前后端数据交换// src/main/java/com/example/demo/dto/StudentDTO.javapackagecom.example.demo.dto;importjavax.validation.constraints.Email;importjavax.validation.constraints.NotBlank;importjavax.validation.constraints.NotNull;importjavax.validation.constraints.Size;// DTO专门用于接收和返回数据不和数据库直接对应publicclassStudentDTO{privateLongid;// 可能不需要前端传NotBlank(message姓名不能为空)Size(min2,max20,message姓名长度2-20)privateStringname;NotNull(message年龄不能为空)privateIntegerage;NotBlank(message邮箱不能为空)Email(message邮箱格式不正确)privateStringemail;// 构造方法publicStudentDTO(){}publicStudentDTO(Stringname,Integerage,Stringemail){this.namename;this.ageage;this.emailemail;}// Getter和Setter// ... 省略}为什么需要DTO安全性不暴露数据库全部字段灵活性可以和Entity结构不一样验证可以加验证注解简化只传输需要的字段Controller使用DTO:PostMappingpublicResponseEntityStudentcreateStudent(ValidRequestBodyStudentDTOstudentDTO){// 1. 接收DTO// 2. 将DTO转为Entity// 3. 调用Service保存// 4. 返回结果}第7层配置类Config - 项目配置// src/main/java/com/example/demo/config/WebConfig.javapackagecom.example.demo.config;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;Configuration// 标记为配置类publicclassWebConfigimplementsWebMvcConfigurer{OverridepublicvoidaddCorsMappings(CorsRegistryregistry){// 配置跨域registry.addMapping(/api/**).allowedOrigins(http://localhost:3000).allowedMethods(GET,POST,PUT,DELETE).allowCredentials(true);}}作用配置项目各种设置跨域、拦截器、过滤器等第三方组件集成第8层异常处理// 1. 自定义异常// src/main/java/com/example/demo/exception/StudentNotFoundException.javapackagecom.example.demo.exception;importorg.springframework.http.HttpStatus;importorg.springframework.web.bind.annotation.ResponseStatus;ResponseStatus(HttpStatus.NOT_FOUND)// 自动返回404publicclassStudentNotFoundExceptionextendsRuntimeException{publicStudentNotFoundException(Stringmessage){super(message);}}// 2. 全局异常处理器// src/main/java/com/example/demo/exception/GlobalExceptionHandler.javapackagecom.example.demo.exception;importorg.springframework.http.HttpStatus;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.MethodArgumentNotValidException;importorg.springframework.web.bind.annotation.ExceptionHandler;importorg.springframework.web.bind.annotation.RestControllerAdvice;importjava.util.HashMap;importjava.util.Map;RestControllerAdvice// 全局异常处理publicclassGlobalExceptionHandler{// 处理数据验证异常ExceptionHandler(MethodArgumentNotValidException.class)publicResponseEntityMapString,StringhandleValidationExceptions(MethodArgumentNotValidExceptionex){MapString,StringerrorsnewHashMap();ex.getBindingResult().getFieldErrors().forEach(error-errors.put(error.getField(),error.getDefaultMessage()));returnResponseEntity.badRequest().body(errors);}// 处理自定义异常ExceptionHandler(StudentNotFoundException.class)publicResponseEntityStringhandleStudentNotFound(StudentNotFoundExceptionex){returnResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());}// 处理其他所有异常ExceptionHandler(Exception.class)publicResponseEntityStringhandleAllExceptions(Exceptionex){returnResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(服务器内部错误: ex.getMessage());}}第9层配置文件# src/main/resources/application.properties # 数据库配置 spring.datasource.urljdbc:mysql://localhost:3306/student_db spring.datasource.usernameroot spring.datasource.password123456 spring.datasource.driver-class-namecom.mysql.cj.jdbc.Driver # JPA配置 spring.jpa.hibernate.ddl-autoupdate spring.jpa.show-sqltrue spring.jpa.properties.hibernate.dialectorg.hibernate.dialect.MySQL8Dialect # 服务器配置 server.port8080 server.servlet.context-path/api # 日志配置 logging.level.com.example.demoDEBUG logging.file.namelogs/application.log # 环境切换 # spring.profiles.activedev三、工作流程完整请求处理1. 用户访问 http://localhost:8080/api/students ↓2. Spring接收请求路由到StudentController ↓3. StudentController调用StudentService接口 ↓4. StudentServiceImpl实现类执行业务逻辑 ↓5. StudentServiceImpl调用StudentRepository接口 ↓6. Spring Data JPA自动生成SQL操作数据库 ↓7. 数据库返回数据 → Repository → Service → Controller ↓8. Controller将数据转为JSON返回给用户四、为什么这样分层设计思想分层作用好比餐厅的…Controller接收请求返回响应服务员点菜、上菜Service业务逻辑处理厨师做菜Repository数据存储采购员:买食材,存食材Entity数据结构食材本身DTO数据传递格式菜单:只展示客人需要的信息五、项目运行流程启动运行DemoApplication.java的main方法扫描Spring扫描所有Component、Service、Repository、Controller创建Bean创建这些类的实例并自动注入依赖启动Web服务器默认内嵌Tomcat启动在8080端口监听请求等待HTTP请求处理请求按上面流程处理返回响应JSON格式数据六、简单记法Controller服务员 → Service厨师 → Repository采购员 → Database仓库 ↑ ↑ ↑ HTTP请求 业务逻辑 数据库操作 ↓ ↓ ↓ 返回JSON 处理数据 存取数据