1. 软件开发和项目介绍 🍐
1.1 软件开发整体介绍 🍐
软件开发整体介绍
作为一名软件开发工程师,我们需要了解在软件开发过程中的开发流程, 以及软件开发过程中涉及到的岗位角色,角色的分工、职责, 并了解软件开发中涉及到的三种软件环境。那么这一小节,我们将从 三个方面,来整体上介绍一下软件开发。
软件开发流程 🍐

| 岗位/角色 | 职责/分工 |
|---|---|
| 项目经理 | 对整个项目负责,任务分配、把控进度 |
| 产品经理 | 进行需求调研,输出需求调研文档、产品原型等 |
| UI 设计师 | 根据产品原型输出界面效果图 |
| 架构师 | 项目整体架构设计、技术选型等 |
| 开发工程师 | 功能代码实现 |
| 测试工程师 | 编写测试用例,输出测试报告 |
| 运维工程师 | 软件环境搭建、项目上线 |
角色分工是在一个项目组中比较标准的角色分工, 但是在实际的项目中, 有一些项目组由于人员配置紧张,
可能并没有专门的架构师或测试人员, 这个时候可能需要有项目经理或者程序员兼任
软件环境 🍐

1). 开发环境(development)
我们作为软件开发人员,在开发阶段使用的环境,就是开发环境,一般外部用户无法访问 。
比如,我们在开发中使用的 MySQL 数据库和其他的一些常用软件,我们可以安装在本地, 也可以安装在一台专门的服务器中, 这些应用软件仅仅在软件开发过程中使用, 项目测试、上线时,我们不会使用这套环境了,这个环境就是开发环境。
2). 测试环境(testing)
当软件开发工程师,将项目的功能模块开发完毕,并且单元测试通过后,就需要将项目部署到测试服务器上,让测试人员对项目进行测试。那这台测试服务器就是专门给测试人员使用的环境, 也就是测试环境,用于项目测试,一般外部用户无法访问 。
3). 生产环境(production)
当项目开发完毕,并且由测试人员测试通过之后,就可以上线项目,将项目部署到线上环境,并正式对外提供服务, 这个线上环境也称之为生产环境。
总结
课堂作业
- 请回答软件的开发流程是什么?🎤
- 请回答软件开发过程中,有哪些角色,以及实际工作中这些角色都需要招聘吗?
- 测试环境和生产环境有什么区别?
1.2 整体业务流程 🍐
整体业务流程

- 可以通过查看原型图,了解项目背景和业务
原型可以直接通过浏览器打开
- 可以通过查看接口文档,了解项目接口,完成代码开发
接口文档通过下面的软件查看

软件官网:https://typoraio.cn/
2. 项目构建 ✏️ ❤️
2.1 项目环境搭建 ✏️ ❤️
项目环境搭建
参考笔记:后端代码初始化
项目名字:tms (teaching_manage_system)
依赖需要加上:可以查看之前的笔记,这里就不再赘述
- spring-boot-starter-web
- spring-boot-starter-test
- lombok
- mybatis-plus-boot-starter
- mysql-connector-java
- mybatis-spring
- hutool-all
- 还需要导入通用结果类AjaxResult到config包下
也就是之前的所有依赖和插件

- 创建数据库tms (可以使用Navicat创建,也可以使用Idea创建),并准备数据库表
dept(部门表)emp(员工表)emp_expr(员工工作经历表)
后续其他的表,后续再说
-- 创建数据库tms
create database if not exists tms default character set utf8mb4 collate utf8mb4_general_ci;
-- 使用数据库tms
use tms;
-- 删除部门表
drop table if exists dept;
-- 部门管理
create table dept(
id int unsigned primary key auto_increment comment '主键ID',
name varchar(10) not null unique comment '部门名称',
create_time datetime comment '创建时间',
update_time datetime comment '修改时间'
) comment '部门表';
INSERT INTO `dept` VALUES (1,'学工部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
(2,'教研部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
(3,'咨询部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
(4,'就业部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
(5,'人事部','2023-09-25 09:47:40','2023-09-25 09:47:40'),
(6,'行政部','2023-09-27 14:00:00','2023-09-27 14:00:00'),
(7,'综合部','2023-09-25 14:44:19','2023-09-25 14:44:19');
-- 先删除这个2个表
drop table if exists emp;
drop table if exists emp_expr;
-- 员工表
create table emp(
id int unsigned primary key auto_increment comment 'ID,主键',
username varchar(20) not null unique comment '用户名',
password varchar(50) default '123456' comment '密码',
name varchar(10) not null comment '姓名',
gender tinyint unsigned not null comment '性别, 1:男, 2:女',
phone char(11) not null unique comment '手机号',
job tinyint unsigned comment '职位, 1 班主任, 2 讲师 , 3 学工主管, 4 教研主管, 5 咨询师',
salary int unsigned comment '薪资',
image varchar(300) comment '头像',
entry_date date comment '入职日期',
dept_id int unsigned comment '部门ID',
create_time datetime comment '创建时间',
update_time datetime comment '修改时间'
) comment '员工表';
INSERT INTO emp VALUES
(1,'shinaian','123456','施耐庵',1,'13309090001',4,15000,'5.png','2000-01-01',2,'2023-10-20 16:35:33','2023-11-16 16:11:26'),
(2,'songjiang','123456','宋江',1,'13309090002',2,8600,'01.png','2015-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:35:37'),
(3,'lujunyi','123456','卢俊义',1,'13309090003',2,8900,'01.png','2008-05-01',2,'2023-10-20 16:35:33','2023-10-20 16:35:39'),
(4,'wuyong','123456','吴用',1,'13309090004',2,9200,'01.png','2007-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:35:41'),
(5,'gongsunsheng','123456','公孙胜',1,'13309090005',2,9500,'01.png','2012-12-05',2,'2023-10-20 16:35:33','2023-10-20 16:35:43'),
(6,'huosanniang','123456','扈三娘',2,'13309090006',3,6500,'01.png','2013-09-05',1,'2023-10-20 16:35:33','2023-10-20 16:35:45'),
(7,'chaijin','123456','柴进',1,'13309090007',1,4700,'01.png','2005-08-01',1,'2023-10-20 16:35:33','2023-10-20 16:35:47'),
(8,'likui','123456','李逵',1,'13309090008',1,4800,'01.png','2014-11-09',1,'2023-10-20 16:35:33','2023-10-20 16:35:49'),
(9,'wusong','123456','武松',1,'13309090009',1,4900,'01.png','2011-03-11',1,'2023-10-20 16:35:33','2023-10-20 16:35:51'),
(10,'linchong','123456','林冲',1,'13309090010',1,5000,'01.png','2013-09-05',1,'2023-10-20 16:35:33','2023-10-20 16:35:53'),
(11,'huyanzhuo','123456','呼延灼',1,'13309090011',2,9700,'01.png','2007-02-01',2,'2023-10-20 16:35:33','2023-10-20 16:35:55'),
(12,'xiaoliguang','123456','小李广',1,'13309090012',2,10000,'01.png','2008-08-18',2,'2023-10-20 16:35:33','2023-10-20 16:35:57'),
(13,'yangzhi','123456','杨志',1,'13309090013',1,5300,'01.png','2012-11-01',1,'2023-10-20 16:35:33','2023-10-20 16:35:59'),
(14,'shijin','123456','史进',1,'13309090014',2,10600,'01.png','2002-08-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:01'),
(15,'sunerniang','123456','孙二娘',2,'13309090015',2,10900,'01.png','2011-05-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:03'),
(16,'luzhishen','123456','鲁智深',1,'13309090016',2,9600,'01.png','2010-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:05'),
(17,'liying','12345678','李应',1,'13309090017',1,5800,'01.png','2015-03-21',1,'2023-10-20 16:35:33','2023-10-20 16:36:07'),
(18,'shiqian','123456','时迁',1,'13309090018',2,10200,'01.png','2015-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:09'),
(19,'gudasao','123456','顾大嫂',2,'13309090019',2,10500,'01.png','2008-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:11'),
(20,'ruanxiaoer','123456','阮小二',1,'13309090020',2,10800,'01.png','2018-01-01',2,'2023-10-20 16:35:33','2023-10-20 16:36:13'),
(21,'ruanxiaowu','123456','阮小五',1,'13309090021',5,5200,'01.png','2015-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:15'),
(22,'ruanxiaoqi','123456','阮小七',1,'13309090022',5,5500,'01.png','2016-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:17'),
(23,'ruanji','123456','阮籍',1,'13309090023',5,5800,'01.png','2012-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:19'),
(24,'tongwei','123456','童威',1,'13309090024',5,5000,'01.png','2006-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:21'),
(25,'tongmeng','123456','童猛',1,'13309090025',5,4800,'01.png','2002-01-01',3,'2023-10-20 16:35:33','2023-10-20 16:36:23'),
(26,'yanshun','123456','燕顺',1,'13309090026',5,5400,'01.png','2011-01-01',3,'2023-10-20 16:35:33','2023-11-08 22:12:46'),
(27,'lijun','123456','李俊',1,'13309090027',2,6600,'8.png','2004-01-01',2,'2023-10-20 16:35:33','2023-11-16 17:56:59'),
(28,'lizhong','123456','李忠',1,'13309090028',5,5000,'6.png','2007-01-01',3,'2023-10-20 16:35:33','2023-11-17 16:34:22'),
(30,'liyun','123456','李云',1,'13309090030',NULL,NULL,'01.png','2020-03-01',NULL,'2023-10-20 16:35:33','2023-10-20 16:36:31'),
(36,'linghuchong','123456','令狐冲',1,'18809091212',2,6800,'1.png','2023-10-19',2,'2023-10-20 20:44:54','2023-11-09 09:41:04');
-- 员工工作经历信息
create table emp_expr(
id int unsigned primary key auto_increment comment 'ID, 主键',
emp_id int unsigned comment '员工ID',
begin date comment '开始时间',
end date comment '结束时间',
company varchar(50) comment '公司名称',
job varchar(50) comment '职位'
)comment '工作经历';- 修改application.yml中的数据库连接信息

# 顶格写
spring:
#数据库连接信息
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/tms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 1234
#Mybatisplus配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
type-aliases-package: cn.yangeit.pojo
global-config:
db-config:
logic-delete-field: isDeleted
id-type: auto前端的代码将来在公司中会由前端工程师专门开发。咱们本次是java的实训,并不是前端的实训,所以这些前端的代码已经提供好了,目的是为了有更好的展示效果,直接运行代码即可。
- 安装前端运行环境node, 版本20.12.0
安装文件下载地址:https://mirrors.aliyun.com/nodejs-release/v20.12.0/
在控制台执行 node -v 查看node是否安装成功

解压前端代码,在控制台直接执行npm run dev 指令,即可启动项目


总结
课堂作业
- 参考上述步骤完成项目环境搭建,不会多看几遍🎤
3. 部门模块
3.1 部门列表查询
部门列表查询
需求:查询数据库表中的所有部门数据,展示在页面上。

代码操作
1️⃣ 1. 准备数据库表 dept 及 实体类 Dept

实体类放到pojo包中
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
private Integer id;
private String name;
private LocalDateTime createTime;
private LocalDateTime updateTime;
}2️⃣ 2. 定义mapper包,并且定义DeptMapper接口继承BaseMappper接口,并声明接口方法。
@Mapper
public interface DeptMapper extends BaseMapper<Dept> {
}3️⃣ 3. 在controller包中创建DeptController,并编写接口方法
参考接口文档的接口定义,编写接口方法

@RestController
public class DeptController {
@Autowired
private DeptMapper deptMapper;
@GetMapping("/depts")
public AjaxResult findAll(){
List<Dept> deptList = deptMapper.selectList(null);
return AjaxResult.success(deptList);
}
}4️⃣ 4. 启动服务,打开apifox进行测试


总结
课堂作业
- 参考上述步骤完成部门列表查询,不会多看几遍🎤
3.2 删除部门
删除部门
删除部门数据。在点击 "删除" 按钮,会根据ID删除部门数据。

了解了需求之后,我们再看看接口文档中,关于删除部门的接口的描述,然后根据接口文档进行服务端接口的开发。

思路分析
明确了删除部门的需求之后,再来梳理一下实现该功能时,三层架构每一层的职责:
- 前端:发送请求,展示数据
- 服务端控制层:接收请求,调用Mapper接口,操作数据库, 返回结果
代码操作
1️⃣ 1. 在controller包中创建DeptController,参考接口文档,并编写接口方法
/**
* 删除部门
*/
@DeleteMapping("/depts")
public AjaxResult delete(Integer id){
System.out.println("删除部门: " + id);
deptMapper.deleteById(id);
return AjaxResult.success();
}2️⃣ 代码编写完毕之后,我们就可以启动服务,进行测试了。

并且观察idea的控制台,mp的日志,可以看到数据库的删除操作。

总结
课堂作业
- 参考上述步骤完成部门删除,不会多看几遍🎤
3.3 新增部门
新增部门
点击 "新增部门" 的按钮之后,弹出新增部门表单,填写部门名称之后,点击确定之后,保存部门数据。

了解了需求之后,我们再看看接口文档中,关于新增部门的接口的描述,然后根据接口文档进行服务端接口的开发 。

思路说明
明确了新增部门的需求之后,再来梳理一下实现该功能时,三层架构每一层的职责:

Mapper这里采用MybatisPlus自动生成sql语句,所以不需要我们手写sql语句。
代码操作
1️⃣ 1. Controller层
我们看到,在controller中,需要接收前端传递的请求参数。 那接下来,我们就先来看看在服务器端的Controller程序中,如何获取json格式的参数。
JSON格式的参数,通常会使用一个实体对象进行接收 。
规则:JSON数据的键名与方法形参对象的属性名相同,并需要使用
@RequestBody注解标识。

2️⃣ 代码编写完毕之后,我们就可以启动服务,进行测试了。

并且观察idea的控制台,mp的日志,可以看到数据库的新增操作。

总结
课堂作业
此时发现,每个方法的路径都是/dept 那么我们可以将这个路径提取到Controller层,然后通过@RequestMapping注解,将路径提取到方法上。

接下来,参考上述步骤完成部门新增,不会多看几遍🎤
3.4 修改部门
前言
对于任何业务的修改功能来说,一般都会分为两步进行:查询回显、修改数据。

查询回显
需求分析
当我们点击 "编辑" 的时候,需要根据ID查询部门数据,然后用于页面回显展示。

明确了根据ID查询部门的需求之后,再来梳理一下实现该功能时,三层架构每一层的职责:

了解了需求之后,我们再看看接口文档中,关于根据ID查询部门的接口的描述,然后根据接口文档进行服务端接口的开发 。

路径参数接收
/depts/1,/depts/2 这种在url中传递的参数,我们称之为路径参数。 那么如何接收这样的路径参数呢 ?
路径参数:通过请求URL直接传递参数,使用{…}来标识该路径参数,需要使用 @PathVariable 获取路径参数。如下所示:

接下来,重启服务,进行测试。

1. 需求分析
查询回显回来之后,就可以对部门的信息进行修改了,修改完毕之后,点击确定,此时,就需要根据ID修改部门的数据。

了解了需求之后,我们再看看接口文档中,关于修改部门的接口的描述,然后根据接口文档进行服务端接口的开发 。

2. 思路分析
参照接口文档,梳理三层架构每一层的职责:

通过接口文档,我们可以看到前端传递的请求参数是json格式的请求参数,在Controller的方法中,我们可以通过 @RequestBody 注解来接收,并将其封装到一个对象中。

接下来,开始测试,修改部门数据。
4. 日志技术
日志技术
什么时日志?
日志就好比生活中的日记,可以随时随地记录你生活中的点点滴滴。
程序中的日志,是用来记录应用程序的运行信息、状态信息、错误信息的。
为什么要在程序中记录日志呢?
- 便于追踪应用程序中的数据信息、程序的执行过程。
- 便于对应用程序的性能进行优化。
- 便于应用程序出现问题之后,排查问题,解决问题。
- 便于监控系统的运行状态。
- ... ...
之前我们编写程序时,也可以通过
System.out.println(...)来输出日志,为什么我们还要学习单独的日志技术呢?这是因为,如果通过
System.out.println(...)来记录日志,会存在以下几点问题:- 硬编码。所有的记录日志的代码,都是硬编码,没有办法做到灵活控制,要想不输出这个日志了,只能删除掉记录日志的代码。
- 只能输出日志到控制台。
- 不便于程序的扩展、维护。
所以,在现在的项目开发中,我们一般都会使用专业的日志框架,来解决这些问题。
日志框架

JUL: 这是JavaSE平台提供的官方日志框架,也被称为JUL。配置相对简单,但不够灵活,性能较差。
Log4j: 一个流行的日志框架,提供了灵活的配置选项,支持多种输出目标。
Logback: 基于Log4j升级而来,提供了更多的功能和配置选项,性能由于Log4j。
Slf4j:(Simple Logging Facade for Java)简单日志门面,提供了一套日志操作的标准接口及抽象类,允许应用程序使用不同的底层日志框架。
代码操作
Slf4j(酸辣粉使用教程)
几个常用的 lombok 注解:
@Data:注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法@Setter:注解在属性上;为属性提供 setting 方法@Getter:注解在属性上;为属性提供 getting 方法@SneakyThrows:无需在签名处显式抛出异常@Log4j:注解在类上;为类提供一个 属性名为log 的 log4j 日志对像,用作日志输出的,一般会在项目每个类的开头加入该注解@Slf4j: 同上@NoArgsConstructor:注解在类上;为类提供一个无参的构造方法@AllArgsConstructor:注解在类上;为类提供一个全参的构造方法
为什么使用@Slf4j?
为了能够少写两行代码,不用每次都在类的最前边写上: private static final Logger logger = LoggerFactory.getLogger(this.XXX.class);
使用步骤:
1. 在springboot项目下的pom.xml 导入下列依赖 如果已经存在,就不需要重新导入
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>2. 在类名上加上注解 @Slf4j

运行结果:

3. 占位符 {} 非常好用
//占位符:日志输出中{}很好用
@Test
public void test2(){
log.info("测试日志info:{}","yangeit");
log.warn("测试日志warn:{},{}",1,6);
}运行结果:


