# hrm_be **Repository Path**: lcmnb/hrm_be ## Basic Information - **Project Name**: hrm_be - **Description**: 人力资源管理系统后台 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2021-06-12 - **Last Updated**: 2021-11-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # saas-hrm ## 系统架构 1、权限开发:jwt、shiro 2、工作流设计:activiti 7 3、企业报表:poi、jasper 4、代码生成器工具的制作和解析 5、人工智能:人脸登录 接口文档:swagger ![image-20210612145445372](C:\Users\LCM\AppData\Roaming\Typora\typora-user-images\image-20210612145445372.png) ## maven工程结构 夫工程:加载依赖,继承spring父类,springweb、log、test、lombok插件 子公共工程:工具util类、结果entity类、异常处理类 子model工程:实体pojo/domain类,依赖于子公共工程和jpa 企业微服务: ## 微服务架构下的id生成 ​ 多个企业的表可能会合并分析,故数据库自增不适用 ​ uuid 生成全局唯一的id码 ​ 全局redis:网络开销大, ​ **雪花算法**(snowflask)twitter开发,使用程序的方式生成唯一的主键值 ![image-20210610233533136](C:\Users\LCM\AppData\Roaming\Typora\typora-user-images\image-20210610233533136.png) ​ 一个雪花算法生成的id构成(共64bit) springframework 5.1.5 springboot 2.1.3 lombok lastest jdk 1.8 ## jpa下的Dao编写 ```java public interface CompanyDao extends JpaRepository<类名,主键的类型>, JpaSpecificationExecutor<类名> { } ``` > 测试类的类报名需要与启动类的包名一致,否则无法注入 ![image-20210611211813247](C:\Users\LCM\AppData\Roaming\Typora\typora-user-images\image-20210611211813247.png) Company表的CURD ## 跨域问题 前端向后端发请求时会引发跨域问题 解决:在controller类上加上@CrossOrigin ## 自定义异常处理 ```java /** * 自定义异常处理器 * 1、声明@ControllerAdvice * 2、异常处理@ExceptionHandler(value = Exception.class) */ @ControllerAdvice public class BaseExceptionHandler { @ExceptionHandler(value = Exception.class) @ResponseBody public Result error(HttpServletRequest request, HttpServletResponse response){ Result result = new Result(ResultCode.SERVER_ERROR); return result; } } //注意要修改spring的扫描包位置,以扫描注解 ``` ## 多租户数据库方案 多租户技术(Muti-TenancyTechnology)又称多重租赁技术架构 一台数据库服务器运行单个应用实例服务于多个租户(客户),且保证用户数据隔离 ## 数据库设计 试用版:共享数据库 正式版:独立schema设计 ## 企业微服务 1. 企业基本信息 2. 企业组织结构模块 1. 查询时,要根据企业id字段来查询全部部门 ```java public List findDepartments(String companyId){ /** * 用于构造查询条件 * root: 包含对象属性 * cq:高级查询 * cb:构造查询条件 * 拼接得到companyId=root.get("companyId").as(String.class) */ Specification spec = new Specification() { @Override public Predicate toPredicate(Root root, CriteriaQuery cq, CriteriaBuilder cb) { //根据属性去查找 return cb.equal(root.get("companyId").as(String.class),companyId); } }; //根据企业id属性去查询所有的部门字段 return departmentDao.findAll(spec); } ``` 对应的controller ```java /** * 查找部门列表 */ @RequestMapping(value = "/department",method = RequestMethod.GET) public Result findDepartments(){ //设置保存的所属企业id,先使用固定值 String companyId = "1"; List departments = departmentService.findDepartments(companyId); //响应结果 Company company = companyService.findCompanyById(companyId); return new Result(ResultCode.SUCCESS,new DeptListResult(company,departments)); } } ``` 企业id抽取到公共模块controller中,企业id查询抽取到公共模块service中 ## 用户微服务 RBAC模型,基于角色的权限访问控制 ![image-20210616143753988](C:\Users\LCM\AppData\Roaming\Typora\typora-user-images\image-20210616143753988.png) ## 权限分配 ![](C:\Users\LCM\AppData\Roaming\Typora\typora-user-images\image-20210618222708711.png) 表结构设计 ## 验证机制 token auth 1、客户端请求服务器时验证用户名密码,通过签发token 2、token响应回客户端,客户端将token存放于cookie中 3、之后每次请求都带着签发的token 4、验证成功则向客户端返回请求数据 **json web token (JWT)**:一套规范,java中可以通过jjwt库生成token字符串 common工具类中,私钥、失效时间L、设置认证token方法、解析token字符串得到claims方法 ## 有状态服务和无状态服务 **无状态服务**:服务器不储存请求上下文的数据信息,每次请求之间没有关系。例子:存储在cookie或请求头的token信息 **有状态服务**:服务器存储请求上下文数据信息。例子:通过session将数据存放在服务器端,客户端通过cookie存储sessionid - 传统session不适用于微服务 - redis模拟session存储数据 ## no session问题 - spring-data-jpa使用的hibernate使用session对象与数据库交互 - **延迟加载(懒加载)**:在同一个session对象内,hibernate会在查询结果被使用时才会去数据库中进行真正的查询。 - 如果session第一次查找中有延迟加载,查找完之后关闭了session,这时再想使用延迟加载的数据,就得再次调用session查找,但此时session已经关闭,所以发生no session问题 ```java //z过滤器使得页面显示完后才关闭session,解决no session问题 @Bean public OpenEntityManagerInViewFilter openEntityManagerInViewFilter(){ return new OpenEntityManagerInViewFilter(); } ``` ## shiro安全框架 apache shiro 身份验证、授权、加密、会话管理、web集成、缓存 **spring** **security** 相似 ********基于ini配置文件的用户认证******** 1. 加载ini配置文件创建SecurityManagerFactory 2. 通过工厂类获取securityManager 3. 通过securityUtils将securityManager绑定到当前运行环境 4. 创建主体Subject(此时的主体还未经过认证) 5. 构造主体登录的凭证(即用户名/密码) 1. UsernamePasswordToken(Username,Password) 2. subject.login(token) 3. subject.isAuthenticated 4. subject.getPrincipal 5. subject.isPermitted 6. subject.hasRole ********自定义的realm******** 继承AuthorizingRealm 重写doGetAuthorizationInfo(授权方法:获取用户授权信息)、doGetAuthenticationInfo(认证方法:根据用户名密码登录并保存数据)、setName(当前realm域名称 ) **shiro的MD5加密** Md5Hash(password,混淆字符串,加密次数) **shiro会话管理** SessionManager:顶层组件(接口),由SecurityManager管理,用于管理subject的session 三个默认实现: ​ 1、DefaultSessionManager:用于JavaSE环境 ​ 2、ServletContainerSessionManager:用于Web环境,直接使用servlet容器的会话。默认 ​ 3、DefaultWebSessionManager:用于web环境,自己维护会话(自己维护着会话,直接废弃了Servlet容器的会话管理)。 ![image-20210627171327778](C:\Users\LCM\AppData\Roaming\Typora\typora-user-images\image-20210627171327778.png) ![image-20210627204950622](C:\Users\LCM\AppData\Roaming\Typora\typora-user-images\image-20210627204950622.png) > 区别的流程 ## Eureka 服务发现框架 分为server组件和client组件 client:各个java微服务 + 负载均衡器 server:注册各个微服务服务