序:模块开发顺序
首先,我们先来理清各个模块开发的顺序

例:班级管理(子模块1),学员管理(子模块2)∈ 班级学员管理(父模块)
学员管理(学员所属班级)∈ 班级管理
那么对Tlias项目分析 ,拥有三个父模块(忽略登录功能),分别为
1.系统信息管理(父模块): 部门管理,员工管理
又 员工管理(员工所属部门)∈ 部门管理
2. 班级学员管理(父模块):班级管理,学员管理
又 学员管理(学员所属班级)∈ 班级管理
且 班级学员管理(班级,学员所属员工[教师])∈系统信息管理
3. 数据统计管理(父模块):员工信息统计,学员信息统计
又 员工信息统计 ∈ 系统信息管理 学员信息统计 ∈ 班级学员管理
故可以得到开发模块的流程:

模块功能[接口]开发的流程(课程所建议流程)为

正:各模块开发
仅列出各个模块开发过程中觉得重要的部分
1.部门管理
1.1 前端各请求参数的接收方式
补丁:可以直接用类来接收,不需要@RequestBody注解,自动绑定
public Result<String> save(@RequestBody CategoryDTO categoryDTO)
1.1.1参数请求:
传递参数:
例如:
/depts?id=1
接受请求:
推荐:将方法形参与前端参数名保持一致,自动识别(省略@RequestParam)
@DeleteMapping("/depts")
public Result deleteById(Integer id)
其他方式:
1.直接将请求体对象HttpServletRequest作为方法形参
2.RequestParam注解进行绑定(requir.通过@ed = false)时为非必须绑定参数(默认为true)
public Result deleteById(@RequestParam(value = "id" required = true) Integer deptid)
当传递的参数为数组时
例:
/emps?ids=1,2,3
可默认用数组接受参数,此时会自动绑定参数
public Result delete(int[] ids)
若要用列表List等接收参数,需要使用@RequestParam 标注,才能绑定参数
public Result delete(@RequestParam List<Integer> ids)
当传递的参数过于复杂时
例:
/emps?name=张&gender=1&begin=2007-09-01&end=2022-09-01&page=1&pageSize=10
可以自定义一个类来接受参数:
@Data
public class EmpQueryParam {
private Integer page = 1;
private Integer pageSize = 10;
private String name;
private Integer gender;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate begin;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate end;
}
@GetMapping
public Result list(EmpQueryParam e)
1.1.2 json请求
传递参数:
例如
{ "image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg", "username": "linpingzhi", "name": "林平之", "gender": 1, "job": 1, "entryDate": "2022-09-18", "deptId": 1, "phone": "18809091234", "salary": 8000, "exprList": [ { "company": "百度科技股份有限公司", "job": "java开发", "begin": "2012-07-01", "end": "2019-03-03" }, { "company": "阿里巴巴科技股份有限公司", "job": "架构师", "begin": "2019-03-15", "end": "2023-03-01" } ] }
接受请求:
json格式的参数,往往通过一个实体对象接收
规则:json格式的参数名与方法形参对象的属性名保持一致,并使用@RequestBody注解标注
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
private Integer id;
private String name;
LocalDateTime createTime;
LocalDateTime updateTime;
}
@PostMapping("/depts")
public Result addDept(@RequestBody Dept dept)
1.1.3路径参数
传递参数:
需要用@PathVariable注解标注
public Result getInfo(@PathVariable("id") Integer deptid)
路径参数和方法形参一致时,可以简化
@GetMapping("/depts/{id}")
public Result getInfo(@PathVariable Integer id)
当传递多个路径参数时
如:
/students/violation/{id}/{score}
方法需要标记多个形参
@PutMapping("/violation/{id}/{score}")
public Result violation(@PathVariable Integer id, @PathVariable Integer score)
2.员工管理
2.1分页查询PageHelper
PageHelper依赖引入[pom.xml]:
<!--分页插件PageHelper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.7</version>
</dependency>
PageHelper使用注意事项:
PageHelper的注意事项
1.SQL语句不能加分号,不然无法修改
2.PageHelper仅进行一次拦截,只对后面第一次调用SQL语句生效
3.Page<>数据结构继承了ArrayList ,对ArrayList进行了改造封装
@Override
public PageResult<Emp> list(EmpQueryParam e) {
//设置分页参数
//Page为页码
//PageSize为每页展示的数据数
PageHelper.startPage(e.getPage(),e.getPageSize());
//调用Mapper
//直接用Page封装结果(Page类由PageHelper提供,封装了total等分页查询参数)
//empMapper.list(e)返回的参数为List<>类型
Page<Emp> p = (Page<Emp>)empMapper.list(e);
//返回结果
//PageResult<>为自定义类
return new PageResult<Emp>(p.getTotal(),p.getResult());
}
PageResult类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult<T> {
private long total;
private List<T> rows;
}
使用泛型<T>的意义是 定义一个PageResult类可以用于多个模块 ,避免代码臃肿
2.2 事务管理
背景描述:
员工管理的新增员工功能涉及到两张表 emp(员工表) ,emp_expr(员工经历表)
新增员工的Service层分别调用了两个Mapper接口,empMapper 和 empExprMapper
当empMapper调用失败,但是empExprMapper调用成功时,就会出现两张表数据不同步的现象。
为了避免这种现象 ,就可以使用事务管理(Transactional)
当一个方法被事务管理标记后
当方法中出现异常时,方法中对数据库的操作都会被撤销(回滚)
@Transactional(rollbackFor = RuntimeException.class,propagation = REQUIRED)
//@Transactional 注解用于声明一个事务方法,它可以应用于方法级别或类级别。
//回滚适用情况默认为RuntimeException
//propagation默认为REQUIRED(加入父事务[存在时]) 当需要强制为新事务时为 REQUIRED_NEW
@Override
public void add(Emp emp) {
empMapper.add(emp);
//调用完emp的add方法后,emp的id获得返回值
List<EmpExpr> exprList = emp.getExprList();
if(!CollectionUtils.isEmpty(exprList)){
//System.out.println(emp.getId());
empExprMapper.addBatch(emp.getId(),exprList);
}
}
2.3 SQL应用
2.3.1添加信息
问题描述:emp的Mapper层在执行Insert语句时,需要获取信息插入后的id,交给empExpr的Mapper执行
使用useGeneratedKeys和keyProperty属性 来取得id
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into emp(username, name, gender, image, dept_id, entry_date, job,salary,phone,create_time,update_time)
values(#{username},#{name},#{gender},
<choose>
<when test="image == ''">
'https://web-framework.oss-cn-hangzhou.aliyuncs.com/2023/1.jpg'
</when>
<otherwise>
#{image}
</otherwise>
</choose>,#{deptId},#{entryDate},#{job},#{salary},#{phone},NOW(),NOW())
</insert>
2.3.2修改信息/根据id获取信息
问题描述:在修改员工信息时,需要进行查询回显,但是员工信息涉及两个表 emp 和 emp_expr ,所以这时Sql语句需要对结果进行映射,并封装在Emp类中
Emp类:
@Data
@NoArgsConstructor
@AllArgsConstructor
// ... existing code ...
public class Emp {
private Integer id;
private String username;
private String password;
private String name;
private Integer gender; //1.男 2.女
private String phone;
private Integer job;
private Integer salary;
private String image;
private MultipartFile file;
private LocalDate entryDate;
private Integer deptId; //1.学工部 2.教研部 3.咨询部 4.就业部 5.人事部 6.行政部
private LocalDateTime createTime;
private LocalDateTime updateTime;
//封装员工工作经历
private List<EmpExpr>exprList ;
//封装部门名称
private String deptName;
}
Empexpr类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class EmpExpr {
private Integer id;
private Integer empId;//对应员工id
private LocalDate begin;
private LocalDate end;
private String company;
private String job;
}
SQL语句
<!--自定义映射结果集ResultMap-->
<resultMap id="empResultMap" type="org.example.pojo.Emp">
<id column="id" property="id" />
<result column="username" property="username" />
<result column="password" property="password" />
<result column="name" property="name" />
<result column="gender" property="gender" />
<result column="phone" property="phone" />
<result column="job" property="job" />
<result column="salary" property="salary" />
<result column="image" property="image" />
<result column="entry_date" property="entryDate" />
<result column="dept_id" property="deptId" />
<result column="create_time" property="createTime" />
<result column="update_time" property="updateTime" />
<!--封装exprList-->
<collection property="exprList" ofType="org.example.pojo.EmpExpr">
<id column="ee_id" property="id"/>
<result column="ee_company" property="company"/>
<result column="ee_job" property="job"/>
<result column="ee_begin" property="begin"/>
<result column="ee_end" property="end"/>
<result column="ee_empid" property="empId"/>
</collection>
</resultMap>
<!--根据ID查询员工的详细信息-->
<select id="get" resultMap="empResultMap">
select e.*,
ee.id ee_id,
ee.emp_id ee_empid,
ee.begin ee_begin,
ee.end ee_end,
ee.company ee_company,
ee.job ee_job
from emp e left join emp_expr ee on e.id = ee.emp_id
where e.id = #{id}
</select>
3.员工信息统计
3.1SQL应用
问题描述:统计各职位员工人数
接口文档响应数据示例:
{ "code": 1, "msg": "success", "data": { "jobList": ["教研主管","学工主管","其他","班主任","咨询师","讲师"], "dataList": [1,1,2,6,8,13] } }
由图中可见,返回的是两个列表,但是职位在emp表中记录的是数字(前端选择后返回数字),所以需要对emp表中的职位进行映射。
<select id="exportEmpJobData" resultType="java.util.Map">
select
(case job when 1 then '班主任'
when 2 then '讲师'
when 3 then '学工主管'
when 4 then '教研主管'
when 5 then '咨询师'
else '其他' end) pos,
count(*) total
from emp group by job
order by total
</select>
出于简化考虑,结果用Map<>进行封装
List<Map<String,Object>> exportEmpJobData();
注:Mybatis在将结果封装进map时为
Map<String,Object> map = new HashMap<>(); map.put("pos",pos1); map.put("total",total1); list.add(map);
在使用时,使用stream流
//封装jobList
List<Map<String,Object>> jobDataList = reportMapper.exportEmpJobData();
List<String> jobList = jobDataList.stream().map(x -> x.get("pos").toString()).toList();
List<Object> dataList = jobDataList.stream().map(x -> x.get("total")).toList();
4.班级管理
4.1自定义异常
问题描述:在班级管理模块的删除功能中,当班级中仍有人时,该班级无法删除,此时需要自定义异常提醒前端操作
自定义异常类:
public class ClazzDeleteWithStuException extends RuntimeException {
public ClazzDeleteWithStuException(String message) {
super(message);
}
}
异常类使用(ClazzServiceImpl):
@Override
public void remove(Integer id) {
if(studentMapper.countByClazzId(id) > 0) {
throw new ClazzDeleteWithStuException("该班级仍有学生 不可删除");
}
clazzMapper.deleteById(id);
}
异常捕获(全局异常处理器GlobalExceptionHandler):
@ExceptionHandler
public Result handleClazzDeleteWithStuException(ClazzDeleteWithStuException e) {
log.error(e.getMessage());
return Result.error(e.getMessage());
}
5.学员管理,班级信息统计-略
该部分业务与前面逻辑重复,故略过
终
复盘一下感觉没多少东西,仍需继续努力QAQ
1741

被折叠的 条评论
为什么被折叠?



