03. 开发普通用户信息管理功能
SQL
CREATE TABLE `user` (
`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 '名称',
`avatar` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '头像',
`role` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '角色',
`phone` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '联系方式',
`email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='普通用户信息';
开发后端接口
- 开发实体类 entity (跟数据库的表的字段对应)
- 创建 controller(定义后端的 http 接口)
- 创建 Service(业务实现)
- 创建 Mapper(数据库操作的接口 增、删、改、查) 以及 Mapper.xml(sql 实现)
User.java
package com.example.entity;
/**
* 普通用户
*/
public class User extends Account {
/** ID */
private Integer id;
/** 用户名 */
private String username;
/** 密码 */
private String password;
/** 姓名 */
private String name;
/** 头像 */
private String avatar;
/** 角色标识 */
private String role;
private String phone;
private String email;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@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;
}
@Override
public String getAvatar() {
return avatar;
}
@Override
public void setAvatar(String avatar) {
this.avatar = avatar;
}
@Override
public String getRole() {
return role;
}
@Override
public void setRole(String role) {
this.role = role;
}
}
UserMapper.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.UserMapper">
<select id="selectAll" resultType="com.example.entity.User">
select * from `user`
<where>
<if test="name != null"> and name like concat('%', #{name}, '%')</if>
</where>
order by id desc
</select>
<insert id="insert" parameterType="com.example.entity.User" useGeneratedKeys="true">
insert into `user`(id, username, password, name, avatar, role, phone, email)
values (#{id}, #{username}, #{password}, #{name}, #{avatar}, #{role}, #{phone}, #{email})
</insert>
<update id="updateById" parameterType="com.example.entity.User">
update `user` set username = #{username}, password = #{password}, name = #{name}, avatar = #{avatar}, role = #{role},
phone = #{phone}, email = #{email}
where id = #{id}
</update>
</mapper>
开发前端页面
- 创建 vue 页面
- 创建路由
- 配置菜单
User.vue
<template>
<div>
<div class="card" style="margin-bottom: 5px;">
<el-input v-model="data.name" style="width: 300px; margin-right: 10px" placeholder="请输入名称查询"></el-input>
<el-button type="primary" @click="load">查询</el-button>
<el-button type="info" style="margin: 0 10px" @click="reset">重置</el-button>
</div>
<div class="card" style="margin-bottom: 5px">
<div style="margin-bottom: 10px">
<el-button type="primary" @click="handleAdd">新增</el-button>
</div>
<el-table :data="data.tableData" stripe>
<el-table-column label="用户名" prop="username"></el-table-column>
<el-table-column label="名称" prop="name"></el-table-column>
<el-table-column label="头像">
<template #default="scope">
<el-image v-if="scope.row.avatar" :src="scope.row.avatar" preview-teleported :preview-src-list="[scope.row.avatar]" style="width: 40px; height: 40px; border-radius: 50%"></el-image>
</template>
</el-table-column>
<el-table-column label="角色" prop="role"></el-table-column>
<el-table-column label="手机号" prop="phone"></el-table-column>
<el-table-column label="邮箱" prop="email"></el-table-column>
<el-table-column label="操作" align="center" width="160">
<template #default="scope">
<el-button type="primary" @click="handleEdit(scope.row)">编辑</el-button>
<el-button type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="card">
<el-pagination @current-change="load" background layout="total, prev, pager, next" v-model:page-size="data.pageSize" v-model:current-page="data.pageNum" :total="data.total"/>
</div>
<el-dialog title="普通用户信息" width="40%" v-model="data.formVisible" :close-on-click-modal="false" destroy-on-close>
<el-form ref="formRef" :model="data.form" :rules="data.rules" label-width="100px" style="padding-right: 50px">
<el-form-item label="账号" prop="username">
<el-input :disabled="data.form.id > 0" v-model="data.form.username" autocomplete="off" />
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="data.form.name" autocomplete="off" />
</el-form-item>
<el-form-item label="头像" prop="avatar">
<el-upload :action="uploadUrl" list-type="picture" :on-success="handleImgSuccess">
<el-button type="primary">上传图片</el-button>
</el-upload>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="data.form.phone" autocomplete="off" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="data.form.email" autocomplete="off" />
</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 request from "@/utils/request";
import {reactive, ref} from "vue";
import {ElMessageBox, ElMessage} from "element-plus";
// 文件上传的接口地址
const uploadUrl = import.meta.env.VITE_BASE_URL + '/files/upload'
const formRef = ref()
const data = reactive({
user: JSON.parse(localStorage.getItem('system-user') || '{}'),
pageNum: 1,
pageSize: 10,
total: 0,
formVisible: false,
form: {},
tableData: [],
name: null,
rules: {
username: [
{ required: true, message: '请输入账号', trigger: 'blur' }
],
name: [
{ required: true, message: '请输入名称', trigger: 'blur' }
],
avatar: [
{ required: true, message: '请上传头像', trigger: 'blur' }
],
phone: [
{ required: true, message: '请输入手机号', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' }
],
}
})
// 分页查询
const load = () => {
request.get('/user/selectPage', {
params: {
pageNum: data.pageNum,
pageSize: data.pageSize,
name: data.name
}
}).then(res => {
data.tableData = res.data?.list
data.total = res.data?.total
})
}
// 新增
const handleAdd = () => {
data.form = {}
data.formVisible = true
}
// 编辑
const handleEdit = (row) => {
data.form = JSON.parse(JSON.stringify(row))
data.formVisible = true
}
// 新增保存
const add = () => {
request.post('/user/add', data.form).then(res => {
if (res.code === '200') {
load()
ElMessage.success('操作成功')
data.formVisible = false
} else {
ElMessage.error(res.msg)
}
})
}
// 编辑保存
const update = () => {
request.put('/user/update', data.form).then(res => {
if (res.code === '200') {
load()
ElMessage.success('操作成功')
data.formVisible = false
} else {
ElMessage.error(res.msg)
}
})
}
// 弹窗保存
const save = () => {
formRef.value.validate(valid => {
if (valid) {
// data.form有id就是更新,没有就是新增
data.form.id ? update() : add()
}
})
}
// 删除
const handleDelete = (id) => {
ElMessageBox.confirm('删除后数据无法恢复,您确定删除吗?', '删除确认', { type: 'warning' }).then(res => {
request.delete('/user/delete/' + id).then(res => {
if (res.code === '200') {
load()
ElMessage.success('操作成功')
} else {
ElMessage.error(res.msg)
}
})
}).catch(err => {})
}
// 重置
const reset = () => {
data.name = null
load()
}
// 处理文件上传的钩子
const handleImgSuccess = (res) => {
data.form.avatar = res.data // res.data就是文件上传返回的文件路径,获取到路径后赋值表单的属性
}
load()
</script>
Element-Plus 官方网站
https://element-plus.org/zh-CN/
preview