学生党学习笔记——黑马程序员Java项目实战《苍穹外卖》——Day02员工管理及分类管理
今天学习的内容主要分为用户管理和分类管理。,都是一些crud的基本操作,看视频熟悉了项目结构之后并不难 ,毕竟是基础。希望看到这里的同学朋友们能跟我一起坚持下去,达到自己 理想的目标!!!
前言
今天学习的内容主要分为用户管理和分类管理。
,都是一些crud的基本操作,看视频熟悉了项目结构之后并不难 ,毕竟是基础。希望看到这里的同学朋友们能跟我一起坚持下去,达到自己 理想的目标!!!
视频学习链接:黑马程序员Java项目实战《苍穹外卖》,最适合新手的SpringBoot+SSM的企业级Java项目实战_哔哩哔哩_bilibili
资料网盘链接:https://pan.baidu.com/s/1MNDzXyVlr3mtmLgBjcPJVw&pwd=6633
本人项目远程仓库:
sky-take-out: 黑马程序员Java项目实战《苍穹外卖》,最适合新手的SpringBoot+SSM的企业级Java项目实战
视频当中采取的开发步骤分为四步走:•需求分析和设计 •代码开发 •功能测试 •代码完善。首先通过接口开发文档对即将要开发的接口进行分析和设计,相当于把“大象塞进冰箱”的步骤细分,需要什么、需要干什么等。代码完善是对代码进行功能方面的完善,让代码不仅仅停留在crud层面上,更加人性化。
一、员工管理
(一)、新增员工
1.需求分析和设计
首先我们进入添加用户的界面,发现就是一个填写信息的表单。那我们可以根据表单内容,以及现实情况分析。其中账号通过mysql数据库中UNIQUE限制手机号、身份证号在前端校验(通过后续测试接口可得知)。

然后打开Apifox进入接口文档具体分析,也可以跟着视频中同步项目地址:苍穹外卖项目接口文档(启动项目后再访问哦~)
接口地址:/admin/employee 访问方式:Post

请求参数:json形式

返回参数


2.代码开发
视频中老师开发的顺序是由外到内,Controller -> Service -> ServiceImpl -> Mapper
注意:当前端传入数据与实体类中对应属性相差太大时使用DTO接收封装数据
显然刚刚新增用户的表单中并没有给12个字段都输入信息,并且例如id一些字段不需要用户输入

/** Controller层
* 新增员工方法
* @param employeeDTO
* @return
*/
@PostMapping
@ApiOperation("新增员工")
public Result save(@RequestBody EmployeeDTO employeeDTO) {
//控制台打印信息
log.info("新增员工{}",employeeDTO);
employeeService.insert(employeeDTO);
return Result.success();
}
/** Service层
* 新增员工
* @param employeeDTO
*/
void insert(EmployeeDTO employeeDTO);
/** Service实现类
* 新增员工
* @param employeeDTO
*/
public void insert(EmployeeDTO employeeDTO) {
//创建实体类对象接受DTO属性,再进行其他属性设置
Employee employee = new Employee();
//1.BeanUtils的属性拷贝赋值
BeanUtils.copyProperties(employeeDTO, employee);
//2
//2.1 默认状态正常;1表示正常,0表示禁用
employee.setStatus(StatusConstant.ENABLE);
//2.2默认密码为123456
employee.setPassword(
DigestUtils.md5DigestAsHex(
PasswordConstant.DEFAULT_PASSWORD.getBytes()));
//2.3设置创建、修改时间
LocalDateTime now = LocalDateTime.now();
employee.setCreateTime(now);
employee.setUpdateTime(now);
//2.4设置创建、修改用户
//TODO 代码完善中完成关于动态获取当前操作用户id问题
employee.setCreateUser(10L);
employee.setUpdateUser(10L);
//3.调用服务层 接口
employeeMapper.insert(employee);
}
/**Mapper层,单表插入语句 -> @Insert注解
* 添加员工
* @param employee
*/
@Insert("insert into employee (name, username, password, phone, sex, id_number, create_time, update_time, create_user, update_user) " +
"values (#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{createTime},#{updateTime},#{createUser},#{updateUser})")
void insert(Employee employee);
3.功能测试
①接口文档测试 ②前后端联调测试(把项目跑起来,模拟用户测试功能)
接口文档测试
这里我们直接使用apifox自动生成的数据进行测试,但是发现请求成功没有返回数据。

因为项目中使用JWT令牌来拦截登录,通过校验用户登录的token进行拦截。token有效时间为2h

并且再次测试登录接口,发现确实会由token
我们将测试的token进行全局配置,注意:参数名必须为token否则扫描不到
之后,为开发方便,可以将token时间设置长一点(根据自己需要),否则两小时登录一次还是比较烦的。
前后端联调测试
会发现和上面接口文档测试不同,因为前端校验长度,手机号必须11位,身份证号必须18位



4.功能完善
问题:username字段unique属性,当用户名重复时会直接报错,用户体验差

返回给前端的只有异常。
解决:在项目全局异常处理中对异常信息进行捕获、处理。
sky-server模块的handler包下的GlobalExceptionHandler类中重写异常处理方法
@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
log.error("异常信息:{}",ex.getMessage());
String message = ex.getMessage();
//判断是否为触发unique的重复异常
if( message.contains("Duplicate entry")){
//根据异常信息可知重复值在索引2的位置,通过空格进行切片
String[] s = message.split(" ");
String username = s[2];
//返回错误提示
String msg = username + MessageConstant.ALREADY_EXISTS;
return Result.error(msg);
} else{
return Result.error(MessageConstant.UNKNOWN_ERROR);
}
}
问题2:解决Service实现类中动态获取当前操作用户id问题

解决:使用ThreadLocal在JWT验证时存储用户id
· 关于ThreadLocal
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
ThreadLocal常用方法:


将service实体类中写死的数据换成localThread中存储的用户id

(二)、员工分页查询
1.需求分析和设计
根据产品原型对接口进行分析,发现如图三个特点。

根据接口文档分析
接口地址:/admin/employee/page 请求方式:Get



2.代码开发
分页查询对应DTO:EmployeePageQueryDTO
(再次强调,迎合前端数据专门设计的封装类xxxDTO)

分页查询对应的返回类PageResult(观察项目结构发现,result包下就Result和PageResult)

注意:此处使用 mybatis 的分页插件 PageHelper 来简化分页代码的开发。底层基于 mybatis 的拦截器实现。(相当于帮我们加limit关键字)
/** Controller层
* 员工分页查询
* @param employeePageQueryDTO
* @return
*/
@GetMapping("/page")
@ApiOperation("分页查询")
public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO) {
log.info("分页查询{}",employeePageQueryDTO);
PageResult pageResult = employeeService.page(employeePageQueryDTO);
return Result.success(pageResult);
}
/** Service层
* 员工分页查询
*
* @param employeePageQueryDTO
* @return
*/
PageResult page(EmployeePageQueryDTO employeePageQueryDTO);
/** Service实现类
* 员工分页查询
*
* @param employeePageQueryDTO
* @return
*/
public PageResult page(EmployeePageQueryDTO employeePageQueryDTO) {
//0.mybatis提供的分页插件工具PageHelper
//相当于select * from employee limit 0,10;
PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());
//1.进行分页查询
Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);
return new PageResult(page.getTotal(), page.getResult());
}
/** Mapper
* 员工分页查询;设计动态数据 -> 使用xml注入
* @param employeePageQueryDTO
* @return
*/
Page<Employee> pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
<select id="pageQuery" resultType="com.sky.entity.Employee" parameterType="com.sky.dto.EmployeePageQueryDTO">
select * from employee
<where>
<if test="name != null and name != ''">
and name like concat('%',#{name},'%')
</if>
</where>
order by create_time desc
</select>
3.功能测试
问题
测试时发现,展示时间时数据全都挤在一块,可读性很差

解决
①:使用@JsonFormat注解对日期格式化(量少方便)

②:拓展mvc消息转换器,对日期类型的数据统一格式化处理(量大方便)
/** WebMvcConfiguration类
* 拓展消息转换器:将时间类型属性自动转换为json格式
* @param converters
*/
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("消息转换器....");
//1.创建自己的消息转换器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
//2.为消息转换器添加转换规则(JacksonObjectMapper在项目common包中json提供)
//2.1JacksonObjectMapper里面有转换规则:将java当中多个时间类转换成对应格式
converter.setObjectMapper(new JacksonObjectMapper());
//3.将自己的转换器加入mvc转换器列表
//注意:add将我们转换器默认加到末尾,可能不生效 ——> 指定位置
converters.add(0,converter);
}

(三)、启用禁用员工账号
1.需求分析和设计

业务规则:
接口设计



2.代码开发
/** Controller
* 员工状态禁启用
* @param status
* @param id
* @return
*/
@PostMapping("/status/{status}")
@ApiOperation("员工状态禁启用")
public Result startOrStop(@PathVariable Integer status,Long id) {
log.info("员工状态禁启用{},{}",status,id);
employeeService.startOrStop(status,id);
return Result.success();
}
/** Service
* 启用员工账号
* @param status
* @param id
*/
void startOrStop(Integer status, Long id);
/** Service实现
* 员工禁启用方法
* @param status
* @param id
*/
public void startOrStop(Integer status, Long id) {
Employee employee = Employee.builder()
.id(id)
.status(status)
.build();
employeeMapper.update(employee);
}
/** Mapper
* 根据id修改员工账号状态
* @param employee
*/
void update(Employee employee);
单单更新一个用户状态没必要单独写一个更新方法,为后面编辑用户功能方便
<update id="update" parameterType="com.sky.entity.Employee">
update employee
<set>
<if test="username != null">username = #{username},</if>
<if test="name != null">name = #{name},</if>
<if test="password != null">password = #{password},</if>
<if test="phone != null">phone = #{phone},</if>
<if test="sex != null">sex = #{sex},</if>
<if test="idNumber != null">id_Number = #{idNumber},</if>
<if test="updateTime != null">update_Time = #{updateTime},</if>
<if test="updateUser != null">update_User = #{updateUser},</if>
<if test="status != null">status = #{status},</if>
</set>
where id = #{id}
</update>
(四)、编辑员工
1.需求分析和设计
编辑员工功能涉及到两个接口:
接口设计



2.代码开发
1.getById
/** Controller
* 修改员工信息前回显员工原有数据
* @param id
* @return
*/
@GetMapping("/{id}")
@ApiOperation("根据id查询员工")
public Result<Employee> getById(@PathVariable Long id) {
log.info("根据id查询员工{}",id);
Employee employee = employeeService.getById(id);
return Result.success(employee);
}
/** Service
* 根据id查询员工
* @param id
* @return
*/
Employee getById(Long id);
/** ServiceImpl
* 根据id查询员工
* @param id
* @return
*/
public Employee getById(Long id) {
Employee employee = employeeMapper.getById(id);
return employee;
}
/** Mapper
* 根据id查询员工信息
* @param id
* @return
*/
@Select("select * from employee where id = #{id}")
Employee getById(Long id);
/** Controller
* 编辑员工信息
* @param employeeDTO
* @return
*/
@PutMapping
@ApiOperation("编辑员工信息")
public Result update(@RequestBody EmployeeDTO employeeDTO) {
log.info("编辑员工信息{}",employeeDTO);
employeeService.update(employeeDTO);
return Result.success();
}
/** Service
* 根据id修改员工信息
* @param employeeDTO
*/
void update(EmployeeDTO employeeDTO);
/** ServiceImpl
* 根据id修改员工信息
* @param employeeDTO
*/
public void update(EmployeeDTO employeeDTO) {
//update set (列 = 属性,.....) where id =
Employee employee = new Employee();
//1.拷贝传入参数属性
BeanUtils.copyProperties(employeeDTO, employee);
//2.更新修改时间及修改人
employee.setUpdateTime(LocalDateTime.now());
employee.setUpdateUser(BaseContext.getCurrentId());
//3.修改员工信息
employeeMapper.update(employee);
}
(五)、导入分类管理类功能代码
将资料中的代码导入到响应位置即可

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)