1.设计数据库
/* Navicat Premium Data Transfer Source Server : localhost_3306 Source Server Type : MySQL Source Server Version : 80037 (8.0.37) Source Host : localhost:3306 Source Schema : studymysql Target Server Type : MySQL Target Server Version : 80037 (8.0.37) File Encoding : 65001 Date: 24/12/2024 11:32:08 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for emp -- ---------------------------- DROP TABLE IF EXISTS `emp`; CREATE TABLE `emp` ( `empno` int NOT NULL AUTO_INCREMENT COMMENT '雇员编号', `ename` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '雇员姓名', `job` varchar(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '表示工作职位', `mgr` int NULL DEFAULT NULL COMMENT '表示一个雇员的领导编号', `hiredate` datetime NULL DEFAULT NULL COMMENT '表示雇佣日期', `sal` double NULL DEFAULT NULL COMMENT '表示月薪,工资', `comm` double NULL DEFAULT NULL COMMENT '表示奖金或佣金', `deptno` int NULL DEFAULT NULL, PRIMARY KEY (`empno`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of emp -- ---------------------------- SET FOREIGN_KEY_CHECKS = 1;
2.编写实体类和数据库形成映射
package com.pyb.pojo; /** * @version 1.0 * @Author 彭彦彬 * @Date 2024/12/24 15:07 * @注释 */ public class Emp { private int empNo; private String eName; private String job; private int mgr; private String hireDate; private double sal; private double comm; private int deptNo; public Emp(int empNo, String eName, String job, int mgr, String hireDate, double sal, double comm, int deptNo) { this.empNo = empNo; this.eName = eName; this.job = job; this.mgr = mgr; this.hireDate = hireDate; this.sal = sal; this.comm = comm; this.deptNo = deptNo; } public Emp(String eName, String job) { this.eName = eName; this.job = job; } public Emp(String eName, String job, int mgr, String hireDate, double sal, int deptNo, double comm) { this.eName = eName; this.job = job; this.mgr = mgr; this.hireDate = hireDate; this.sal = sal; this.deptNo = deptNo; this.comm = comm; } @Override public String toString() { return "Emp{" + "empNo=" + empNo + ", eName='" + eName + '\'' + ", job='" + job + '\'' + ", mgr=" + mgr + ", hireDate='" + hireDate + '\'' + ", sal=" + sal + ", comm=" + comm + ", deptNo=" + deptNo + '}'; } public Emp() { } public int getEmpNo() { return empNo; } public void setEmpNo(int empNo) { this.empNo = empNo; } public String geteName() { return eName; } public void seteName(String eName) { this.eName = eName; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public int getMgr() { return mgr; } public void setMgr(int mgr) { this.mgr = mgr; } public String getHireDate() { return hireDate; } public void setHireDate(String hireDate) { this.hireDate = hireDate; } public double getSal() { return sal; } public void setSal(double sal) { this.sal = sal; } public double getComm() { return comm; } public void setComm(double comm) { this.comm = comm; } public int getDeptNo() { return deptNo; } public void setDeptNo(int deptNo) { this.deptNo = deptNo; } }
3.编写数据和Java代码交互逻辑
- 定义业务接口
package com.pyb.dao; import com.pyb.pojo.Emp; import java.sql.SQLException; import java.util.List; /** * @version 1.0 * @Author 彭彦彬 * @Date 2024/12/25 10:17 * @注释 */ public interface EmpDao { /** * 获取所有用户数据 * @return */ List<Emp> list() throws SQLException; /** * 查询员工信息通过姓名 * @param name * @return */ Emp selectEmpByName(String name) throws SQLException; /** * 添加員工信息 * @param emp */ int addEmp(Emp emp); int deleteEmp(Emp emp); List<Emp> selectEmpByLike(Emp emp,int page,int limit); long countEmpByLike(Emp emp); }
- 实现业务接口
package com.pyb.dao.daoImpl; import com.pyb.dao.EmpDao; import com.pyb.pojo.Emp; import com.pyb.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; /** * @version 1.0 * @Author 彭彦彬 * @Date 2024/12/25 10:19 */ public class EmpDaoImpl implements EmpDao { @Override public List<Emp> list() throws SQLException { String sql = "SELECT * FROM emp"; List<Emp> list = new ArrayList<>(); // 使用 try-with-resources 确保资源自动关闭 try (Connection con = JdbcUtils.getConnection(); PreparedStatement ps = con.prepareStatement(sql); ResultSet rs = ps.executeQuery()) { while (rs.next()) { int empno = rs.getInt("empno"); String ename = rs.getString("ename"); String job = rs.getString("job"); int mgr = rs.getInt("mgr"); String hiredate = rs.getString("hiredate"); // 如果 hiredate 是日期类型 double sal = rs.getDouble("sal"); double comm = rs.getDouble("comm"); int deptno = rs.getInt("deptno"); list.add(new Emp(empno, ename, job, mgr, hiredate, sal, comm, deptno)); } } catch (SQLException e) { // 记录详细的错误信息,以便于调试 e.printStackTrace(); // 在实际应用中应使用日志框架如 SLF4J 等记录错误信息 throw e; // 或者抛出自定义异常 } return list; } @Override public Emp selectEmpByName(String name) throws SQLException { String sql = "SELECT * FROM emp WHERE ename = ?"; // 使用 try-with-resources 确保资源自动关闭 try (Connection con = JdbcUtils.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { ps.setString(1, name); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { int empno = rs.getInt("empno"); String ename = rs.getString("ename"); String job = rs.getString("job"); int mgr = rs.getInt("mgr"); String hiredate = rs.getString("hiredate"); // 如果 hiredate 是日期类型 double sal = rs.getDouble("sal"); double comm = rs.getDouble("comm"); int deptno = rs.getInt("deptno"); return new Emp(empno, ename, job, mgr, hiredate, sal, comm, deptno); } } // 如果没有找到员工,则返回 null return null; } catch (SQLException e) { // 记录详细的错误信息,以便于调试 e.printStackTrace(); // 在实际应用中应使用日志框架如 SLF4J 等记录错误信息 throw e; // 或者抛出自定义异常 } } @Override public int addEmp(Emp emp) { String sql="insert into emp(ename,job,mgr,hiredate,sal,comm,deptno)values(?,?,?,?,?,?,?)"; int effect=0; // 使用 try-with-resources 确保资源自动关闭 try (Connection con = JdbcUtils.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { ps.setString(1,emp.geteName()); ps.setString(2,emp.getJob()); ps.setInt(3,emp.getMgr()); ps.setString(4,emp.getHireDate()); ps.setDouble(5, emp.getSal()); ps.setDouble(6,emp.getComm()); ps.setInt(7,emp.getDeptNo()); effect=ps.executeUpdate(); } catch (SQLException e) { // 记录详细的错误信息,以便于调试 e.printStackTrace(); // 在实际应用中应使用日志框架如 SLF4J 等记录错误信息 } return effect; } @Override public int deleteEmp(Emp emp) { String sql = "DELETE FROM emp WHERE empno = ?"; int affectedRows = 0; // 使用 try-with-resources 确保资源自动关闭 try (Connection con = JdbcUtils.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { ps.setInt(1, emp.getEmpNo()); affectedRows = ps.executeUpdate(); if (affectedRows == 0) { System.out.println("Warning: No rows were deleted for empno=" + emp.getEmpNo()); // 可选择抛出自定义异常或返回特定值以表示未找到要删除的记录 } else { System.out.println("Employee with empno=" + emp.getEmpNo() + " deleted successfully."); } } catch (SQLException e) { // 记录详细的错误信息,以便于调试 e.printStackTrace(); // 在实际应用中应使用日志框架如 SLF4J 等记录错误信息 // 抛出自定义异常或进行其他适当的错误处理 throw new RuntimeException("Database error occurred while deleting employee.", e); } return affectedRows; } @Override public List<Emp> selectEmpByLike(Emp emp, int page, int limit) { // Adjust the SQL query to support pagination using LIMIT and OFFSET String sql = "SELECT * FROM emp WHERE ename LIKE ? OR job LIKE ? LIMIT ? OFFSET ?"; List<Emp> list = new ArrayList<>(); try (Connection con = JdbcUtils.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { // Set parameters with wildcards for the LIKE clause ps.setString(1, "%" + emp.geteName() + "%"); ps.setString(2, "%" + emp.getJob() + "%"); // Calculate offset based on page number and limit int offset = (page - 1) * limit; ps.setInt(3, limit); ps.setInt(4, offset); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { int empno = rs.getInt("empno"); String ename = rs.getString("ename"); String job = rs.getString("job"); int mgr = rs.getInt("mgr"); String hiredate = rs.getString("hiredate"); // Assuming hiredate is a DATE type in database double sal = rs.getDouble("sal"); Double comm = rs.getDouble("comm"); // Use Double to handle NULL values int deptno = rs.getInt("deptno"); // Handle possible null values for comm if (rs.wasNull()) { comm = null; } list.add(new Emp(empno, ename, job, mgr, hiredate, sal, comm, deptno)); } } } catch (SQLException e) { // Log the exception using a logging framework in production code e.printStackTrace(); // You may want to throw or handle the exception here } return list; // Return the populated list } @Override public long countEmpByLike(Emp emp) { String sql = "SELECT COUNT(*) FROM emp WHERE ename LIKE ? OR job LIKE ?"; try (Connection con = JdbcUtils.getConnection(); PreparedStatement ps = con.prepareStatement(sql)) { // Set parameters with wildcards for the LIKE clause ps.setString(1, "%" + emp.geteName() + "%"); ps.setString(2, "%" + emp.getJob() + "%"); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { return rs.getLong(1); } } } catch (SQLException e) { // Log the exception using a logging framework in production code e.printStackTrace(); } return 0L; } }
- 编写服务层接口
package com.pyb.service; /** * @version 1.0 * @Author 彭彦彬 * @Date 2024/12/25 14:22 * @注释 */ import com.pyb.pojo.Emp; import java.sql.SQLException; import java.util.List; public interface EmpService { List<Emp> selectEmpByLike(Emp emp, int page, int limit) throws SQLException; long countEmpByLike(Emp emp) throws SQLException; }
- 编写服务层实现类
package com.pyb.service.serviceImpl; import com.pyb.dao.EmpDao; import com.pyb.dao.daoImpl.EmpDaoImpl; import com.pyb.pojo.Emp; import com.pyb.service.EmpService; import java.sql.SQLException; import java.util.List; public class EmpServiceImpl implements EmpService { private final EmpDao empDao = new EmpDaoImpl(); @Override public List<Emp> selectEmpByLike(Emp emp, int page, int limit) throws SQLException { return empDao.selectEmpByLike(emp, page, limit); } @Override public long countEmpByLike(Emp emp) throws SQLException { return empDao.countEmpByLike(emp); } }
- 编写控制层实现页面控制
package com.pyb.controller; import com.fasterxml.jackson.databind.ObjectMapper; import com.pyb.service.EmpService; import com.pyb.pojo.Emp; import com.pyb.service.serviceImpl.EmpServiceImpl; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; @WebServlet("/api/likeEmp") public class EmpLikeServlet extends HttpServlet { private final EmpService empService = new EmpServiceImpl(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { handleRequest(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { handleRequest(req, resp); } private void handleRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { // 处理请求编码 req.setCharacterEncoding("utf-8"); resp.setContentType("application/json;charset=UTF-8"); resp.setHeader("Access-Control-Allow-Origin", "*"); // 生产环境中应限制到具体域名 resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); resp.setHeader("Access-Control-Max-Age", "3600"); resp.setHeader("Access-Control-Allow-Headers", "Content-Type"); // 解析分页参数 int page = Integer.parseInt(req.getParameter("page") != null ? req.getParameter("page") : "1"); int limit = Integer.parseInt(req.getParameter("limit") != null ? req.getParameter("limit") : "2"); // 解析检索参数 String ename = req.getParameter("ename"); String job = req.getParameter("job"); // 调用Service层 List<Emp> list = empService.selectEmpByLike(new Emp(ename, job), page, limit); long totalUsers = empService.countEmpByLike(new Emp(ename, job)); // 构建响应对象 Map<String, Object> responseData = new HashMap<>(); responseData.put("users", list); responseData.put("total", totalUsers); responseData.put("page", page); responseData.put("limit", limit); if (ename != null) responseData.put("ename", ename); if (job != null) responseData.put("job", job); ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(resp.getWriter(), responseData); } catch (SQLException e) { throw new RuntimeException(e); } } }
启动服务部署到tomcat,用postman测试接口
http://localhost:8080/api/likeEmp?ename=a
- 测试结果
4.编写前端页面,实现前后端数据交互
- html页面
<template> <div class="employee-manager"> <!-- 现有的表格和分页组件 --> <el-card class="box-card"> <template #header> <div class="card-header"> <span>员工列表</span> <!-- 检索框 --> <el-input v-model="searchEname" placeholder="请输入姓名" style="width: 200px; margin-right: 10px;"></el-input> <el-input v-model="searchJob" placeholder="请输入岗位" style="width: 200px; margin-right: 10px;"></el-input> <el-button type="primary" @click="fetchData">搜索</el-button> <el-button type="info" @click="resetSearch">重置</el-button> <el-button type="primary" @click="openAddEmployeeDialog">添加员工</el-button> </div> </template> <el-table :data="paginatedData" style="width: 100%; margin-top: 20px;" stripe> <el-table-column prop="empNo" label="ID" width="100" /> <el-table-column prop="eName" label="姓名" width="100" /> <el-table-column prop="job" label="岗位" width="100" /> <el-table-column prop="mgr" label="上级编号" /> <el-table-column prop="hireDate" label="入职日期" width="200"/> <el-table-column prop="sal" label="月薪" width="100"/> <el-table-column prop="comm" label="奖金" /> <el-table-column prop="deptNo" label="部门编号" /> <el-table-column fixed="right" label="操作" width="180"> <template #default="scope"> <el-button size="small" type="danger" @click="deleteEmployee(scope.row.empNo)">删除</el-button> </template> </el-table-column> </el-table> <el-pagination layout="total, sizes, prev, pager, next, jumper" :total="totalItems" :page-size="pageSize" :current-page="currentPage" @size-change="handleSizeChange" @current-change="handleCurrentChange" :page-sizes="[3, 6, 9, 12]" style="margin-top: 20px;" > </el-pagination> </el-card> <!-- 添加员工对话框 --> <el-dialog v-model="dialogVisible" title="添加员工" width="30%"> <el-form :model="employeeForm" label-width="100px" class="add-employee-form"> <el-form-item label="ID"> <el-input v-model="employeeForm.id" placeholder="请输入ID"></el-input> </el-form-item> <el-form-item label="姓名"> <el-input v-model="employeeForm.name" placeholder="请输入姓名"></el-input> </el-form-item> <el-form-item label="职位"> <el-input v-model="employeeForm.position" placeholder="请输入职位"></el-input> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="closeDialog">取消</el-button> <el-button type="primary" @click="addEmployee">确认添加</el-button> </span> </template> </el-dialog> </div> </template>
- css样式页面
<style scoped> .employee-manager { padding: 20px; } .box-card { width: 100%; } .card-header { display: flex; justify-content: space-between; align-items: center; } .add-employee-form { max-width: 400px; margin: auto; } .el-table { border-radius: 8px; overflow: hidden; } .el-pagination { text-align: center; } .dialog-footer { text-align: right; } </style>
- 和后台交互的script代码
<script lang="js" setup> import { ref, onMounted, computed } from 'vue'; import axios from 'axios'; import { ElMessage } from 'element-plus'; // 局部引入 ElMessage const tableData = ref([]); // 使用 ref 创建响应式数据源 const totalItems = ref(0); const currentPage = ref(1); const pageSize = ref(3); // 表单数据模型 const employeeForm = ref({ id: '', name: '', position: '' }); // 对话框可见性 const dialogVisible = ref(false); // 检索条件 const searchEname = ref(''); const searchJob = ref(''); // 计算属性,用于根据当前页码和每页大小获取分页后的数据 const paginatedData = computed(() => { const start = (currentPage.value - 1) * pageSize.value; const end = start + pageSize.value; return tableData.value; }); const fetchData = async () => { try { const response = await axios.get('http://localhost:8080/api/likeEmp', { params: { page: currentPage.value, limit: pageSize.value, ename: searchEname.value, job: searchJob.value } }); const { users, total } = response.data; tableData.value = users.map(user => ({ ...user, id: user.id, name: user.name, position: user.position })); totalItems.value = total; // 更新总条目数 } catch (error) { console.error('Error fetching data:', error); } }; onMounted(() => { fetchData(); // 组件挂载时自动加载数据 }); const handleSizeChange = (newSize) => { pageSize.value = newSize; fetchData(); }; const handleCurrentChange = (newPage) => { currentPage.value = newPage; fetchData(); }; // 打开添加员工对话框的方法 const openAddEmployeeDialog = () => { dialogVisible.value = true; }; // 关闭对话框的方法 const closeDialog = () => { dialogVisible.value = false; Object.assign(employeeForm.value, { id: '', name: '', position: '' }); }; // 添加员工的方法 const addEmployee = async () => { try { const response = await axios.post('http://localhost:8080/api/emp', employeeForm.value, { headers: { 'Content-Type': 'application/json' } }); console.log('Employee added successfully:', response.data); // 关闭对话框并清空表单 closeDialog(); // 刷新表格数据 fetchData(); } catch (error) { console.error('Error adding employee:', error); } }; // 删除员工的方法 const deleteEmployee = async (empNo) => { try { const response = await axios.delete(`http://localhost:8080/api/delEmp`, { params: { empNo: empNo } }); console.log('Employee deleted successfully:', response.data.message); ElMessage({ message: response.data.message, type: response.data.success ? 'success' : 'error' }); // 刷新表格数据 fetchData(); } catch (error) { console.error('Error deleting employee:', error); ElMessage({ message: '删除员工时出错', type: 'error' }); } }; // 重置检索条件的方法 const resetSearch = () => { searchEname.value = ''; searchJob.value = ''; fetchData(); }; </script>
- 实现效果