Views: 0
逻辑
前端操作:
管理员点击”新增”按钮 弹出空白表单,填写教师信息(用户名、姓名、性别等) 点击”保存”按钮提交
后端处理:
// 1. 检查用户名是否已存在(防重复) Teacher dbTeacher = teacherMapper.selectByUsername(teacher.getUsername()); if(已存在){ 直接报错:”用户名已存在” }
// 2. 设置默认值: if(没填密码){ 自动设置密码为”123456″ } 强制设置角色为”TEACHER”
// 3. 保存到数据库 teacherMapper.insert(teacher);
结果反馈:
成功:提示”新增成功”,列表自动刷新显示新教师 失败:提示具体原因
关键处理点
唯一性校验:通过用户名检查教师是否已存在 默认值设置: 密码为空时自动设为”123456″ 角色固定设为”TEACHER” 异常处理:用户名存在时抛出业务异常 数据流向:Controller → Service → Mapper → DB(数据库)
创建教师信息表
CREATE TABLE `teacher` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键id',
`username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '用户名',
`password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码',
`name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '姓名',
`sex` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '性别',
`title` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '职称',
`speciality_id` int DEFAULT NULL COMMENT '专业id',
`role` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '角色',
`avatar` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='教师信息';
idea中Mac快捷键
替换
get,set方法:
找到插件GenerateAllSetter
一键调用一个对象的所有的set方法,get方法等 在方法上生成两个对象的转换
快捷键:control+enter
导包:
自动导包/修复导包问题:⌘ + Enter
优化导包(移除未使用的):⌃ + ⌥ + O
手动导包提示:⌘ + N
entity—teacher
public class Teacher extends Account {
private Integer id;
private String username;
private String password;
private String name;
private String sex;
private String title;
private Integer specialityId;
private String specialityName;
private String role;
private String avatar;
//get和set方法
@Override
public Integer getId() {
return id;
}
@Override
public void setId(Integer id) {
this.id = id;
}
@Override
public String getUsername() {
return username;
}
@Override
public void setUsername(String username) {
this.username = username;
}
@Override
public String getPassword() {
return password;
}
@Override
public void setPassword(String password) {
this.password = password;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getSpecialityId() {
return specialityId;
}
public void setSpecialityId(Integer specialityId) {
this.specialityId = specialityId;
}
@Override
public String getRole() {
return role;
}
@Override
public void setRole(String role) {
this.role = role;
}
@Override
public String getAvatar() {
return avatar;
}
@Override
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public String getSpecialityName() {
return specialityName;
}
public void setSpecialityName(String specialityName) {
this.specialityName = specialityName;
}
}
解决前端vue里面没有错警告
比如
设置(setting)里面——修改html里面
前端添加教师信息
<el-menu-item index="/teacher">
<el-icon><Avatar /></el-icon>
/*图标在 https://element-plus.org/ 里面找*/
<span>教师信息</span>
</el-menu-item>
现在前端也有教师信息菜单了,图标也可以更改
配置路由,加一个teacher信息
{ path: 'teacher', component: () => import('@/views/manager/teacher.vue')},
在manager下面新建一个Teacher.vue
vue
<template>
<div>
<!-- 新增按钮 可以参考Admin.vue里面的内容 -->
<div class="card" style="margin-bottom: 5px">
<div style="margin-bottom: 10px">
<!-- 新增教师按钮,点击触发handleAdd方法 -->
<el-button type="primary" @click="handleAdd">新增</el-button>
</div>
</div>
<!-- 教师信息弹窗对话框 -->
<el-dialog title="教师信息" width="40%" v-model="data.formVisible" :close-on-click-modal="false" destroy-on-close>
<el-form :model="data.form" label-width="100px" style="padding-right: 50px">
<!--prop v-model 里面要与后端保持一致不然接收不到 -->
<el-form-item label="账号" prop="username">
<el-input v-model="data.form.username" autocomplete="off" placeholder="请输入账号"/>
</el-form-item>
<el-form-item label="姓名" prop="name">
<el-input v-model="data.form.name" autocomplete="off" placeholder="请输入姓名"/>
</el-form-item>
<el-form-item label="性别" prop="sex">
<el-select v-model="data.form.sex" placeholder="请选择性别" style="width: 100%">
<el-option label="男" value="男"></el-option>
<el-option label="女" value="女"></el-option>
</el-select>
</el-form-item>
<el-form-item label="职称" prop="title">
<el-select v-model="data.form.title" placeholder="请选择职称" style="width: 100%">
<el-option label="讲师" value="讲师"></el-option>
<el-option label="副教授" value="副教授"></el-option>
<el-option label="教授" value="教授"></el-option>
</el-select>
</el-form-item>
</el-form>
<!-- 弹窗取消,保存 -->
<template #footer>
<span class="dialog-footer">
<el-button @click="data.formVisible = false">取 消</el-button>
<el-button type="primary" @click="save">保 存</el-button>
</span>
</template>
</el-dialog>
</div>
</template>
<script setup>
//导包
import {reactive} from "vue";
import request from "@/utils/request";
import {ElMessage} from "element-plus";
const data = reactive({
// 教师信息弹窗对话框
formVisible: false,
// 教师信息表单数据
form: {
},
})
// 新增教师按钮点击事件
const handleAdd = () => {
// 清空教师信息表单数据
data.form = {
}
// 打开教师信息弹窗对话框
data.formVisible = true
}
const save = () => {
// 调用后端接口保存教师信息
// 这里可以使用axios或者其他请求库发送请求
// 例如:axios.post('/api/teacher/add', data.form)
request.post('/teacher/add', data.form).then(res => {
if (res.code === '200') {
// 保存成功,提示用户
ElMessage.success('操作成功')
// 关闭教师信息弹窗对话框
data.formVisible = false
}else {
// 保存失败,提示用户
ElMessage.error(res.msg)
}
})
}
</script>
Controller—TeacherController
/**
* 教师模块前端操作接口入口
* 拿到数据后,调用service层的方法,返回结果
* 前端调用接口时,需要传入参数,调用service层的方法,返回结果
**/@RestController
@RequestMapping("/teacher")
public class TeacherController {
@Resource
// 注入TeacherService
private TeacherService teacherService;
/**
* 新增教师
* */
@PostMapping("/add")
public Result add(@RequestBody Teacher teacher){
teacherService.add(teacher);
return Result.success();
}
}
Service—TeacherService 核心逻辑
package com.example.service;
import cn.hutool.core.util.ObjectUtil;
import com.example.entity.Teacher;
import com.example.exception.CustomException;
import com.example.mapper.TeacherMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
/**
* 教师模块业务逻辑接口
* 要把数据往数据库里存,调用mapper层的方法,返回结果
* 业务逻辑接口调用mapper层的方法,返回结果
*/
@Service
public class TeacherService {
// 注入TeacherMapper
@Resource
private TeacherMapper teacherMapper;
/**
* 新增教师
*/
public void add(Teacher teacher) {
// ToDo 新增教师逻辑处理
// 检查教师是否已经存在,检查用户唯一性
Teacher dbTeacher = teacherMapper.selectByUsername(teacher.getUsername());
if (ObjectUtil.isNotEmpty(dbTeacher)) {
throw new CustomException("用户名已存在");
}
// 如果没有密码,就设置密码为123456
if(ObjectUtil.isEmpty(teacher.getPassword())){
teacher.setPassword("123456");
}
// 固定角色
teacher.setRole("TEACHER");
// 持久化操作
teacherMapper.insert(teacher);
}
}
mapper—TeacherMapper
package com.example.mapper;
//接口
import com.example.entity.Teacher;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface TeacherMapper {
// 新增教师
void insert(Teacher teacher);
@Select("select * from teacher where username = #{username}")
Teacher selectByUsername(String username);
}
TeacherMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.TeacherMapper">
<insert id="insert" parameterType="com.example.entity.Teacher" useGeneratedKeys="true">
insert into teacher (username, password, name,sex,title,speciality_id,role,avatar)
values (#{username}, #{password}, #{name}, #{sex}, #{title}, #{specialityId}, #{role}, #{avatar})
</insert>
</mapper>
简单逻辑在mapper可以用注解,复杂逻辑用xml namespace 对应mapper接口的全类名 1. 映射文件的位置必须和mapper接口的包结构相同 2. 映射文件的名称必须和mapper接口的名称相同 3. 映射文件的后缀名必须是.xml 1. 映射文件中的sql语句的id必须和mapper接口中的方法名相同 2. 映射文件中的sql语句的参数类型必须和mapper接口中的方法参数类型相同 3. 映射文件中的sql语句的返回值类型必须和mapper接口中的方法返回值类型相同
1. Controller(控制层)
- 职责:
- 接收客户端请求(HTTP/RPC等),解析参数(如URL、Body、Header)。
- 调用 Service 层处理业务逻辑。
- 返回响应(JSON/XML等)或视图(如HTML)。
- 特点:
- 轻量级,仅做请求转发和参数校验,不包含业务逻辑。
- 通常使用
@Controller
或@RestController
注解(Spring中)。
2. Service(业务逻辑层)
- 职责:
- 处理核心业务逻辑(如订单创建、用户权限校验)。
- 协调多个 Mapper 操作(事务管理)。
- 调用外部服务(如支付接口、消息队列)。
- 特点:
- 使用
@Service
注解,是业务逻辑的集中点。 - 可能涉及事务(
@Transactional
)。
- 使用
3. Mapper(数据访问层,或称DAO)
- 职责:
- 直接操作数据库(CRUD),执行SQL语句。
- 与数据库表一一对应(如MyBatis的
@Mapper
或JPA的Repository)。
- 特点:
- 无业务逻辑,仅做数据持久化。
- 使用
@Mapper
(MyBatis)或继承JpaRepository
(Spring Data JPA)。
三者的协作流程
- 请求入口:
- 客户端 →
Controller
(接收请求) → 调用Service
。
- 客户端 →
- 业务处理:
Service
处理逻辑 → 调用Mapper
读写数据库。
- 数据持久化:
Mapper
执行SQL → 返回数据给Service
→Service
返回结果给Controller
。
- 响应输出:
Controller
将结果封装为响应 → 返回客户端。
关键原则
- 单向依赖:
Controller
→Service
→Mapper
(禁止反向依赖或跨层调用)。 - 职责隔离:
Controller
不管业务,Service
不管SQL,Mapper
只管数据库。
- 复用性: 一个
Service
可能被多个Controller
调用,一个Mapper
可能被多个Service
调用。
通过这种分层设计,系统更易于维护、扩展和测试,符合高内聚低耦合的软件工程原则
先写前端然后写后端——Controller
→ Service
→ Mapper