这篇文章的避雷点:不涉及知识讲解只有操作,所以没有java基础和,javaweb基础和前端基础的兄弟请谨慎考虑以这篇文章来学习前后端分离,当然兄弟可以结合ai来学习这篇文章的知识点。
这篇文章所使用的软件及环境条件:mysql 8.0.32 , node.js v20.17.0,navicat 16.1.9,
idea 2024.3.2旗舰版 , Vue @vue/cli 5.0.8,postman
这文章灵感:是结合程序员青哥的教学项目,bilibili视频 《【 免费学习】1天学会SpringBoot3+Vue3实战项目开发,手把手带你做完整的前后端分离项目,适合计算机毕业设计、实习项目、Java、Vue编程练手项目**》** 和 我自身的知识储备所编写的学习笔记
后端项目位置: Admin/zwy_manager_back_v1
前端项目地址:Admin/zwy_manager_up_v1
1.后端项目
1.1数据库搭建
新建一个数据库

将下面sql执行
sql
/*
Navicat Premium Data Transfer
Source Server : javaEE
Source Server Type : MySQL
Source Server Version : 80032 (8.0.32)
Source Host : localhost:3306
Source Schema : zwy
Target Server Type : MySQL
Target Server Version : 80032 (8.0.32)
File Encoding : 65001
Date: 05/04/2025 11:05:52
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for employee
-- ----------------------------
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`name` char(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`gender` enum('男','女') CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '男',
`title` char(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`birthday` date NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1005 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of employee
-- ----------------------------
INSERT INTO `employee` VALUES (1001, '张三', '男', '高级工程师', '1985-01-01');
INSERT INTO `employee` VALUES (1002, '李四', '女', '助工', '1995-01-01');
INSERT INTO `employee` VALUES (1003, '王五', '男', '工程师', '1988-11-11');
INSERT INTO `employee` VALUES (1004, '赵六', '男', '工程师', '1988-12-12');
SET FOREIGN_KEY_CHECKS = 1;
1.2后端项目搭建
1.2.1使用idea内置的spring initializr创建项目


1.2.2项目的基本结构

1.2.2.1数据库连接测试
在application.properties中配置数据库(注意修改你的数据库名称和你mysql的用户和密码)
sql
spring.application.name=zwy_manager_back_v1
# 数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/zwy?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123456
在ZwyManagerBackV1ApplicationTests.java 编写数据库连接测试方法
java
@SpringBootTest
class ZwyManagerBackV1ApplicationTests {
@Resource
private DataSource dataSource;
@Test
void contextLoads() {
}
@Test
void testDataSource() throws Exception {
System.out.println(dataSource.getClass().getName());
System.out.println(dataSource.getConnection());
}
}
正确测试结果(如果没有成功请仔细检查application.properties中配置数据库)

1.2.2.2创建实体类
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/entity
名称:Employee
sql
@Data
public class Employee {
private Integer id;
private String name;
private String gender;
private String title;
private Date birthday;
}
1.3使用mybatis对employee表进行增删改查
1.3.1配置端口号和mybatis实体和xml的映射
在application.properties中添加
sql
# 端口号
server.port=9999
#配置mybatis实体和xml映射
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
1.3.2编写mapper接口和它的xml映射文件(持久层)
1.3.2.1编写mapper接口
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/mapper
名称:EmployeeMapper
sql
@Mapper
public interface EmployeeMapper {
int insert(Employee employee);
int deleteById(Integer id);
int update(Employee employee);
Employee selectById(Integer id);
List<Employee> selectAll();
}
1.3.2.2编写xml映射文件
位置:src/main/resources/mapper
名称:EmployeeMapper.xml
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.cdp.zwy.zwy_manager_back_v1.mapper.EmployeeMapper">
<resultMap id="employeeResultMap" type="com.cdp.zwy.zwy_manager_back_v1.entity.Employee">
</resultMap>
<insert id="insert" parameterType="com.cdp.zwy.zwy_manager_back_v1.entity.Employee">
insert into employee(name,gender,title,birthday) values(#{name},#{gender},#{title},#{birthday})
</insert>
<delete id="deleteById" parameterType="int">
delete from employee where id=#{id}
</delete>
<update id="update" parameterType="com.cdp.zwy.zwy_manager_back_v1.entity.Employee">
update employee set name=#{name},gender=#{gender},title=#{title},birthday=#{birthday} where id=#{id}
</update>
<select id="selectById" parameterType="int" resultMap="employeeResultMap">
select * from employee where id=#{id}
</select>
<select id="selectAll" resultMap="employeeResultMap">
select * from employee
</select>
</mapper>
1.3.3编写sevice层调用mapper接口(业务层)
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/service
名称:EmployeeService
java
@Service
public class EmployeeService {
@Resource
private EmployeeMapper employeeMapper;
public int add(Employee employee) {
int row = employeeMapper.insert(employee);
if(row!=1){
throw new RuntimeException("添加失败");
}
return row;
}
public int deleteById(Integer id) {
int row = employeeMapper.deleteById(id);
if(row!=1){
throw new RuntimeException("删除失败");
}
return row;
}
public int modify(Employee employee) {
int row = employeeMapper.update(employee);
if(row!=1){
throw new RuntimeException("更新失败");
}
return row;
}
public Employee findById(Integer id) {
return employeeMapper.selectById(id);
}
public List<Employee> findAll() {
return employeeMapper.selectAll();
}
}
1.3.4编写controller层(控制层 api)
控制层调用业余层
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/controller
名称:EmployeeController
java
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Resource
private EmployeeService employeeService;
@PostMapping("/add")
public int add(@RequestBody Employee employee){
return employeeService.add(employee);
}
@GetMapping("/findAll")
public List<Employee> findAll(){
return employeeService.findAll();
}
@GetMapping("/findById/{id}")
public Employee findById(@PathVariable Integer id){
return employeeService.findById(id);
}
@DeleteMapping("/deleteById/{id}")
public int deleteById(@PathVariable Integer id){
return employeeService.deleteById(id);
}
@PutMapping("/modify")
public int modify(@RequestBody Employee employee){
return employeeService.modify(employee);
}
}
1.3.4测试接口层(控制层)
1.3.4.1浏览器测试Get请求方式的API
employee表数据

http://localhost:9999/employee/findAll

http://localhost:9999/employee/findById/1001

1.3.4.2postman测试delete,put,post请求方式的API(或者在API测试工具)
java
localhost:9999/employee/deleteById/1004


java
localhost:9999/employee/add


XML
localhost:9999/employee/modify


到这里,你已经掌握了 MyBatis 对一张表的增删改查操作,但这还不够。虽然上面的代码实现了基本功能,但仍存在一些不足至少有以下两点:
第一点:接口返回值不够规范:
例如,find 方法返回实体对象或对象列表,增删改操作返回影响行数。这种返回值方式在前后端分离的项目中不够统一,我们需要定义一个通用的返回对象,便于前端处理。
第二点:异常处理不够完善:
当前代码缺乏自定义异常处理机制,这会导致问题定位困难。我们需要引入自定义异常,以便快速定位和处理问题。
通过优化这两点,我们可以让代码更加规范、健壮,并更好地支持前后端分离的开发模式。
1.4接口层的返回统一对象并且实施异常处理
1.4.1编写Result统一返回类
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/common
名称:Result
java
@Data
public class Result {
private String code;
private String msg;
private Object data;
public Result() {
}
public Result(String code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static Result success() {
return new Result("200", "success", null);
}
public static Result success(Object data) {
return new Result("200", "success", data);
}
public static Result error() {
return new Result("500", "请求失败", null);
}
public static Result error(String code,String msg) {
return new Result(code, msg, null);
}
}
1.4.2编写错误码枚举类
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/common
名称:ErrorCode
java
public enum ErrorCode {
NOT_DATA("10000","没有数据"),
EMPLOYEE_NOT_FOUND("10001", "该员工不存在"),
EMPLOYEE_ADD_ERROR("10002", "添加员工失败"),
EMPLOYEE_DELETE_ERROR("10003", "删除员工失败"),
EMPLOYEE_MODIFY_ERROR("10004", "修改员工失败");
private final String code;
private final String msg;
ErrorCode(String code, String msg) {
this.code = code;
this.msg = msg;
}
public String getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
1.4.3编写业务层的异常处理类
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/common
名称:EmployeeServiceException
java
public class EmployeeServiceException extends RuntimeException {
private final ErrorCode errorCode;
public EmployeeServiceException(ErrorCode errorCode) {
super(errorCode.getMsg());
this.errorCode = errorCode;
}
public ErrorCode getErrorCode() {
return errorCode;
}
}
1.4.4修改业务层使用异常处理
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/service
名称:EmployeeService
java
@Service
public class EmployeeService {
@Resource
private EmployeeMapper employeeMapper;
public int add(Employee employee) {
int row = employeeMapper.insert(employee);
if(row!=1){
throw new EmployeeServiceException(ErrorCode.EMPLOYEE_ADD_ERROR);
}
return row;
}
public int deleteById(Integer id) {
Employee employee = employeeMapper.selectById(id);
if (employee == null){
throw new EmployeeServiceException(ErrorCode.EMPLOYEE_NOT_FOUND);
}
int row = employeeMapper.deleteById(id);
if(row!=1){
throw new EmployeeServiceException(ErrorCode.EMPLOYEE_DELETE_ERROR);
}
return row;
}
public int modify(Employee employee) {
Employee employee1 = employeeMapper.selectById(employee.getId());
if (employee1 == null){
throw new EmployeeServiceException(ErrorCode.EMPLOYEE_NOT_FOUND);
}
int row = employeeMapper.update(employee);
if(row!=1){
throw new EmployeeServiceException(ErrorCode.EMPLOYEE_MODIFY_ERROR);
}
return row;
}
public Employee findById(Integer id) {
Employee employee = employeeMapper.selectById(id);
if(employee == null){
throw new EmployeeServiceException(ErrorCode.EMPLOYEE_NOT_FOUND);
}
return employee;
}
public List<Employee> findAll() {
List<Employee> employees = employeeMapper.selectAll();
if(employees.size() == 0){
throw new EmployeeServiceException(ErrorCode.NOT_DATA);
}
return employees;
}
}
1.4.5修改控制层(接口层)的方法返回值
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/controller
名称:EmployeeController
java
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Resource
private EmployeeService employeeService;
@PostMapping("/add")
public Result add(@RequestBody Employee employee){
return Result.success(employeeService.add(employee));
}
@GetMapping("/findAll")
public Result findAll(){
return Result.success(employeeService.findAll());
}
@GetMapping("/findById/{id}")
public Result findById(@PathVariable Integer id){
return Result.success(employeeService.findById(id));
}
@DeleteMapping("/deleteById/{id}")
public Result deleteById(@PathVariable Integer id){
return Result.success(employeeService.deleteById(id));
}
@PutMapping("/modify")
public Result modify(@RequestBody Employee employee){
return Result.success(employeeService.modify(employee));
}
}
1.4.6编写全局异常处理类
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/exception
名称:GlobalExceptionHandler
java
@ControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(EmployeeServiceException.class)
public ResponseEntity<Result> handleEmployeeServiceException(EmployeeServiceException ex) {
// 记录日志
log.error("业务异常: 错误码={}, 错误信息={}", ex.getErrorCode().getCode(), ex.getErrorCode().getMsg(), ex);
// 返回统一错误响应
Result response = new Result(
ex.getErrorCode().getCode(),
ex.getErrorCode().getMsg(),
null
);
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
}
还需要导入两个maven依赖坐标,在pom.xml<dependencies></dependencies>标签里加
XML
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.1.0-alpha1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.18</version>
<scope>compile</scope>
</dependency>
1.4.7测试修改后是够可以正常使用
许多bug是在更改中产生的,当然存在bug我肯定会改上面的代码,所以你是看不到bug的哈哈哈
依旧测试api,我这里测试和1.3.4是一样的操作我在重复一编保证逻辑的完整性,你如果很强可以不看这个自己尝试。
1.4.7.1浏览器测试Get请求方式的API
employee表数据

http://localhost:9999/employee/findAll

http://localhost:9999/employee/findById/1001

这里我只展示一个业务层的异常抛出哈,其他的异常触发你们自己去告一哈。
查询一个没有的员工
java
http://localhost:9999/employee/findById/100

1.4.7.2postman测试delete,put,post请求方式的API(或者在API测试工具)
java
localhost:9999/employee/deleteById/1005


java
localhost:9999/employee/add


XML
localhost:9999/employee/modify


1.5加入分页查询
1.5.1maven引入pageHelper
位置:pom.xml <dependencies></dependencies>标签里
XML
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
1.5.2在业务层中添加分页查询方法
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/service/EmployeeService.java
java
/**
* 分页查询
* @param pageNum
* @param pageSize
* @return
*/
public PageInfo<Employee> selectPage(Integer pageNum, Integer pageSize) {
PageHelper.startPage(pageNum,pageSize);
List<Employee> list = employeeMapper.selectAll();
return PageInfo.of(list);
}
1.5.3在控制层调用该方法
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/controller/EmployeeController.java
java
@GetMapping("/selectPage")
public Result selectPage(@RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "2") Integer pageSize){
return Result.success(employeeService.selectPage(pageNum,pageSize));
}
1.5.4启动项目测试该接口
java
http://localhost:9999/employee/selectPage

1.5.5前端涉及到一个根据员工名称模糊分页查询,考虑到拓展直接传入Employee类型对象
所以要添加一个api接口
接口层:
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/controller/EmployeeController.java
java
@PostMapping("/findByName")
public Result findByName(@RequestBody Employee employee, @RequestParam(defaultValue = "1") Integer pageNum, @RequestParam(defaultValue = "2") Integer pageSize){
return Result.success(employeeService.findByName(pageNum, pageSize,employee.getName()));
}
业务层:
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/service/EmployeeService.java
java
public PageInfo<Employee> findByName(Integer pageNum, Integer pageSize, String name) {
PageHelper.startPage(pageNum,pageSize);
List<Employee> list = employeeMapper.selectFuzzy(name);
return PageInfo.of(list);
}
持久层:
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/mapper/EmployeeMapper.java
java
List<Employee> selectFuzzy(String name);
位置:src/main/resources/mapper/EmployeeMapper.xml
XML
<select id="selectFuzzy" resultMap="employeeResultMap">
select * from employee where 1 = 1
and
<if test="#{name}!=null">
name like concat('%',#{name},'%')
</if>
</select>
测试该接口

1.6跨域请求
我们知道后端项目和前端项目是分离的,后端项目启动占用一个端口,前端项目启动占用一个端口
这是前端的一个按钮可能会调用有后端的一个api结构,这是就是跨域请求。这个项目是用的axios发送的请求,跨域配置在后端配置
位置:src/main/java/com/cdp/zwy/background_manager_back/config/CorsConfig.java
java
@Configuration
public class CorsFilter {
@Bean
public CorsFilter corsFiler(){
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
//1.设置访问源地址(任意地址可以访问,这里可以想象如果两台pc端链接是否可以直接在pc1部署后端,pc2部署前端)
corsConfiguration.addAllowedOrigin("*");
//2.设置访问源请求头
corsConfiguration.addAllowedHeader("*");
//3.设置访问源请求方法
corsConfiguration.addAllowedMethod("*");
//4.对接口配置跨域设置
source.registerCorsConfiguration("/**",corsConfiguration);
return new CorsFilter();
}
1.7往数据库添加点数据
注意id不能重复,你可也先将数据全删掉再添加数据
sql
use zwy
INSERT INTO `employee` VALUES (1001, '赵敏', '女', '资深数据分析师', '1985-03-15');
INSERT INTO `employee` VALUES (1002, '孙涛', '男', '初级程序员', '1998-06-20');
INSERT INTO `employee` VALUES (1003, '周杰', '男', '高级产品经理', '1982-09-30');
INSERT INTO `employee` VALUES (1004, '吴静', '女', '资深UI设计师', '1987-04-22');
INSERT INTO `employee` VALUES (1005, '郑强', '男', '初级运维工程师', '1999-01-10');
INSERT INTO `employee` VALUES (1006, '王丽', '女', '高级市场专员', '1989-07-18');
INSERT INTO `employee` VALUES (1007, '刘洋', '男', '资深架构师', '1978-11-25');
INSERT INTO `employee` VALUES (1008, '陈静', '女', '初级文案策划', '1996-03-05');
INSERT INTO `employee` VALUES (1009, '杨光', '男', '高级销售经理', '1984-05-12');
INSERT INTO `employee` VALUES (1010, '李娜', '女', '资深人力资源专员', '1986-08-08');
INSERT INTO `employee` VALUES (1011, '张伟', '男', '初级财务助理', '1997-02-28');
INSERT INTO `employee` VALUES (1012, '赵丽', '女', '高级技术专家', '1983-10-01');
INSERT INTO `employee` VALUES (1013, '孙强', '男', '资深测试工程师', '1980-07-20');
INSERT INTO `employee` VALUES (1014, '周梅', '女', '初级运营专员', '1995-04-15');
INSERT INTO `employee` VALUES (1015, '吴涛', '男', '高级项目经理', '1981-09-10');
INSERT INTO `employee` VALUES (1016, '郑丽', '女', '资深法律顾问', '1985-03-05');
INSERT INTO `employee` VALUES (1017, '王强', '男', '初级技术支持', '1998-06-30');
INSERT INTO `employee` VALUES (1018, '刘静', '女', '高级市场分析师', '1987-08-12');
INSERT INTO `employee` VALUES (1019, '陈伟', '男', '资深软件工程师', '1979-11-05');
INSERT INTO `employee` VALUES (1020, '杨丽', '女', '初级行政专员', '1996-02-20');
INSERT INTO `employee` VALUES (1021, '李伟', '男', '高级数据科学家', '1984-07-10');
INSERT INTO `employee` VALUES (1022, '张丽', '女', '资深前端工程师', '1986-01-18');
INSERT INTO `employee` VALUES (1023, '赵伟', '男', '初级后端工程师', '1997-05-25');
INSERT INTO `employee` VALUES (1024, '孙丽', '女', '高级UI/UX设计师', '1983-09-30');
INSERT INTO `employee` VALUES (1025, '周伟', '男', '资深产品经理', '1980-03-15');
INSERT INTO `employee` VALUES (1026, '吴丽', '女', '初级数据分析师', '1995-07-20');
INSERT INTO `employee` VALUES (1027, '郑伟', '男', '高级技术顾问', '1981-10-01');
INSERT INTO `employee` VALUES (1028, '王丽', '女', '资深市场专员', '1985-04-15');
INSERT INTO `employee` VALUES (1029, '刘伟', '男', '初级程序员', '1998-08-10');
INSERT INTO `employee` VALUES (1030, '陈丽', '女', '高级人力资源经理', '1987-02-28');
INSERT INTO `employee` VALUES (1031, '杨伟', '男', '资深运维工程师', '1979-06-20');
INSERT INTO `employee` VALUES (1032, '李丽', '女', '初级文案策划', '1996-01-12');
INSERT INTO `employee` VALUES (1033, '张伟', '男', '高级销售代表', '1984-09-05');
INSERT INTO `employee` VALUES (1034, '赵丽', '女', '资深法律顾问', '1986-03-18');
INSERT INTO `employee` VALUES (1035, '孙伟', '男', '初级技术支持', '1997-07-25');
INSERT INTO `employee` VALUES (1036, '周丽', '女', '高级市场分析师', '1983-11-30');
INSERT INTO `employee` VALUES (1037, '吴伟', '男', '资深软件工程师', '1980-05-10');
INSERT INTO `employee` VALUES (1038, '郑丽', '女', '初级行政专员', '1995-09-12');
INSERT INTO `employee` VALUES (1039, '王伟', '男', '高级数据科学家', '1981-08-05');
INSERT INTO `employee` VALUES (1040, '刘丽', '女', '资深前端工程师', '1987-02-18');
INSERT INTO `employee` VALUES (1041, '陈伟', '男', '初级后端工程师', '1998-04-20');
INSERT INTO `employee` VALUES (1042, '杨丽', '女', '高级UI/UX设计师', '1984-10-30');
INSERT INTO `employee` VALUES (1043, '李伟', '男', '资深产品经理', '1980-06-15');
INSERT INTO `employee` VALUES (1044, '张丽', '女', '初级数据分析师', '1996-08-10');
INSERT INTO `employee` VALUES (1045, '赵伟', '男', '高级技术顾问', '1981-12-01');
INSERT INTO `employee` VALUES (1046, '孙丽', '女', '资深市场专员', '1985-05-15');
INSERT INTO `employee` VALUES (1047, '周伟', '男', '初级程序员', '1998-09-20');
INSERT INTO `employee` VALUES (1048, '吴丽', '女', '高级人力资源经理', '1987-03-28');
INSERT INTO `employee` VALUES (1049, '郑伟', '男', '资深运维工程师', '1979-07-20');
INSERT INTO `employee` VALUES (1050, '王丽', '女', '初级文案策划', '1996-02-12');
INSERT INTO `employee` VALUES (1051, '刘伟', '男', '高级销售代表', '1984-10-05');
INSERT INTO `employee` VALUES (1052, '陈丽', '女', '资深法律顾问', '1986-04-18');
INSERT INTO `employee` VALUES (1053, '杨伟', '男', '初级技术支持', '1997-08-25');
INSERT INTO `employee` VALUES (1054, '李丽', '女', '高级市场分析师', '1983-12-30');
INSERT INTO `employee` VALUES (1055, '张伟', '男', '资深软件工程师', '1980-07-10');
INSERT INTO `employee` VALUES (1056, '赵丽', '女', '初级行政专员', '1995-10-12');
INSERT INTO employee VALUES (1057, '孙伟', '男', '高级数据科学家', '1981-09-05');
INSERT INTO employee VALUES (1058, '周丽', '女', '资深前端工程师', '1987-03-18');
INSERT INTO employee VALUES (1059, '吴伟', '男', '初级后端工程师', '1998-05-20');
INSERT INTO employee VALUES (1060, '郑丽', '女', '高级UI/UX设计师', '1984-11-30');
INSERT INTO employee VALUES (1061, '王伟', '男', '资深产品经理', '1980-08-15');
INSERT INTO employee VALUES (1062, '刘丽', '女', '初级数据分析师', '1996-09-10');
INSERT INTO employee VALUES (1063, '陈伟', '男', '高级技术顾问', '1981-10-01');
INSERT INTO employee VALUES (1064, '杨丽', '女', '资深市场专员', '1985-06-15');
INSERT INTO employee VALUES (1065, '李伟', '男', '初级程序员', '1998-10-20');
INSERT INTO employee VALUES (1066, '张丽', '女', '高级人力资源经理', '1987-04-28');
INSERT INTO employee VALUES (1067, '赵伟', '男', '资深运维工程师', '1979-08-20');
INSERT INTO employee VALUES (1068, '孙丽', '女', '初级文案策划', '1996-03-12');
INSERT INTO employee VALUES (1069, '周伟', '男', '高级销售代表', '1984-11-05');
INSERT INTO employee VALUES (1070, '吴丽', '女', '资深法律顾问', '1986-05-18');
INSERT INTO employee VALUES (1071, '郑伟', '男', '初级技术支持', '1997-09-25');
INSERT INTO employee VALUES (1072, '王丽', '女', '高级市场分析师', '1983-01-30');
INSERT INTO employee VALUES (1073, '刘伟', '男', '资深软件工程师', '1980-08-10');
INSERT INTO employee VALUES (1074, '陈丽', '女', '初级行政专员', '1995-11-12');
INSERT INTO employee VALUES (1075, '杨伟', '男', '高级数据科学家', '1981-10-05');
INSERT INTO employee VALUES (1076, '李丽', '女', '资深前端工程师', '1987-04-18');
INSERT INTO employee VALUES (1077, '张伟', '男', '初级后端工程师', '1998-06-20');
INSERT INTO employee VALUES (1078, '赵丽', '女', '高级UI/UX设计师', '1984-12-30');
INSERT INTO employee VALUES (1079, '孙伟', '男', '资深产品经理', '1980-09-15');
INSERT INTO employee VALUES (1080, '周丽', '女', '初级数据分析师', '1996-10-10');
INSERT INTO employee VALUES (1081, '吴伟', '男', '高级技术顾问', '1981-11-01');
INSERT INTO employee VALUES (1082, '郑丽', '女', '资深市场专员', '1985-07-15');
INSERT INTO employee VALUES (1083, '王伟', '男', '初级程序员', '1998-11-20');
INSERT INTO employee VALUES (1084, '刘丽', '女', '高级人力资源经理', '1987-05-28');
INSERT INTO employee VALUES (1085, '陈伟', '男', '资深运维工程师', '1979-09-20');
INSERT INTO employee VALUES (1086, '杨丽', '女', '初级文案策划', '1996-04-12');
INSERT INTO employee VALUES (1087, '李伟', '男', '高级销售代表', '1984-12-05');
INSERT INTO employee VALUES (1088, '张丽', '女', '资深法律顾问', '1986-06-18');
INSERT INTO employee VALUES (1089, '赵伟', '男', '初级技术支持', '1997-10-25');
INSERT INTO employee VALUES (1090, '孙丽', '女', '高级市场分析师', '1983-02-30');
INSERT INTO employee VALUES (1091, '周伟', '男', '资深软件工程师', '1980-09-10');
INSERT INTO employee VALUES (1092, '吴丽', '女', '初级行政专员', '1995-12-12');
INSERT INTO employee VALUES (1093, '郑伟', '男', '高级数据科学家', '1981-11-05');
INSERT INTO employee VALUES (1094, '王丽', '女', '资深前端工程师', '1987-05-18');
INSERT INTO employee VALUES (1095, '刘伟', '男', '初级后端工程师', '1998-07-20');
INSERT INTO employee VALUES (1096, '陈丽', '女', '高级UI/UX设计师', '1984-01-30');
INSERT INTO employee VALUES (1097, '杨伟', '男', '资深产品经理', '1980-10-15');
INSERT INTO employee VALUES (1098, '李丽', '女', '初级数据分析师', '1996-11-10');
INSERT INTO employee VALUES (1099, '张伟', '男', '高级技术顾问', '1981-12-01');
INSERT INTO employee VALUES (1100, '赵丽', '女', '资深市场专员', '1985-08-15');
1.8添加批量删除
控制层:
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/controller/EmployeeController.java
java
@DeleteMapping("/deleteBatch")
public Result deleteBatch(@RequestBody List<Integer> ids){
return Result.success(employeeService.deleteBatch(ids));
}
业务层:
位置:src/main/java/com/cdp/zwy/zwy_manager_back_v1/service/EmployeeService.java
java
public int deleteBatch(List<Integer> ids) {
int rows = 0;
for (Integer id : ids) {
Employee employee = employeeMapper.selectById(id);
if (employee == null){
throw new EmployeeServiceException(ErrorCode.EMPLOYEE_NOT_FOUND);
}
int row = employeeMapper.deleteById(id);
if(row!=1){
throw new EmployeeServiceException(ErrorCode.EMPLOYEE_DELETE_ERROR);
}
rows++;
}
return rows;
}
测试

2.前端项目
2.1项目创建
2.1.1使用cmd创建vue项目
在文件资源管理器中打开你想创建位置路径
npm create vue@latest

选择只选择Route

依次执行以下命令

访问搭建好的vue项目

2.1.2瘦身vue项目
idea打开该项目,项目原始结构如下

瘦身后的项目结构

修改3个文件添加1个文件
名称:App.vue
位置:src/App.vue
html
<template>
<RouterView/>
</template>
名称:main.js
位置:src/main.js
html
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
名称:HelloWorld.vue
位置:src/views/HelloWorld.vue
html
<template>
<div>
<h1>Hello World</h1>
</div>
</template>
<script setup>
</script>
名称:index.js
位置:src/router/index.js
html
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'hello',
component: () => import('../views/HelloWorld.vue'),
},
],
})
export default router
2.1.3集成element-plus
下载element-plus依赖
npm install element-plus@

package-lock.json或package.json或node_modules查看是否引入

配置element-plus
位置:src/main.js
名称:main.js
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
app.use(ElementPlus)

测试element-plus是否配置好
新建视图
位置:src/views/Button.vue
名称:Button.vue
html
<template>
<div>
<el-button type="primary" @click="handleClick">按钮</el-button>
</div>
</template>
<script setup>
</script>
添加路由
位置:src/router/index.js
名称:index.js
javascript
{
path: '/button',
name: 'button',
component: () => import('../views/Button.vue'),
}

访问该视图

2.2视图搭建
一共有4个,404.vue,manager.vue,employeeOp.vue,home.vue
其中manager.vue(employeeOp.vue,home.vue) 是嵌套关系
404.vue是路由守卫
2.2.1 全局映入icon
位置:src/main.js
名称:main.js
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}

2.2.2导入所需要的图片和样式
位置:src/assets/global.css
名称:global.css
css
.card {
margin-top: 20px;
margin-left: 10px;
padding: 10px;
width: calc(100% - 40px);
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 4px;
color: #303133;
}
位置:src/assets/img.png
名称:img.png

位置:/assets/404.png
名称:404.png

2.2.3视图文件编写
位置:src/view/employeeDataOp.vue
名称:employeeDataOp.vue
html
<template>
<div >
<!-- 第一项 搜索框和重置按钮-->
<div class="card">
<el-input v-model="searchName" placeholder="请输入员工姓名" style="width: 200px;margin-right: 5px;" suffix-icon="Search"/>
<el-button type="primary">搜索</el-button>
<el-button type="warning">重置</el-button>
</div>
<!-- 第二项 常用操作 批量删除 添加员工-->
<div class="card">
<el-button type="primary">新建员工</el-button>
<el-button type="danger">批量删除</el-button>
</div>
<!-- 第三项 员工数据表格-->
<div class="card">
<el-table :data = "data.tableData" height="400" style="width: 100%;border: #7a7575 solid 1px">
<el-table-column prop="id" label="编号" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="gender" label="性别" />
<el-table-column prop="title" label="职位" />
<el-table-column prop="birthday" label="出生日期"/>
</el-table>
</div>
<!-- 第四项 分页组件-->
<div class="card">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
:small="small"
:disabled="disabled"
:background="background"
layout="total, sizes, prev, pager, next, jumper"
:total="400"
/>
</div>
</div>
</template>
<script setup>
import {reactive} from "vue";
const data = reactive({
tableData: [
{
id:1,
name:'张三',
gender:'男',
title:'高级工程师',
birthday:'1985-01-01'
},
],
})
</script>
位置:src/veiws/home.vue
名称:home.vue
html
<template>
<div>
员工管理系统首页
</div>
</template>
<script setup>
</script>
位置:src/veiws/manager.vue
名称:manager.vue
html
<template>
<div>
<!-- 顶部信息栏(logo 系统名 用户头像 用户名)开始 -->
<div style="height: 40px;background-color: aqua;display:flex;align-items:center;
">
<img src="../assets/img.png" style="width: 40px;margin-left: 20px">
<span style="margin-left: 10px;font-size: 20px;font-family: 新宋体;color: white">员工管理系统</span>
<div style="flex:1"></div>
<el-avatar src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png"/>
<span style="margin-left: 10px;margin-right:10px;font-size: 20px;font-family: 新宋体;color: white">泳</span>
</div>
<!-- 顶部信息栏(logo 系统名 用户头像 用户名)结束 -->
<!-- body部分开始-->
<div style="display: flex">
<!-- 左边导航栏开始-->
<div style="width: 140px;height: calc(100vh - 40px);border-right: #cdcdcd solid 1px">
<el-menu
router>
<el-menu-item index="/manager/home" >
<el-icon>
<HomeFilled />
</el-icon>
<span>首页</span>
</el-menu-item>
<el-menu-item index="/manager/employeeDataOp">
<el-icon><User /></el-icon>
<span>员工管理</span>
</el-menu-item>
</el-menu>
</div>
<!-- 左边导航栏结束-->
<!-- 右边数据域开始-->
<div style="width: calc(100% - 140px)">
<RouterView/>
</div>
<!-- 右边数据域结束-->
</div>
<!-- body部分结束-->
</div>
</template>
<script setup>
</script>
位置:src/view/404.vue
名称:404.vue
html
<template>
<div class="card" style="display:flex;align-items:center;">
<img src="@/assets/404.png" style="width: 100%;">
</div>
<div style="margin-top: 20px;">
<div style="text-align: center;">
<el-button type="primary" @click="backLatestPage">返回上一页</el-button>
</div>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
const backLatestPage = () => {
router.go(-1)
}
</script>
2.2.4路由修改
位置:src/router/index.js
名称:index.js
javascript
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'hello',
component: () => import('../views/HelloWorld.vue'),
},
{
path: '/button',
name: 'button',
component: () => import('../views/Button.vue'),
},
{
path:'/manager',
name:'manager',
component:()=>import('../views/Manager.vue'),
children:[
{
path:'/manager/employeeDataOp',
name:'employeeDataOp',
meta:{title:'员工数据操作'},
component:()=>import('../views/employeeDataOp.vue')
},
{
path:'/manager/home',
name:'home',
meta:{title:'首页'},
component:()=>import('../views/home.vue')
}
]
},
{
path:'/404',
name:'404',
meta:{title:'404'},
component:()=>import('../views/404.vue')
},
{
path:'/:pathMatch(.*)*',
redirect:'/404',
}
],
})
router.beforeEach((to,from,next)=>{
document.title=to.meta.title;
next()
})
export default router
2.2.4静态界面展示



2.3接口调用
2.3.1安装axios(发请求的工具)
npm install axios@latest

2.3.2编写request.js文件(处理请求)
位置:src/utils/request.js
javascript
const request = axios.create({
baseURL:'http://localhost:9999',//后台接口地址
timeout:5000 //请求超时设置
})
//request 拦截器
// 可以自请求发送前对请求做一些处理
request.interceptors.request.use(config => {
config.headers['Content-Type'] = 'application/json;charset=utf-8';
return config
},error => {
return Promise.reject(error)
});
//可以在接口响应后统一处理结果
request.interceptors.response.use(
response =>{
let res = response.data;
// 兼容服务器端返回的字符串数据
if(typeof res === 'string') {
res = res ? JSON.parse(res) : res
}
return res;
},
error => {
if(error.response.status === 404){
ElMessage.error('服务器未找到该接口')
}else if(error.response.status === 500){
ElMessage.error('服务器内部错误')
}else{
console.error(error.message)
}
return Promise.reject(error)
}
)
export default request
2.3.3修改employeeDataOp.vue
位置:src/views/employeeDataOp.vue
html
<template>
<div >
<!-- 第一项 搜索框和重置按钮-->
<div class="card">
<el-input v-model="data.searchName" placeholder="请输入员工姓名" style="width: 200px;margin-right: 5px;" suffix-icon="Search"/>
<el-button type="primary" @click="loadData()">搜索</el-button>
<el-button type="warning" @click="reset()">重置</el-button>
</div>
<!-- 第二项 常用操作 批量删除 添加员工-->
<div class="card">
<el-button type="primary" @click="switchAddDialog">新建员工</el-button>
<el-button type="danger" @click="deleteBatchMessageBox">批量删除</el-button>
</div>
<!-- 第三项 员工数据表格-->
<div class="card">
<el-table @selectionChange="handleSelectionChange" :data = "data.tableData" height="400" style="width: 100%;border: #7a7575 solid 1px">
<el-table-column type="selection" width="55" />
<el-table-column prop="id" label="编号" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="gender" label="性别" />
<el-table-column prop="title" label="职位" />
<el-table-column prop="birthday" label="出生日期"/>
<el-table-column fixed="right" label="操作" width="120">
<template #default="scope">
<el-button type="primary" @click="editRow(scope.row)" circle>
<el-icon><Edit /></el-icon>
</el-button>
<el-button type="danger" @click="deleteMessageBox(scope.row)" circle>
<el-icon><Delete /></el-icon>
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 第四项 分页组件-->
<div class="card">
<el-pagination
v-model:current-page="data.currentPage"
v-model:page-size="data.pageSize"
@current-change="loadData"
@size-change="loadData"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
v-model:total="data.total"
/>
</div>
<el-dialog
v-model="data.AddDialogVisible"
title="新建员工"
width="300"
align-center
>
<el-input v-model="data.employee.name" style="width: 240px;margin-bottom: 20px;" placeholder="请输入名称"></el-input>
<el-radio-group v-model="data.employee.gender" style="width: 240px;margin-bottom: 20px;">
<el-radio value="男" size="large" border>男</el-radio>
<el-radio value="女" size="large" border>女</el-radio>
</el-radio-group>
<el-input v-model="data.employee.title" style="width: 240px;margin-bottom: 20px;" placeholder="请输入职称"></el-input>
<el-date-picker
v-model="data.employee.birthday"
type="date"
placeholder="选择出生日期"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
<template #footer>
<div class="dialog-footer">
<el-button @click="switchAddDialog">取消</el-button>
<el-button type="primary" @click="save()">
确定
</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {reactive,ref} from "vue";
import request from "@/utils/request.js";
import {ElMessage,ElMessageBox} from "element-plus";
const res = ref();
const data = reactive({
AddDialogVisible:false,
tableData: [
],
currentPage:1,
pageSize:5,
searchName:'',
employee:{
id:0,
name:'',
gender:'',
title:'',
birthday:''
},
ids:[]
})
const loadData = () => {
const loadAll = () =>{
request.get('employee/selectPage', {
params: {
pageNum: data.currentPage,
pageSize: data.pageSize,
}
}).then(res=> {
data.tableData = res.data.list;
data.total = res.data.total;
console.log(res.data.list)
})
}
const loadByName = () =>{
request.post('employee/findByName',{
name:data.searchName,
},{ params: {
pageNum: data.currentPage,
pageSize: data.pageSize,
}}).then(res=>{
data.tableData = res.data.list;
data.total = res.data.total;
console.log(res.data.list)
})
}
data.searchName ? loadByName() :loadAll()
}
loadData();
const reset = () =>{
data.searchName = '';
loadData();
}
const switchAddDialog = () =>{
data.AddDialogVisible = data.AddDialogVisible ? false : true;
}
const editRow = (row) =>{
data.employee = row;
switchAddDialog();
//深拷贝,解决就算取消修改,数据还是被修改了的问题
data.employee = JSON.parse(JSON.stringify(row));
}
const save = () =>{
const update = () =>{
request.put('employee/modify',data.employee).then(res=>{
console.log(res);
if(res.code === '200'){
ElMessage.success('添加成功');
loadData();
switchAddDialog();
}else {
ElMessage.error(res.code + '/n' + res.msg);
}
})
}
const add = () =>{
request.post('employee/add',data.employee).then(res=>{
console.log(res);
if(res.code === '200'){
ElMessage.success('添加成功');
loadData();
switchAddDialog();
}else {
ElMessage.error(res.code + '/n' + res.msg);
}
})
}
data.employee.id != 0 ? update() : add();
}
const deleteOne = (row) =>{
request.delete(`employee/deleteById/${row.id}`).then(res=>{
if(res.code === '200'){
ElMessage.success('删除成功');
loadData();
}else {
ElMessage.error(res.code + '/n' + res.msg);
}
})
}
const handleSelectionChange = (rows) =>{
data.ids = rows.map(row => row.id);
console.log(data.ids);
}
const deleteBatch = () =>{
request.delete(`employee/deleteBatch`,{data:data.ids}).then(res=>{
if(res.code === '200'){
ElMessage.success('批量删除成功');
loadData();
}else {
ElMessage.error(res.code + '/n' + res.msg);
}
})
}
const deleteMessageBox = (row) =>{
ElMessageBox.confirm('此操作将永久删除该信息, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'danger',
}).then(() => {
deleteOne(row);
}).catch(() => {
ElMessage({
type: 'info',
message: '已取消删除',
});
});
}
const deleteBatchMessageBox = () =>{
if(data.ids.length === 0){
ElMessage.error('请选择要删除的数据');
return;
}
ElMessageBox.confirm('此操作将永久删除该信息, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'danger',
}).then(() => {
deleteBatch();
}).catch(() => {
ElMessage({
type: 'info',
message: '已取消删除',
});
});
}
</script>
我来解释也哈这个视图,
静态内容方面
分为四个部分对应代码四个<div>
第一个是搜索框
第二个是一些基础操作
第三个是表格
第四个是分页组件

还有一个对话框作用是添加或修改员工信息点击新建按钮这个对话框显示对应代码<el_dialog>标签

还有一个消息框当,进行删除操作时候提供一个缓冲,以免误删对应const deleteMassageBox,deleteBatchMassageBox.
