技术选型
Nginx反向代理与负载均衡
负载均衡
反向代理
nginx.conf文件如下(实现跨域):
用户脱敏
为了用户隐私安全,数据库存储的登录密码一般不以明文存储,而是通过加密算法后再存储,一般加密算法用md5等,因此前端要想通过用户登录校验,就需要在后端用户登录方法中对输入的密码进行同样的算法加密,才能匹配上数据库的密码,从而正常登录
新增员工
DTO:当controller方法所需参数并不完整需要实体类所有参数时,可以封装一个请求体,只包含请求所需要的参数,这个请求体就叫DTO,采用DTO可以使前端人员在进行postman调试时更加清楚哪些参数是必要的,方便开发
比如用户登录,只需要id、username、name、phone、sex、idNumber等参数,不需要其他参数了(员工实体类包含有其他参数)
controller层:调用持久层方法
service实现类(持久层)实现方法:由于请求体DTO只传递必要的参数,而向数据库新增用户肯定是包含一些其他字段的,所以需要把DTO转换为对应的实体类,使用拷贝方法copyProperties,这样没传的参数在实体类对象中被设置为null
注意这里使用MP更好
TODO:接口文档发送请求携带token,否则无法通过jwt令牌校验,前端人员无法测试发送请求,token也可能会过期
全局异常处理器
这里不是采取后端代码对用户名进行校验,而是在用户名重复的时候对异常进行拦截处理
正常来说,应该在编写代码的时候就考虑的用户名重复的情况,并在后端对其做校验
像"已存在"这类字符串最好封装成常量类的某个常量
动态获取id
上面在新增用户的时候,用户id采用固定的10L,现在要修改成每个用户有各自的id
首先是jwt令牌认证,过程如下,生成的jwt token时将用户id放进去了
具体流程
TODO 为什么是先登录获取用户id,再新增用户?
用户登陆成功生成jwt token
用户生成jwt token之后的每次登录都会在请求头requestHeader中携带该token,通过token拦截器可以获取该token,并进行校验,从而再次登录
从token中获取到用户id,然后将该用户id(当前登录用户),传到新增用户的setCreateUser、setUpdateUser中,由于每次请求(调用一个controller方法)是一个线程,只有在线程内才能获取到对应的值(新增用户是一个请求,用户登录是一个请求,所以新增用户与用户登录是两个线程,用户登录token中获取到的用户id不能传给新增用户所需要的setCreateUser、setUpdateUser),所以需要一个全局存储器来存储这个用户id,实现跨线程使用
TODO 既然使用ThreadLocal来存储并共享使用变量,为什么还说成是具有线程隔离效果?不应该是解决线程隔离问题吗?
全局存储器
存储变量
获取变量
用户分页查询
封装请求体DTO
封装通用返回结果
封装分页查询结果
封装前端返回结果
实际上我觉得这里使用VO更好
具体实现
controller层
service层
service实现类
视频里采用pageHelper来分页(不用mp就老是要去mapper里写对应的sql语句),我更倾向于使用mp的querywrapper来分页
分页查询结果日期格式化
数据库里存储时间的数据类型是列表,渲染到前端就是一整串数字而不是常见的时间格式,所以需要格式化
启用禁用员工账号
controller层 通过url传参,使用@PathVariable注解,如果参数名一致则不需要额外指明从url中取哪个参数
service层
service实现类 没必要用构建器(@Builder注解),正常的new对象就可以了
编辑员工
根据id查询员工
controller
service
service实现类:这里将密码手动设置成隐藏的形式,最好是使用VO将结果返回给前端
修改员工数据
controller
service
service实现类:我不支持这种做法,因为如果原先数据库中员工所有字段都是有值的,如果只拷贝请求体的参数,那些本来有值的字段就变成null了,丢失数据,最好避免这种做法,还是手动改比较好(用MP更轻松)TODO
公共字段自动填充
存在的问题
实现方法
编写完后记得删除原来的手动设置
封装枚举类
自定义注解
定义切面类
切入点@PointCut注解定义了要拦截的方法所在的位置 和 所使用的注解 使用前置通知,实现在数据库更新操作之前拦截方法,JoinPoint可以获取到拦截到的方法、注解、参数等