目录
- day1
- 一、项目效果展示
- 二、项目开发整体介绍
- 三、项目介绍
- 3.1 定位
- 3.2 功能架构
- 3.3 产品原型
- 3.4 技术选型
- 四、开发环境搭建
- 4.1 前端环境
- 4.2 后端环境
- 五、导入接口文档
- 六、Swagger
- 6.1 介绍
- 6.2 使用方式
- 6.3 常用注解
- day2
- 一、新增员工
- 二、员工分页查询
- 三、启用禁用员工账号
- 四、编辑员工
- 五、导入分类模块功能代码
- day3
来源: 黑马程序员Java项目实战《苍穹外卖》,最适合新手的SpringBoot+SSM的企业级Java项目实战
day1
一、项目效果展示
二、项目开发整体介绍
三、项目介绍
3.1 定位
3.2 功能架构
3.3 产品原型
html页面,包括管理端和用户端两种
3.4 技术选型
四、开发环境搭建
4.1 前端环境
前端工程是基于nginx运行的,已经是打包好的程序,直接双击执行exe文件,接着在浏览器访问localhost
即可。
4.2 后端环境
后端工程是基于maven进行构建的,并且进行分模块开发
导入的时候,需要配置maven的settings文件中阿里云镜像
- 使用git进行版本控制:本地创建仓库,远程创建仓库,将本地仓库推送到远程
- 数据库环境搭建:导入数据库文件即可
- 前后端联调:通过断点调试,一步步理清登录功能。
1.获取前端对象(employeeLoginDTO)
2.使用DTO中username属性通过EmployeeMapper查询数据库,得到emplyee对象
3.判断密码是否一致,且用户状态是否为‘启用’,都是则登录成功
4.生成JWK令牌,通过配置文件获取密钥和过期时间,令牌名称为token
5.通过Builder注解的方法生成employeeLoginVO对象,包括主键值、用户名、姓名和jwt令牌
6.后端统一返回结果为Result<T>,封装了错误信息msg和返回的VO对象
7.另外,文件中定义了各种异常,继承自BaseException,它的父类为RuntimeException。通过全局处理器handler来捕获全部的异常,进行处理
-
前端发送的请求,如何请求到后端服务的?
是通过nginx方向代理,将前端发送的动态请求有nginx转发到后端服务器
-
完善登录功能
在数据库中加密存储密码—> 在server登录功能处,将明文密码先加密在进行对比
五、导入接口文档
接口设计能力
前后端分离开发流程。使用apifox导入接口json文件。划分了两个文件,包括管理端和用户端。
六、Swagger
6.1 介绍
6.2 使用方式
最后去网页访问http://localhost:8080/doc.html,会出现下面的界面
6.3 常用注解
day2
一、新增员工
- 根据接口文档,写service。EmployeeController.java
/**
* 新增员工
* @param employeeDTO
* @return
*/
@PostMapping
@ApiOperation("新增员工")
public Result save(@RequestBody EmployeeDTO employeeDTO){
log.info("新增员工:{}", employeeDTO);
employeeService.save(employeeDTO);
return Result.success();
}
- 完善EmployeeService接口和EmployeeServiceImpl接口实现类的save方法。EmployeeServiceImpl.java
/**
* 新增员工
* @param employeeDTO
*/
public void save(EmployeeDTO employeeDTO) {
// 对象的转换,将DTO转为实体对象
Employee employee = new Employee();
// 对象属性拷贝,将dto对象拷贝给entity。DTO和entity对象的属性名有一部分一致
BeanUtils.copyProperties(employeeDTO,employee);
// 对entity的其他属性初始化
employee.setStatus(StatusConstant.ENABLE); //状态
employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes())); //密码
employee.setCreateTime(LocalDateTime.now()); //创建时间
employee.setUpdateTime(LocalDateTime.now()); //修改时间
// todo 后期需要改为当前用户的属性
employee.setCreateUser(10L); //创建人
employee.setUpdateUser(10L); //修改人
employeeMapper.insert(employee);
}
- 完善EmployeeMapper接口中的sql。EmployeeMapper.java
/**
* 插入员工数据
* @param employee
*/
@Insert("insert into employee (name, username, password, phone, sex, id_number, status, create_time, update_time, " +
"create_user, update_user) values (#{name}, #{username}, #{password}, #{phone}, #{sex}, #{idNumber}, " +
"#{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
void insert(Employee employee);
- 通过接口文档测试功能(常用)或者是前后端联调测试。
通过接口文档测试的时候,发出的请求需要带上token令牌。因此需要添加一个全局变量,名称为token。
- 完善登录功能。重复录入,抛出异常没有处理;新增员工,创建人和修改人设置的是固定值。完善好仍要进行测试。
//1.重复录入,异常处理即可
//GlobalExceptionHandler.java
/**
* 处理sql异常
* @param ex
* @return
*/
@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
String message = ex.getMessage();
if(message.contains("Duplicate entry")){
String username = message.split(" ")[2];
String msg = username + MessageConstant.ALREADY_EXISTS;
return Result.error(msg);
}else{
return Result.error(MessageConstant.UNKNOWN_ERROR);
}
}
//2.使用threadLocal方法解决获取当前用户id
//BaseContext.java
package com.sky.context;
public class BaseContext {
public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id) {
threadLocal.set(id);
}
public static Long getCurrentId() {
return threadLocal.get();
}
public static void removeCurrentId() {
threadLocal.remove();
}
}
//JwtTokenAdminInterceptor.java
BaseContext.setCurrentId(empId);
//EmployeeServiceImpl.java
employee.setCreateUser(BaseContext.getCurrentId()); //创建人
employee.setUpdateUser(BaseContext.getCurrentId()); //修改人
二、员工分页查询
//EmployeeController.java
/**
* 员工分页查询
* @param employeePageQueryDTO
* @return
*/
@GetMapping
@ApiOperation("员工分页查询")
public Result<PageResult> pageQuery(EmployeePageQueryDTO employeePageQueryDTO){
log.info("员工分页查询,参数为:{}", employeePageQueryDTO);
PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);
return Result.success(pageResult);
}
//EmployeeServiceImpl.java
/**
* 员工分页查询
* @param employeePageQueryDTO
* @return
*/
@Override
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
//select * from employee limit 0,10
//开始分页查询
PageHelper.startPage(employeePageQueryDTO.getPage(),employeePageQueryDTO.getPageSize());
Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);
long total = page.getTotal();
List<Employee> records = page.getResult();
return new PageResult(total, records);
}
//EmployeeMapper.java
/**
* 员工分页查询
* @param employeePageQueryDTO
* @return
*/
Page<Employee> pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
//EmployeeMapper.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.sky.mapper.EmployeeMapper">
<select id="pageQuery" resultType="com.sky.entity.Employee">
select * from
<where>
<if test="name != null and name != ''">
and name like concat('%',#{name},'%')
</if>
</where>
order by create_time desc
</select>
</mapper>
完善代码:1时间的问题
/**
* 扩张Spring MVC框架的消息转换器
* @param converters
*/
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转化器...");
//创建一个消息转换器对象
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
//需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
converter.setObjectMapper(new JacksonObjectMapper());
//将自己的消息转换器加入容器中
converters.add(0,converter);
}
三、启用禁用员工账号
//EmployeeController.java
/**
* 启用禁用员工账号
* @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();
}
//EmployeeServiceImpl.java
/**
* 启用禁用员工账号
* @param status
* @param id
* @return
*/
public void startOrStop(Integer status, Long id) {
//update employee set status=? where id = ?
//为了更通用的使用update方法,在mapper中定义的是通用的update方法,每次传递一个实体对象,而不是修改的属性
// Employee employee = new Employee();
// employee.setStatus(status);
// employee.setId(id);
Employee employee = Employee.builder()
.status(status)
.id(id)
.build();
employeeMapper.update(employee);
}
//EmployeeMapper.xml
<update id="update" parameterType="com.sky.entity.Employee">
update employee
<set>
<if test="name != null">name = #{name},</if>
<if test="username != null">username = #{username},</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="status != null">status = #{status},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="updateUser != null">update_user = #{updateUser},</if>
</set>
where id = #{id}
</update>
四、编辑员工
两个接口,根据id查询员工,修改员工信息
//EmployeeController.java
/**
* 根据id查询员工
* @param id
* @return
*/
@GetMapping("/{id}")
@ApiOperation("根据id查询员工")
public Result<Employee> getById(@PathVariable Long id){
Employee employee = employeeService.getById(id);
return Result.success(employee);
}
/**
* 编辑员工信息
* @param employeeDTO
* @return
*/
@PutMapping
@ApiOperation("编辑员工信息")
public Result update(@RequestBody EmployeeDTO employeeDTO){
log.info("编辑员工信息:{}", employeeDTO);
employeeService.update(employeeDTO);
return Result.success();
}
//EmployeeServiceImpl.java
/**
* 根据id查询员工
* @param id
* @return
*/
public Employee getById(Long id) {
Employee employee = employeeMapper.getById(id);
employee.setPassword("****"); // 将传给前端的密码设置为*
return employee;
}
/**
* 编辑员工信息
* @param employeeDTO
*/
public void update(EmployeeDTO employeeDTO) {
Employee employee = new Employee();
BeanUtils.copyProperties(employeeDTO,employee);
employee.setUpdateTime(LocalDateTime.now());
employee.setUpdateUser(BaseContext.getCurrentId());
employeeMapper.update(employee);
}
//EmployeeMapper.java
/**
* 根据id查询员工
* @param id
* @return
*/
@Select("select * from employee where id = #{id}")
Employee getById(Long id);