数据的全局流动浏览器发请求 │ ▼ ┌─────────────────┐ │ Controller 层 │ ← 接收请求返回响应前台接待 │ 控制层 │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Service 层 │ ← 处理业务逻辑业务主管 │ 业务层 │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ Dao / Mapper 层 │ ← 操作数据库仓库管理员 │ 数据访问层 │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ 数据库 │ │ MySQL │ └─────────────────┘ 贯穿所有层的 ┌─────────────────┐ │ Entity 实体类 │ ← 数据的载体像快递包裹一样在各层之间传递 │ 实体层 │ └─────────────────┘Entity实体层实体类就是和数据库表一一对应的 Java 对象用来在各层之间传递数据表的内容student 表 ┌────┬────────┬────┬──────────┐ │ id │ name │ age│ email │ ├────┼────────┼────┼──────────┤ │ 1 │ 张三 │ 20 │ zsqq.com│ │ 2 │ 李四 │ 22 │ lsqq.com│ └────┴────────┴────┴──────────┘实体类的内容packagecom.example.entity;publicclassStudent{privateIntegerid;// 对应表里的 id 列privateStringname;// 对应表里的 name 列privateIntegerage;// 对应表里的 age 列privateStringemail;// 对应表里的 email 列// ---- 无参构造必须有很多框架依赖它----publicStudent(){}// ---- 全参构造方便创建对象----publicStudent(Integerid,Stringname,Integerage,Stringemail){this.idid;this.namename;this.ageage;this.emailemail;}// ---- getter 和 setter必须有框架通过它们读写数据----publicIntegergetId(){returnid;}publicvoidsetId(Integerid){this.idid;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.namename;}publicIntegergetAge(){returnage;}publicvoidsetAge(Integerage){this.ageage;}publicStringgetEmail(){returnemail;}publicvoidsetEmail(Stringemail){this.emailemail;}// ---- toString 方便打印调试 ----OverridepublicStringtoString(){returnStudent{idid, namename, ageage, emailemail};}}Dao层Mapper层Dao 层专门负责对数据库做增删改查CRUD它不关心业务规则只关心怎么存取数据只负责增删改查packagecom.example.dao;importcom.example.entity.Student;importorg.apache.ibatis.annotations.*;importjava.util.List;/** * Dao 层使用 MyBatis 框架操作数据库 * * 每个方法对应一个 SQL 操作 * 这里只定义接口SQL 写在注解或 XML 文件里 */Mapper// 告诉 MyBatis这是一个数据库操作接口请帮我生成实现类publicinterfaceStudentDao{// ---- 增往数据库插入一条学生记录 ----Insert(INSERT INTO student(name, age, email) VALUES(#{name}, #{age}, #{email}))intinsert(Studentstudent);// #{name} 的意思是从传入的 Student 对象里取 name 字段的值// ---- 删根据 id 删除一条记录 ----Delete(DELETE FROM student WHERE id #{id})intdeleteById(Integerid);// ---- 改修改学生信息 ----Update(UPDATE student SET name#{name}, age#{age}, email#{email} WHERE id#{id})intupdate(Studentstudent);// ---- 查根据 id 查询一个学生 ----Select(SELECT * FROM student WHERE id #{id})StudentselectById(Integerid);// ---- 查查询所有学生 ----Select(SELECT * FROM student)ListStudentselectAll();// ---- 查根据名字模糊查询 ----Select(SELECT * FROM student WHERE name LIKE CONCAT(%, #{name}, %))ListStudentselectByName(Stringname);}Service层业务逻辑层Service 层负责实现具体的业务规则它是整个系统最核心的一层业务主管。客户说我要办银行卡主管会想先检查身份证、再查征信、再开户……这些流程和规则都在主管脑子里Service 层调用 Dao 层来操作数据库Service 层不处理 HTTP 请求也不直接写 SQL业务规则校验、判断、流程写在 Service 层举例子packagecom.example.service;importcom.example.dao.StudentDao;importcom.example.entity.Student;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importjava.util.List;Service// 告诉 Spring这是一个 Service 类请放进容器管理publicclassStudentService{Autowired// 让 Spring 自动把 StudentDao 的实例注入进来privateStudentDaostudentDao;/** * 添加学生——这是业务方法里面有业务规则 */publicintaddStudent(Studentstudent){// 业务规则1名字不能为空 if(student.getName()null||student.getName().trim().isEmpty()){thrownewRuntimeException(学生姓名不能为空);}// 业务规则2年龄必须在合理范围 if(student.getAge()1||student.getAge()150){thrownewRuntimeException(年龄必须在 1-150 之间);}// 业务规则3检查是否重名 ListStudentexistingstudentDao.selectByName(student.getName());if(!existing.isEmpty()){thrownewRuntimeException(已经存在同名学生student.getName());}// 所有规则都通过了才去操作数据库returnstudentDao.insert(student);}/** * 删除学生——有业务规则 */publicintdeleteStudent(Integerid){// 业务规则先检查学生是否存在 StudentstudentstudentDao.selectById(id);if(studentnull){thrownewRuntimeException(学生不存在idid);}returnstudentDao.deleteById(id);}/** * 修改学生信息 */publicintupdateStudent(Studentstudent){// 业务规则先检查存在性StudentexistingstudentDao.selectById(student.getId());if(existingnull){thrownewRuntimeException(学生不存在idstudent.getId());}returnstudentDao.update(student);}/** * 查询单个学生 */publicStudentgetStudent(Integerid){returnstudentDao.selectById(id);}/** * 查询所有学生 */publicListStudentgetAllStudents(){returnstudentDao.selectAll();}}Controller层用来接收请求参数调用Service层然后返回结果packagecom.example.controller;importcom.example.entity.Student;importcom.example.service.StudentService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.web.bind.annotation.*;importjava.util.List;importjava.util.HashMap;importjava.util.Map;RestController// 告诉 Spring这是一个控制器返回的数据直接写入 HTTP 响应体RequestMapping(/student)// 所有接口的 URL 都以 /student 开头publicclassStudentController{AutowiredprivateStudentServicestudentService;/** * 添加学生 * 前端发 POST 请求到 /student/add * 请求体里带 JSON 数据 * * 例如POST /student/add * Body: {name:张三, age:20, email:zsqq.com} */PostMapping(/add)publicMapString,ObjectaddStudent(RequestBodyStudentstudent){// RequestBody 把前端发来的 JSON 自动转成 Student 对象MapString,ObjectresultnewHashMap();try{introwsstudentService.addStudent(student);result.put(code,200);result.put(msg,添加成功);result.put(data,rows);}catch(Exceptione){result.put(code,500);result.put(msg,e.getMessage());// 把 Service 层抛出的错误信息返回}returnresult;}/** * 删除学生 * DELETE /student/delete/1 */DeleteMapping(/delete/{id})publicMapString,ObjectdeleteStudent(PathVariableIntegerid){// PathVariable 从 URL 路径中取 id 的值MapString,ObjectresultnewHashMap();try{studentService.deleteStudent(id);result.put(code,200);result.put(msg,删除成功);}catch(Exceptione){result.put(code,500);result.put(msg,e.getMessage());}returnresult;}/** * 查询单个学生 * GET /student/1 */GetMapping(/{id})publicMapString,ObjectgetStudent(PathVariableIntegerid){MapString,ObjectresultnewHashMap();StudentstudentstudentService.getStudent(id);if(student!null){result.put(code,200);result.put(msg,查询成功);result.put(data,student);}else{result.put(code,404);result.put(msg,学生不存在);}returnresult;}/** * 查询所有学生 * GET /student/list */GetMapping(/list)publicMapString,ObjectgetAllStudents(){MapString,ObjectresultnewHashMap();ListStudentliststudentService.getAllStudents();result.put(code,200);result.put(msg,查询成功);result.put(data,list);returnresult;}}