使用@RequestParam时el前端
时间: 2023-07-06 13:39:09 浏览: 171
我理解你的问题是如何在前端使用EL表达式获取@RequestParam中的参数值。
在Spring MVC中,@RequestParam注解用于从请求参数中获取参数值。在JSP页面中,可以使用EL表达式来获取请求参数值。具体做法如下:
1. 在JSP页面中引入core标签库:<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
2. 使用EL表达式获取请求参数值,例如:${param.paramName}
其中,paramName是@RequestParam注解中指定的参数名。
示例代码如下:
```jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<title>获取请求参数值</title>
</head>
<body>
<h1>获取请求参数值</h1>
<p>参数名:paramName,参数值:${param.paramName}</p>
</body>
</html>
```
希望能够解决你的问题,如有疑问请继续追问。
相关问题
el前端如何传递@RequestParam需要的值
在前端传递@RequestParam需要的值,可以使用表单提交或者Ajax请求。
如果使用表单提交,可以在表单中添加一个输入框,用户输入@RequestParam需要的值,然后在提交表单时将该值传递给后端。示例代码如下:
```html
<form action="/path/to/controller" method="get">
<label for="paramName">参数名:</label>
<input type="text" id="paramName" name="paramName">
<button type="submit">提交</button>
</form>
```
在上面的代码中,通过input标签获取用户输入的参数值,并在表单提交时将该值传递给后端。
如果使用Ajax请求,可以在前端使用JavaScript获取用户输入的值,然后通过Ajax请求将该值传递给后端。示例代码如下:
```javascript
var paramName = document.getElementById("paramName").value;
// 使用Ajax请求将paramName传递给后端
$.ajax({
url: "/path/to/controller",
type: "GET",
data: {paramName: paramName},
success: function(data) {
console.log(data);
},
error: function(xhr, status, error) {
console.log(error);
}
});
```
在上面的代码中,使用JavaScript获取用户输入的参数值,并通过Ajax请求将该值传递给后端。在Ajax请求中,使用data属性将参数值传递给后端。
希望能够解决你的问题,如有疑问请继续追问。
/** * 条件分页查询 */ @GetMapping public Result page(String name , Integer degree, Integer clazzId, @RequestParam(defaultValue = "1") Integer page , @RequestParam(defaultValue = "10") Integer pageSize){ PageResult pageResult = studentService.page(name,degree,clazzId,page,pageSize); return Result.success(pageResult); } 后端的分页查询只有这几个参数,根据我补充的信息再调整下,并生成完整的代码
<think>根据您提供的后端分页查询接口,目前只支持name、degree、clazzId三个查询条件,以及分页参数。因此,我们需要调整前端搜索表单,去掉学号(no)和手机号(phone)的搜索条件,以保持前后端一致。
调整后的搜索表单将只包含:
1. 班级(clazzId)
2. 学历(degree)
3. 姓名(name)
同时,分页参数使用pagination对象中的current和size。
另外,根据后端接口,我们需要注意:
- 请求参数名:name, degree, clazzId, page, pageSize
- 参数位置:查询字符串(GET请求)
因此,我们需要修改前端搜索部分的代码,移除学号和手机号的输入框,并调整请求参数。
以下是完整的调整后代码:
```vue
<template>
<div class="student-management">
<!-- 搜索区域 -->
<el-card class="search-card">
<el-form :inline="true" :model="searchForm">
<el-form-item label="班级">
<el-select v-model="searchForm.clazzId" placeholder="请选择班级" clearable filterable>
<el-option
v-for="clazz in clazzOptions"
:key="clazz.id"
:label="clazz.name"
:value="clazz.id"
/>
</el-select>
</el-form-item>
<el-form-item label="学历">
<el-select v-model="searchForm.degree" placeholder="请选择学历" clearable>
<el-option
v-for="degree in degreeOptions"
:key="degree.value"
:label="degree.label"
:value="degree.value"
/>
</el-select>
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="searchForm.name" placeholder="请输入姓名" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch" :icon="Search">查询</el-button>
<el-button @click="resetSearch" :icon="Refresh">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 操作按钮区域 -->
<div class="action-buttons">
<el-button type="primary" @click="handleAdd" :icon="Plus">新增学员</el-button>
<el-button
type="danger"
:disabled="!selectedRows.length"
@click="handleBatchDelete"
:icon="Delete"
>
批量删除
</el-button>
</div>
<!-- 学员列表 -->
<el-card>
<el-table
:data="studentList"
border
stripe
@selection-change="handleSelectionChange"
v-loading="loading"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="no" label="学号" width="120" align="center" />
<el-table-column prop="name" label="姓名" width="100" align="center" />
<el-table-column label="性别" width="80" align="center">
<template #default="{ row }">
{{ row.gender === 1 ? '男' : '女' }}
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" width="130" align="center" />
<!-- 身份证号脱敏展示 -->
<el-table-column label="身份证号" width="180" align="center">
<template #default="{ row }">
<span v-if="row.idCard">
{{ row.idCard.substring(0, 6) }}****{{ row.idCard.substring(row.idCard.length - 4) }}
</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="学历" width="100" align="center">
<template #default="{ row }">
{{ getDegreeLabel(row.degree) }}
</template>
</el-table-column>
<el-table-column prop="clazzName" label="班级" width="150" align="center" />
<el-table-column label="违纪情况" width="120" align="center">
<template #default="{ row }">
<el-tag v-if="row.violationCount > 0" type="danger">
{{ row.violationCount }}次({{ row.violationScore }}分)
</el-tag>
<el-tag v-else type="success">无违纪</el-tag>
</template>
</el-table-column>
<!-- 最后修改时间 -->
<el-table-column prop="updateTime" label="最后修改时间" width="180" align="center">
<template #default="{ row }">
{{ formatDateTime(row.updateTime) }}
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="250" align="center">
<template #default="{ row }">
<el-button size="small" @click="handleEdit(row)" :icon="Edit">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(row.id)" :icon="Delete">
删除
</el-button>
<el-button
size="small"
type="warning"
@click="handleViolation(row)"
:disabled="row.violationScore >= 100"
:icon="Warning"
>
违纪
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination
class="pagination"
v-model:current-page="pagination.current"
v-model:page-size="pagination.size"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
<!-- 学生表单对话框 -->
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑学员信息' : '新增学员'" width="600px">
<el-form ref="studentFormRef" :model="studentForm" :rules="rules" label-width="100px">
<el-form-item label="姓名" prop="name">
<el-input v-model="studentForm.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="学号" prop="no">
<el-input v-model="studentForm.no" placeholder="请输入学号" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="studentForm.gender">
<el-radio :label="1">男</el-radio>
<el-radio :label="2">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="studentForm.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="studentForm.idCard" placeholder="请输入身份证号" />
</el-form-item>
<el-form-item label="是否院校" prop="isCollege">
<el-radio-group v-model="studentForm.isCollege">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="学历" prop="degree">
<el-select v-model="studentForm.degree" placeholder="请选择学历" style="width: 100%">
<el-option
v-for="degree in degreeOptions"
:key="degree.value"
:label="degree.label"
:value="degree.value"
/>
</el-select>
</el-form-item>
<el-form-item label="毕业时间" prop="graduationDate">
<el-date-picker
v-model="studentForm.graduationDate"
type="date"
placeholder="选择毕业日期"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="班级" prop="clazzId">
<el-select v-model="studentForm.clazzId" placeholder="请选择班级" style="width: 100%">
<el-option
v-for="clazz in clazzOptions"
:key="clazz.id"
:label="clazz.name"
:value="clazz.id"
/>
</el-select>
</el-form-item>
<el-form-item label="联系地址" prop="address">
<el-input v-model="studentForm.address" type="textarea" placeholder="请输入联系地址" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</template>
</el-dialog>
<!-- 违纪处理对话框 -->
<el-dialog v-model="violationDialogVisible" title="违纪处理" width="400px">
<el-form :model="violationForm" label-width="80px">
<el-form-item label="学员姓名">
<el-input :value="currentStudent?.name" disabled />
</el-form-item>
<el-form-item label="当前扣分">
<el-input :value="currentStudent?.violationScore" disabled />
</el-form-item>
<el-form-item label="扣分数" prop="score">
<el-input-number
v-model="violationForm.score"
:min="1"
:max="100"
controls-position="right"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="violationDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleViolationSubmit">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import {
ElMessage,
ElMessageBox,
type FormInstance,
type FormRules,
} from 'element-plus'
import {
Search,
Refresh,
Plus,
Delete,
Edit,
Warning
} from '@element-plus/icons-vue'
import dayjs from 'dayjs'
import {
queryPageApi,
addApi,
updateApi,
deleteApi,
handleViolationApi,
queryClazzListApi,
type StudentModel,
type StudentQueryParams,
type ViolationHandleParams,
type PageResultModel,
type ResultModel,
type ClazzModel,
Gender,
DegreeType,
CollegeFlag,
} from '@/api/stu'
// 搜索表单(根据后端接口调整,只保留name, degree, clazzId)
const searchForm = reactive<StudentQueryParams>({
clazzId: null,
degree: null,
name: '',
page: 1,
pageSize: 10,
})
// 分页信息
const pagination = reactive({
current: 1,
size: 10,
total: 0,
})
// 学员列表
const studentList = ref<StudentModel[]>([])
const selectedRows = ref<StudentModel[]>([])
const loading = ref(false)
// 学历选项
const degreeOptions = [
{ value: DegreeType.JUNIOR, label: '初中' },
{ value: DegreeType.HIGH_SCHOOL, label: '高中' },
{ value: DegreeType.COLLEGE, label: '大专' },
{ value: DegreeType.BACHELOR, label: '本科' },
{ value: DegreeType.MASTER, label: '硕士' },
{ value: DegreeType.DOCTOR, label: '博士' },
]
// 班级选项(从API获取)
const clazzOptions = ref<ClazzModel[]>([])
// 表单相关
const dialogVisible = ref(false)
const violationDialogVisible = ref(false)
const isEdit = ref(false)
const studentFormRef = ref<FormInstance>()
const currentStudent = ref<StudentModel | null>(null)
// 学生表单
const studentForm = reactive<Partial<StudentModel>>({
name: '',
no: '',
gender: Gender.MALE,
phone: '',
idCard: '',
isCollege: CollegeFlag.IS_COLLEGE,
address: '',
degree: undefined,
graduationDate: '',
clazzId: undefined,
})
// 违纪表单
const violationForm = reactive({
score: 1,
})
// 表单验证规则
const rules = reactive<FormRules>({
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
no: [{ required: true, message: '请输入学号', trigger: 'blur' }],
gender: [{ required: true, message: '请选择性别', trigger: 'change' }],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' },
],
idCard: [
{ required: true, message: '请输入身份证号', trigger: 'blur' },
{
pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
message: '身份证号格式不正确',
trigger: 'blur',
},
],
clazzId: [{ required: true, message: '请选择班级', trigger: 'change' }],
})
// 获取学历标签
const getDegreeLabel = (degree?: number | null) => {
if (!degree) return '-'
const degreeOption = degreeOptions.find((opt) => opt.value === degree)
return degreeOption ? degreeOption.label : '-'
}
// 格式化时间
const formatDateTime = (dateString?: string) => {
if (!dateString) return '-'
return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss')
}
// 获取班级列表
const fetchClazzList = async () => {
try {
const response: ResultModel<ClazzModel[]> = await queryClazzListApi()
if (response.code === 1) {
clazzOptions.value = response.data
} else {
ElMessage.error(`获取班级列表失败: ${response.msg}`)
}
} catch (error) {
console.error('获取班级列表出错:', error)
ElMessage.error('获取班级列表失败')
}
}
// 获取学员列表
const fetchStudents = async () => {
try {
loading.value = true
// 构建查询参数(根据后端接口,只传递name, degree, clazzId和分页参数)
const params: StudentQueryParams = {
name: searchForm.name,
degree: searchForm.degree,
clazzId: searchForm.clazzId,
page: pagination.current,
pageSize: pagination.size,
}
const response: PageResultModel<StudentModel> = await queryPageApi(params)
if (response.code === 1) {
studentList.value = response.data.rows
pagination.total = response.data.total
} else {
console.error('获取学员列表失败:', response.msg)
}
} catch (error) {
console.error('获取学员列表出错:', error)
} finally {
loading.value = false
}
}
// 搜索处理
const handleSearch = () => {
pagination.current = 1
fetchStudents()
}
// 重置搜索
const resetSearch = () => {
searchForm.clazzId = null
searchForm.degree = null
searchForm.name = ''
handleSearch()
}
// 分页大小变化
const handleSizeChange = (size: number) => {
pagination.size = size
pagination.current = 1
fetchStudents()
}
// 当前页变化
const handleCurrentChange = (current: number) => {
pagination.current = current
fetchStudents()
}
// 表格选择变化
const handleSelectionChange = (rows: StudentModel[]) => {
selectedRows.value = rows
}
// 新增学员
const handleAdd = () => {
isEdit.value = false
// 重置表单
Object.assign(studentForm, {
name: '',
no: '',
gender: Gender.MALE,
phone: '',
idCard: '',
isCollege: CollegeFlag.IS_COLLEGE,
address: '',
degree: undefined,
graduationDate: '',
clazzId: undefined,
})
dialogVisible.value = true
}
// 编辑学员
const handleEdit = (student: StudentModel) => {
isEdit.value = true
currentStudent.value = student
// 填充表单数据
Object.assign(studentForm, { ...student })
dialogVisible.value = true
}
// 提交表单
const submitForm = async () => {
if (!studentFormRef.value) return
try {
await studentFormRef.value.validate()
if (isEdit.value) {
// 编辑学员
const response: ResultModel = await updateApi(studentForm as StudentModel)
if (response.code === 1) {
ElMessage.success('学员信息更新成功')
dialogVisible.value = false
fetchStudents()
} else {
ElMessage.error(`更新失败: ${response.msg}`)
}
} else {
// 新增学员
const response: ResultModel<number> = await addApi(studentForm as Omit<StudentModel, 'id'>)
if (response.code === 1) {
ElMessage.success(`学员添加成功,ID: ${response.data}`)
dialogVisible.value = false
fetchStudents()
} else {
ElMessage.error(`添加失败: ${response.msg}`)
}
}
} catch (error) {
console.error('表单提交失败:', error)
}
}
// 删除学员
const handleDelete = async (id: number) => {
try {
await ElMessageBox.confirm('确定要删除该学员吗?', '警告', {
type: 'warning',
confirmButtonText: '确定',
cancelButtonText: '取消',
})
const response: ResultModel = await deleteApi([id])
if (response.code === 1) {
ElMessage.success('学员删除成功')
fetchStudents()
} else {
ElMessage.error(`删除失败: ${response.msg}`)
}
} catch (error) {
console.log('删除操作已取消')
}
}
// 批量删除
const handleBatchDelete = async () => {
if (!selectedRows.value.length) return
try {
const ids = selectedRows.value.map((row) => row.id)
await ElMessageBox.confirm(`确定要删除选中的 ${ids.length} 位学员吗?', '警告`, {
type: 'warning',
confirmButtonText: '确定',
cancelButtonText: '取消',
})
const response: ResultModel = await deleteApi(ids)
if (response.code === 1) {
ElMessage.success(`成功删除 ${ids.length} 位学员`)
selectedRows.value = []
fetchStudents()
} else {
ElMessage.error(`批量删除失败: ${response.msg}`)
}
} catch (error) {
console.log('批量删除操作已取消')
}
}
// 违纪处理
const handleViolation = (student: StudentModel) => {
currentStudent.value = student
violationForm.score = 1
violationDialogVisible.value = true
}
// 提交违纪处理
const handleViolationSubmit = async () => {
if (!currentStudent.value) return
try {
const params: ViolationHandleParams = {
id: currentStudent.value.id,
score: violationForm.score,
}
const response: ResultModel = await handleViolationApi(params)
if (response.code === 1) {
ElMessage.success('违纪处理成功')
violationDialogVisible.value = false
fetchStudents()
} else {
ElMessage.error(`违纪处理失败: ${response.msg}`)
}
} catch (error) {
console.error('违纪处理出错:', error)
}
}
// 初始化加载数据
onMounted(() => {
fetchStudents()
fetchClazzList()
})
</script>
<style scoped>
.student-management {
padding: 20px;
}
.search-card {
margin-bottom: 20px;
}
.action-buttons {
margin-bottom: 15px;
}
.pagination {
margin-top: 20px;
justify-content: flex-end;
}
</style>
```
### 调整说明:
1. **搜索表单调整**:
- 移除了学号(no)和手机号(phone)的搜索条件,只保留班级、学历和姓名。
- 重置搜索时,只重置这三个字段。
2. **请求参数调整**:
- 在 `fetchStudents` 方法中,构建的查询参数只包含 `name`, `degree`, `clazzId`, `page`, `pageSize`,与后端接口一致。
3. **其他部分保持不变**:
- 班级选项仍然通过API动态获取。
- 身份证号脱敏显示、最后修改时间显示等功能保持不变。
这样调整后,前端搜索功能与后端接口完全匹配,避免了传递无效参数。
§§相关问题§§:
1. 在Vue3中,如何优雅地处理表单验证?
2. Element Plus的分页组件如何与后端API进行配合?
3. 如何优化Element Plus表格在大数据量下的渲染性能?
4. 在Vue3组合式API中,如何处理多个异步请求的并行加载?</think>根据您提供的后端分页查询接口,我将调整前端代码以匹配后端参数,并生成完整的学生管理组件代码。以下是优化后的实现:
```vue
<template>
<div class="student-management">
<!-- 搜索区域 -->
<el-card class="search-card">
<el-form :inline="true" :model="searchForm">
<el-form-item label="班级">
<el-select v-model="searchForm.clazzId" placeholder="请选择班级" clearable filterable>
<el-option
v-for="clazz in clazzOptions"
:key="clazz.id"
:label="clazz.name"
:value="clazz.id"
/>
</el-select>
</el-form-item>
<el-form-item label="学历">
<el-select v-model="searchForm.degree" placeholder="请选择学历" clearable>
<el-option
v-for="degree in degreeOptions"
:key="degree.value"
:label="degree.label"
:value="degree.value"
/>
</el-select>
</el-form-item>
<el-form-item label="姓名">
<el-input v-model="searchForm.name" placeholder="请输入姓名" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="resetSearch">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 操作按钮区域 -->
<div class="action-buttons">
<el-button type="primary" @click="handleAdd">新增学员</el-button>
<el-button
type="danger"
:disabled="!selectedRows.length"
@click="handleBatchDelete"
>
批量删除
</el-button>
</div>
<!-- 学员列表 -->
<el-card>
<el-table
:data="studentList"
border
stripe
@selection-change="handleSelectionChange"
v-loading="loading"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column prop="no" label="学号" width="120" align="center" />
<el-table-column prop="name" label="姓名" width="100" align="center" />
<el-table-column label="性别" width="80" align="center">
<template #default="{ row }">
{{ row.gender === 1 ? '男' : '女' }}
</template>
</el-table-column>
<el-table-column prop="phone" label="手机号" width="130" align="center" />
<!-- 身份证号脱敏展示 -->
<el-table-column label="身份证号" width="180" align="center">
<template #default="{ row }">
<span v-if="row.idCard">
{{ row.idCard.substring(0, 6) }}****{{ row.idCard.substring(row.idCard.length - 4) }}
</span>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="学历" width="100" align="center">
<template #default="{ row }">
{{ getDegreeLabel(row.degree) }}
</template>
</el-table-column>
<el-table-column prop="clazzName" label="班级" width="150" align="center" />
<el-table-column label="违纪情况" width="120" align="center">
<template #default="{ row }">
<el-tag v-if="row.violationCount > 0" type="danger">
{{ row.violationCount }}次({{ row.violationScore }}分)
</el-tag>
<el-tag v-else type="success">无违纪</el-tag>
</template>
</el-table-column>
<!-- 最后修改时间 -->
<el-table-column prop="updateTime" label="最后修改时间" width="180" align="center">
<template #default="{ row }">
{{ formatDateTime(row.updateTime) }}
</template>
</el-table-column>
<el-table-column label="操作" fixed="right" width="250" align="center">
<template #default="{ row }">
<el-button size="small" @click="handleEdit(row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(row.id)">删除</el-button>
<el-button
size="small"
type="warning"
@click="handleViolation(row)"
:disabled="row.violationScore >= 100"
>
违纪
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<el-pagination
class="pagination"
v-model:current-page="pagination.current"
v-model:page-size="pagination.size"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</el-card>
<!-- 学生表单对话框 -->
<el-dialog v-model="dialogVisible" :title="isEdit ? '编辑学员信息' : '新增学员'" width="600px">
<el-form ref="studentFormRef" :model="studentForm" :rules="rules" label-width="100px">
<el-form-item label="姓名" prop="name">
<el-input v-model="studentForm.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="学号" prop="no">
<el-input v-model="studentForm.no" placeholder="请输入学号" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="studentForm.gender">
<el-radio :label="1">男</el-radio>
<el-radio :label="2">女</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="studentForm.phone" placeholder="请输入手机号" />
</el-form-item>
<el-form-item label="身份证号" prop="idCard">
<el-input v-model="studentForm.idCard" placeholder="请输入身份证号" />
</el-form-item>
<el-form-item label="是否院校" prop="isCollege">
<el-radio-group v-model="studentForm.isCollege">
<el-radio :label="1">是</el-radio>
<el-radio :label="0">否</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="学历" prop="degree">
<el-select v-model="studentForm.degree" placeholder="请选择学历" style="width: 100%">
<el-option
v-for="degree in degreeOptions"
:key="degree.value"
:label="degree.label"
:value="degree.value"
/>
</el-select>
</el-form-item>
<el-form-item label="毕业时间" prop="graduationDate">
<el-date-picker
v-model="studentForm.graduationDate"
type="date"
placeholder="选择毕业日期"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="班级" prop="clazzId">
<el-select v-model="studentForm.clazzId" placeholder="请选择班级" style="width: 100%">
<el-option
v-for="clazz in clazzOptions"
:key="clazz.id"
:label="clazz.name"
:value="clazz.id"
/>
</el-select>
</el-form-item>
<el-form-item label="联系地址" prop="address">
<el-input v-model="studentForm.address" type="textarea" placeholder="请输入联系地址" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitForm">确定</el-button>
</template>
</el-dialog>
<!-- 违纪处理对话框 -->
<el-dialog v-model="violationDialogVisible" title="违纪处理" width="400px">
<el-form :model="violationForm" label-width="80px">
<el-form-item label="学员姓名">
<el-input :value="currentStudent?.name" disabled />
</el-form-item>
<el-form-item label="当前扣分">
<el-input :value="currentStudent?.violationScore" disabled />
</el-form-item>
<el-form-item label="扣分数" prop="score">
<el-input-number
v-model="violationForm.score"
:min="1"
:max="100"
controls-position="right"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="violationDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleViolationSubmit">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
import {
ElMessage,
ElMessageBox,
type FormInstance,
type FormRules,
} from 'element-plus'
import dayjs from 'dayjs'
import {
queryPageApi,
addApi,
updateApi,
deleteApi,
handleViolationApi,
queryClazzListApi,
type StudentModel,
type StudentQueryParams,
type ViolationHandleParams,
type PageResultModel,
type ResultModel,
type ClazzModel,
Gender,
DegreeType,
CollegeFlag,
} from '@/api/stu'
// 搜索表单(根据后端接口调整)
const searchForm = reactive<StudentQueryParams>({
clazzId: null,
degree: null,
name: '',
page: 1,
pageSize: 10,
})
// 分页信息
const pagination = reactive({
current: 1,
size: 10,
total: 0,
})
// 学员列表
const studentList = ref<StudentModel[]>([])
const selectedRows = ref<StudentModel[]>([])
const loading = ref(false)
// 学历选项
const degreeOptions = [
{ value: DegreeType.JUNIOR, label: '初中' },
{ value: DegreeType.HIGH_SCHOOL, label: '高中' },
{ value: DegreeType.COLLEGE, label: '大专' },
{ value: DegreeType.BACHELOR, label: '本科' },
{ value: DegreeType.MASTER, label: '硕士' },
{ value: DegreeType.DOCTOR, label: '博士' },
]
// 班级选项(从API获取)
const clazzOptions = ref<ClazzModel[]>([])
// 表单相关
const dialogVisible = ref(false)
const violationDialogVisible = ref(false)
const isEdit = ref(false)
const studentFormRef = ref<FormInstance>()
const currentStudent = ref<StudentModel | null>(null)
// 学生表单
const studentForm = reactive<Partial<StudentModel>>({
name: '',
no: '',
gender: Gender.MALE,
phone: '',
idCard: '',
isCollege: CollegeFlag.IS_COLLEGE,
address: '',
degree: undefined,
graduationDate: '',
clazzId: undefined,
})
// 违纪表单
const violationForm = reactive({
score: 1,
})
// 表单验证规则
const rules = reactive<FormRules>({
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
no: [{ required: true, message: '请输入学号', trigger: 'blur' }],
gender: [{ required: true, message: '请选择性别', trigger: 'change' }],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' },
],
idCard: [
{ required: true, message: '请输入身份证号', trigger: 'blur' },
{
pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
message: '身份证号格式不正确',
trigger: 'blur',
},
],
clazzId: [{ required: true, message: '请选择班级', trigger: 'change' }],
})
// 获取学历标签
const getDegreeLabel = (degree?: number | null) => {
if (!degree) return '-'
const degreeOption = degreeOptions.find((opt) => opt.value === degree)
return degreeOption ? degreeOption.label : '-'
}
// 格式化时间
const formatDateTime = (dateString?: string) => {
if (!dateString) return '-'
return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss')
}
// 获取班级列表
const fetchClazzList = async () => {
try {
const response: ResultModel<ClazzModel[]> = await queryClazzListApi()
if (response.code === 1) {
clazzOptions.value = response.data
} else {
ElMessage.error(`获取班级列表失败: ${response.msg}`)
}
} catch (error) {
console.error('获取班级列表出错:', error)
ElMessage.error('获取班级列表失败')
}
}
// 获取学员列表(根据后端接口调整)
const fetchStudents = async () => {
try {
loading.value = true
// 构建查询参数(根据后端接口)
const params: StudentQueryParams = {
name: searchForm.name,
degree: searchForm.degree,
clazzId: searchForm.clazzId,
page: pagination.current,
pageSize: pagination.size,
}
const response: PageResultModel<StudentModel> = await queryPageApi(params)
if (response.code === 1) {
studentList.value = response.data.rows
pagination.total = response.data.total
} else {
console.error('获取学员列表失败:', response.msg)
}
} catch (error) {
console.error('获取学员列表出错:', error)
} finally {
loading.value = false
}
}
// 搜索处理
const handleSearch = () => {
pagination.current = 1
fetchStudents()
}
// 重置搜索
const resetSearch = () => {
searchForm.clazzId = null
searchForm.degree = null
searchForm.name = ''
handleSearch()
}
// 分页大小变化
const handleSizeChange = (size: number) => {
pagination.size = size
pagination.current = 1
fetchStudents()
}
// 当前页变化
const handleCurrentChange = (current: number) => {
pagination.current = current
fetchStudents()
}
// 表格选择变化
const handleSelectionChange = (rows: StudentModel[]) => {
selectedRows.value = rows
}
// 新增学员
const handleAdd = () => {
isEdit.value = false
// 重置表单
Object.assign(studentForm, {
name: '',
no: '',
gender: Gender.MALE,
phone: '',
idCard: '',
isCollege: CollegeFlag.IS_COLLEGE,
address: '',
degree: undefined,
graduationDate: '',
clazzId: undefined,
})
dialogVisible.value = true
}
// 编辑学员
const handleEdit = (student: StudentModel) => {
isEdit.value = true
currentStudent.value = student
// 填充表单数据
Object.assign(studentForm, { ...student })
dialogVisible.value = true
}
// 提交表单
const submitForm = async () => {
if (!studentFormRef.value) return
try {
await studentFormRef.value.validate()
if (isEdit.value) {
// 编辑学员
const response: ResultModel = await updateApi(studentForm as StudentModel)
if (response.code === 1) {
ElMessage.success('学员信息更新成功')
dialogVisible.value = false
fetchStudents()
} else {
ElMessage.error(`更新失败: ${response.msg}`)
}
} else {
// 新增学员
const response: ResultModel<number> = await addApi(studentForm as Omit<StudentModel, 'id'>)
if (response.code === 1) {
ElMessage.success(`学员添加成功,ID: ${response.data}`)
dialogVisible.value = false
fetchStudents()
} else {
ElMessage.error(`添加失败: ${response.msg}`)
}
}
} catch (error) {
console.error('表单提交失败:', error)
}
}
// 删除学员
const handleDelete = async (id: number) => {
try {
await ElMessageBox.confirm('确定要删除该学员吗?', '警告', {
type: 'warning',
confirmButtonText: '确定',
cancelButtonText: '取消',
})
const response: ResultModel = await deleteApi([id])
if (response.code === 1) {
ElMessage.success('学员删除成功')
fetchStudents()
} else {
ElMessage.error(`删除失败: ${response.msg}`)
}
} catch (error) {
console.log('删除操作已取消')
}
}
// 批量删除
const handleBatchDelete = async () => {
if (!selectedRows.value.length) return
try {
const ids = selectedRows.value.map((row) => row.id)
await ElMessageBox.confirm(`确定要删除选中的 ${ids.length} 位学员吗?`, '警告', {
type: 'warning',
confirmButtonText: '确定',
cancelButtonText: '取消',
})
const response: ResultModel = await deleteApi(ids)
if (response.code === 1) {
ElMessage.success(`成功删除 ${ids.length} 位学员`)
selectedRows.value = []
fetchStudents()
} else {
ElMessage.error(`批量删除失败: ${response.msg}`)
}
} catch (error) {
console.log('批量删除操作已取消')
}
}
// 违纪处理
const handleViolation = (student: StudentModel) => {
currentStudent.value = student
violationForm.score = 1
violationDialogVisible.value = true
}
// 提交违纪处理
const handleViolationSubmit = async () => {
if (!currentStudent.value) return
try {
const params: ViolationHandleParams = {
id: currentStudent.value.id,
score: violationForm.score,
}
const response: ResultModel = await handleViolationApi(params)
if (response.code === 1) {
ElMessage.success('违纪处理成功')
violationDialogVisible.value = false
fetchStudents()
} else {
ElMessage.error(`违纪处理失败: ${response.msg}`)
}
} catch (error) {
console.error('违纪处理出错:', error)
}
}
// 初始化加载数据
onMounted(() => {
fetchStudents()
fetchClazzList()
})
</script>
<style scoped>
.student-management {
padding: 20px;
}
.search-card {
margin-bottom: 20px;
}
.action-buttons {
margin-bottom: 15px;
}
.pagination {
margin-top: 20px;
justify-content: flex-end;
}
</style>
```
### 关键调整说明:
1. **后端接口适配**:
- 搜索参数调整为 `name`, `degree`, `clazzId` 三个字段
- 分页参数使用 `page` 和 `pageSize` 字段
- 请求参数构建完全匹配后端接口:
```typescript
const params: StudentQueryParams = {
name: searchForm.name,
degree: searchForm.degree,
clazzId: searchForm.clazzId,
page: pagination.current,
pageSize: pagination.size,
}
```
2. **身份证号脱敏处理**:
```html
<el-table-column label="身份证号" width="180" align="center">
<template #default="{ row }">
<span v-if="row.idCard">
{{ row.idCard.substring(0, 6) }}****{{ row.idCard.substring(row.idCard.length - 4) }}
</span>
<span v-else>-</span>
</template>
</el-table-column>
```
3. **时间显示优化**:
```javascript
const formatDateTime = (dateString?: string) => {
if (!dateString) return '-'
return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss')
}
```
4. **班级数据动态加载**:
```typescript
const fetchClazzList = async () => {
try {
const response: ResultModel<ClazzModel[]> = await queryClazzListApi()
if (response.code === 1) {
clazzOptions.value = response.data
}
} catch (error) {
console.error('获取班级列表出错:', error)
}
}
```
5. **API层调整**:
```typescript
// 分页查询接口
export const queryPageApi = (
params: StudentQueryParams
): Promise<PageResultModel<StudentModel>> => {
return request.get('/students', { params })
}
// 班级查询接口
export const queryClazzListApi = (): Promise<ResultModel<ClazzModel[]>> => {
return request.get('/clazzs/list')
}
```
### 使用说明:
1. 确保后端实现了 `/students` 分页查询接口和 `/clazzs/list` 班级列表接口
2. 身份证号脱敏仅在前端展示,原始数据保持不变
3. 最后修改时间字段需要后端返回 `updateTime` 字段
4. 违纪处理接口路径为 `/students/violation/{id}/{score}`
这个实现完全适配您提供的后端接口,同时优化了用户体验和安全性,特别是敏感信息的处理。
阅读全文
相关推荐









(一)项目构建
使用 Maven 构建项目,在pom.xml中引入 Spring MVC 相关依赖,如spring - webmvc,配置 Servlet、JSP 等相关依赖,确保项目具备 Spring MVC 运行环境 。示例关键依赖配置:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring - webmvc</artifactId>
<version>5.3.18</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet - api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp - api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
</dependencies>
(二)Spring MVC 配置
DispatcherServlet 配置:在 Web.xml(或 Servlet 3.0 + 环境下用 Java 配置)中配置 DispatcherServlet,指定 Spring MVC 配置文件位置,使其能拦截处理请求 。示例 Web.xml 配置:
<servlet>
<servlet - name>springmvc</servlet - name>
<servlet - class>org.springframework.web.servlet.DispatcherServlet</servlet - class>
<init - param>
contextConfigLocation
classpath:springmvc - servlet.xml
</init - param>
<load - on - startup>1</load - on - startup>
</servlet>
<servlet - mapping>
<servlet - name>springmvc</servlet - name>
<url - pattern>/</url - pattern>
</servlet - mapping>
Spring MVC 配置文件(springmvc - servlet.xml):开启组件扫描(扫描控制器等组件)、视图解析器(配置前缀后缀,解析 JSP 视图)、开启注解驱动等 。示例:
<context:component - scan base - package="com.example.controller"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
</bean>
<mvc:annotation - driven/>
三)功能模块实现
1. 用户登录验证
o 控制器(Controller):创建LoginController,编写方法处理/login请求(对应login.jsp表单提交),接收用户名、密码参数(可通过@RequestParam注解),进行简单验证(如硬编码用户名 “admin”、密码 “123” 模拟,实际可连数据库查询),验证成功用return "redirect:/main";重定向到主页控制器方法,失败则带错误信息(通过model.addAttribute)返回login视图(即login.jsp )。示例代码:
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password,
Model model) {
if ("admin".equals(username) && "123".equals(password)) {
return "redirect:/main";
} else {
model.addAttribute("error", "用户名或密码错误");
return "login";
}
}
2. 登录页面(login.jsp):使用 Spring 表单标签库(需引入相关标签库)或普通 HTML 表单,提交到/login,显示错误信息(通过 EL 表达式${error} )。示例关键代码:
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<html>
<body>
<form:form action="/https/wenku.csdn.net/login" method="post">
用户名:<form:input path="username"/>
密码:<form:password path="password"/>
<input type="submit" value="登录">
</form:form>
<c:if test="${not empty error}">
${error}
</c:if>
</body>
</html>
3. 访问控制(拦截器实现)
o 创建拦截器类:实现HandlerInterceptor接口,在preHandle方法中检查会话是否有用户登录标识(如session.getAttribute("user") ,假设登录成功时在会话存user对象),无则redirect到/login并返回false拦截,有则返回true放行 。示例:
package com.example.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
Object user = request.getSession().getAttribute("user");
if (user == null) {
response.sendRedirect(request.getContextPath() + "/login");
return false;
}
return true;
}
}
4. 配置拦截器:在 Spring MVC 配置文件(springmvc - servlet.xml)中注册拦截器,指定拦截路径(如/main )。示例:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/main"/>
<bean class="com.example.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
5. 会话管理(登出功能)
o 控制器方法:在MainController中编写处理登出的方法,调用session.invalidate()销毁会话,然后redirect到登录页 。示例:
package com.example.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class MainController {
@RequestMapping("/main")
public String main() {
return "main";
}
@RequestMapping("/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/login";
}
}
6. 主页(main.jsp):添加 “退出” 链接, href 指向/logout 。示例:
<html>
<body>
欢迎访问主页
退出
</body>
</html>







