当前位置: 首页 > news >正文

API网关与社保模块

API网关与社保模块

理解zuul网关的作用完成zuul网关的搭建

实现社保模块的代码开发

zuul网关

在学习完前面的知识后,微服务架构已经初具雏形。但还有一些问题:不同的微服务一般会有不同的网 络地址,客户端在访问这些微服务时必须记住几十甚至几百个地址,这对于客户端方来说太复杂也难以 维护。如下图:

如果让客户端直接与各个微服务通讯,可能会有很多问题:

  • 客户端会请求多个不同的服务,需要维护不同的请求地址,增加开发难度

  • 在某些场景下存在跨域请求的问题

  • 加大身份认证的难度,每个微服务需要独立认证

因此,我们需要一个微服务网关,介于客户端与服务器之间的中间层,所有的外部请求都会先经过微服

务网关。客户端只需要与网关交互,只知道一个网关地址即可,这样简化了开发还有以下优点:

1、易于监控

2、易于认证

3、减少了客户端与各个微服务之间的交互次数

API网关是一个服务器,是系统对外的唯一入口。API网关封装了系统内部架构,为每个客户端提供 一个定制的API。API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在 网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。

什么是zuul网关

ZUUL是Netflflix开源的微服务网关,它可以和Eureka、Ribbon、Hystrix等组件配合使用,Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:

  • 动态路由:动态将请求路由到不同后端集群

  • 压力测试:逐渐增加指向集群的流量,以了解性能

  • 负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求静态响应处理:边缘位置进行响应,避免转发到内部集群

  • 身份认证和安全: 识别每一个资源的验证要求,并拒绝那些不符的请求。Spring Cloud对Zuul进行了整合和增强。

Spring Cloud对Zuul进行了整合和增强

Zuul加入后的架构

不管是来自于客户端(PC或移动端)的请求,还是服务内部调用。一切对服务的请求都会经过Zuul这个 网关,然后再由网关来实现 鉴权、动态路由等等操作。Zuul就是我们服务的统一入口。

快速入门

工程搭建

创建工程 ihrm_gate ,并导入zuul网关的响应依赖


    <dependencies><!--eureka客户端--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--zuul网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>com.ihrm</groupId><artifactId>ihrm_common</artifactId><version>1.0-SNAPSHOT</version><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></exclusion></exclusions></dependency></dependencies>

编写启动类

在网关工程中的 com.ihrm.gate 下创建启动类 GateApplication


package com.ihrm.gate;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;//声明boot工程
@SpringBootApplication(scanBasePackages="com.ihrm")
//开启zuul网关功能
@EnableZuulProxy
public class GateApplication {public static void main(String[] args) {SpringApplication.run(GateApplication.class);}
}

@EnableZuulProxy注解开启Zuul网关功能

编写配置文件

#注册到eureka的服务地址
eureka:client:service-url:defaultZone: http://127.0.0.1:6868/eureka/instance:preferIpAddress : trueinstance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
#服务配置
server:port: 9090
#spring配置
spring:#1.应用配置application:name: ihrm-gate #指定服务名redis:host: 127.0.0.1port: 6379
#配置路由规则
zuul:routes:#路由id,随便写ihrm-company:path: /company/** #需要映射的路径地址#url: http://127.0.0.1:9001 #映射路径对应的实际微服务的url路径serviceId: ihrm-company#zuul 自动的会删除请求的前缀 http://127.0.0.1:9001/companystripPrefix: false #不删除请求前缀

配置路由规则

通过zuul网关请求企业微服务,需要在application.yml中配置路由转发规则如下

#配置路由规则
zuul:routes:#路由id,随便写ihrm-company:path: /company/** #需要映射的路径地址url: http://127.0.0.1:9001 #映射路径对应的实际微服务的url路径#zuul 自动的会删除请求的前缀 http://127.0.0.1:9001/companystripPrefix: false #不删除请求前缀

骚戴理解:例如前端发的请求是http://localhost:9090/company,其中9090是zuul网关的端口号,然后就会匹配到path路径,因为符合/company/**,匹配上后会把http://localhost:9090/替换成http://127.0.0.1:9001,然后把/company拼接在后面,最终成http://127.0.0.1:9001/company,这是在配置了stripPrefix: false的情况下,如果没有配置这个,那就需要发请求的时候是http://localhost:9090/company/company,因为zuul网关会自动删除掉前缀/company

注释

代码

作用

配置路由规则

zuul:

配置Zuul网关的路由规则

路由id,随便写

ihrm-company:

设置路由的id,可以随意命名

需要映射的路径地址

path: /company/**

配置需要映射的路径地址,即客户端请求的路径地址

映射路径对应的实际微服务的url路径

url: http://127.0.0.1:9001

配置映射路径对应的实际微服务的url路径,即请求需要转发到的服务地址

zuul 自动的会删除请求的前缀 http://127.0.0.1:9001/company

stripPrefix: false

配置是否删除请求前缀,这里设置为false,表示不删除请求前缀

路由配置

在刚才的路由规则中,我们把路径对应的服务地址写死了!如果同一服务有多个实例的话,这样做显然 就不合理了。我们应该根据服务的名称,去Eureka注册中心查找服务对应的所有实例列表,然后进行动态路由才对!

添加Eureka客户端发现功能

  • 添加eureka依赖


    <dependencies><!--eureka客户端--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--zuul网关--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>com.ihrm</groupId><artifactId>ihrm_common</artifactId><version>1.0-SNAPSHOT</version><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></exclusion></exclusions></dependency></dependencies>
  • 修改启动类,开启服务发现功能


package com.ihrm.gate;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;//声明boot工程
@SpringBootApplication(scanBasePackages="com.ihrm")
//开启zuul网关功能
@EnableZuulProxy
//开启服务发现功能
@EnableDiscoveryClient
public class GateApplication {public static void main(String[] args) {SpringApplication.run(GateApplication.class);}
}

修改配置文件

  • 在application.xml中添加eureka服务发现的相关配置信息

#注册到eureka的服务地址
eureka:client:service-url:defaultZone: http://127.0.0.1:6868/eureka/instance:preferIpAddress : trueinstance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
#服务配置
server:port: 9090
#spring配置
spring:#1.应用配置application:name: ihrm-gate #指定服务名redis:host: 127.0.0.1port: 6379
#配置路由规则
zuul:routes:#路由id,随便写ihrm-company:path: /company/** #需要映射的路径地址#url: http://127.0.0.1:9001 #映射路径对应的实际微服务的url路径serviceId: ihrm-company#zuul 自动的会删除请求的前缀 http://127.0.0.1:9001/companystripPrefix: false #不删除请求前缀

zuul网关从eureka注册中心中获取服务提供者的所有数据

骚戴理解:解释一下下面的配置内容

#注册到eureka的服务地址
eureka:client:service-url:defaultZone: http://127.0.0.1:6868/eureka/instance:preferIpAddress : trueinstance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}

注释

代码

作用

注册到eureka的服务地址

eureka:

配置Eureka注册中心的相关信息

配置Eureka客户端的服务地址

eureka.client.service-url.defaultZone: http://127.0.0.1:6868/eureka/

配置Eureka客户端注册中心的服务地址,即Eureka Server的地址

配置Eureka客户端实例的信息

eureka.instance

配置Eureka客户端实例的信息,包括优先使用IP地址、实例ID等信息

优先使用IP地址

preferIpAddress : true

配置Eureka客户端实例优先使用IP地址

实例ID

instance-id: {spring.cloud.client.ip-address}:spring.cloud.client.ip−address:{spring.application.name}:${server.port}

配置Eureka客户端实例的ID,使用${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}表达式,其中${spring.cloud.client.ip-address}表示客户端的IP地址,${spring.application.name}表示应用名称,${server.port}表示应用端口号。

  • 修改zuul路由的映射规则

因为已经有了Eureka客户端,我们可以从Eureka获取服务的地址信息,因此映射时无需指定IP地址,而 是通过serviceId: ihrm-company来指定服务名称访问,而且Zuul已经集成了Ribbon的负载均衡功能。

zuul:routes:ihrm-company: # 这里是路由id,随意写path: /ihrm-company/** # 这里是映射路径serviceId: ihrm-company # 指定服务名称

简化配置

在刚才的配置中,我们的规则是这样的:

  • zuul.routes.<route>.path=/xxx/** : 来指定映射路径。 <route> 是自定义的路由名

  • zuul.routes.<route>.serviceId=/user-service :来指定服务名。

而大多数情况下,我们的 <route> 路由名称往往和 服务名会写成一样的。因此Zuul就提供了一种简化的配置语法: zuul.routes.<serviceId>=<path>

比方说上面我们关于user-service的配置可以简化为一条(省去了对服务名称的配置):


zuul:routes:ihrm-company: /ihrm-company/** # 这里是映射路径

在使用Zuul的过程中,上面讲述的规则已经大大的简化了配置项。但是当服务较多时,配置也是比较繁 琐的。因此Zuul就指定了默认的路由规则:

  • 默认情况下,一切服务的映射路径就是服务名本身。例如服务名为: ihrm-company ,则默认的映射路径就是: /ihrm-company/**

也就是说,刚才的映射规则我们完全不配置也是可以的

前端修改

由于使用了zuul网关统一对所有微服务进行转发,那么我们在前端系统调用的时候,只需要向网关服务 器发送请求即可。在前端框架中的 config/index.js 中修改请求URL

基于Zuul的统一鉴权

spring cloud Zuul包含了对请求的路由和过滤2个功能。路由功能负责将请求转发到具体的微服务上, 而过滤器负责对请求的处理过程进行干预,是实现权限校验、服务聚合等功能的基础。

Zuul的过滤器

ZuulFilter

ZuulFilter是过滤器的顶级父类。在这里我们看一下其中定义的4个最重要的方法:


public abstract ZuulFilter implements IZuulFilter{abstract public String filterType();abstract public int filterOrder();boolean shouldFilter();// 来自IZuulFilterObject run() throws ZuulException;// IZuulFilter
}

shouldFilter :返回一个 Boolean 值,判断该过滤器是否需要执行。返回true执行,返回false 不执行。

run :过滤器的具体业务逻辑。

filterType :返回字符串,代表过滤器的类型。包含以下4种:

  • pre :请求在被路由之前执行

  • routing :在路由请求时调用

  • post :在routing和errror过滤器之后调用

  • error :处理请求时发生错误调用

filterOrder :通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。

自定义过滤器

接下来我们来自定义一个过滤器,用于深入理解zuul过滤器的执行过程


package com.ihrm.gate.filter;import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;/*** 自定义过滤器*/
//@Component
public class LoginFilter extends ZuulFilter {/*** String类型的返回值*  定义过滤器类型的*      pre     : 在执行路由请求之前执行*      routing : 在路由请求时调用*      post    : 在routing和error过滤器之后执行*      error   : 处理请求出现异常的时候执行*/public String filterType() {return "pre";}/*** int类型的返回值*  定义过滤器的优先级 : 数字越小,优先级越高*/public int filterOrder() {return 2;}/*** boolean类型的返回值*  判断过滤器是否需要执行**/public boolean shouldFilter() {//对某些请求过滤(不执行过滤器)return true;}/*** run方法 : 过滤器中负责的具体业务逻辑*  使用过滤器进行jwt的鉴权*/public Object run() throws ZuulException {//System.out.println("执行了LoginFilter的run方法");//1.获取请求对象request//1.1 获取Zuul提供的请求上下文的对象(工具类)RequestContext rc = RequestContext.getCurrentContext();//1.2 从上下文对象获取request对象HttpServletRequest request = rc.getRequest();//2.从request中获取Authorization的头信息String token = request.getHeader("Authorization");//3.判断if(token == null || "".equals(token)) {//没有传递token信息,需要登录,拦截rc.setSendZuulResponse(false);//返回错误的401状态码rc.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());}return null;}}

过滤器执行生命周期

这张是Zuul官网提供的请求生命周期图,清晰的表现了一个请求在各个过滤器的执行顺序。

正常流程:

  • 请求到达首先会经过pre类型过滤器,而后到达routing类型,进行路由,请求就到达真正的 服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。

异常流程:

  • 整个过程中,pre或者routing过滤器出现异常,都会直接进入error过滤器,再error处理完毕 后,会将请求交给POST过滤器,最后返回给用户。

  • 如果是error过滤器自己出现异常,最终也会进入POST过滤器,而后返回。

  • 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和routing不同的时,请求 不会再到达POST过滤器了。

所有内置过滤器列表:

使用场景

场景非常多:

  • 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了

  • 异常处理:一般会在error类型和post类型过滤器中结合来处理。

  • 服务调用时长统计:pre和post结合使用。

统一鉴权

基于JWT的统一鉴权

在某些应用中,往往使用JWT的形式进行无状态的用户鉴权。对于JWT的鉴权,只需要使用Zuul的自定义过滤器,在过滤器中判断是否携带JWT的token信息即可。


    public Object run() throws ZuulException {//System.out.println("执行了LoginFilter的run方法");//1.获取请求对象request//1.1 获取Zuul提供的请求上下文的对象(工具类)RequestContext rc = RequestContext.getCurrentContext();//1.2 从上下文对象获取request对象HttpServletRequest request = rc.getRequest();//2.从request中获取Authorization的头信息String token = request.getHeader("Authorization");//3.判断if(token == null || "".equals(token)) {//没有传递token信息,需要登录,拦截rc.setSendZuulResponse(false);//返回错误的401状态码rc.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());}return null;}

基于Shiro的统一鉴权

由于我们的系统使用shiro结合自定义session的形式,相当于将用户数据存储到了分布式缓存redis中。 那么只需要再zuul中使用shiro即可完成统一用户权限校验

  • 引入shiro依赖


<dependency><groupId>com.ihrm</groupId><artifactId>ihrm_common</artifactId><version>1.0-SNAPSHOT</version>
</dependency>
  • 配置shiro


package com.ihrm.gate;import com.ihrm.common.shiro.realm.IhrmRealm;
import com.ihrm.common.shiro.session.CustomSessionManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.LinkedHashMap;
import java.util.Map;@Configuration
public class ShiroConfiguration {//1.创建realm@Beanpublic IhrmRealm getRealm() {return new IhrmRealm();}//2.创建安全管理器@Beanpublic SecurityManager getSecurityManager(IhrmRealm realm) {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(realm);//将自定义的会话管理器注册到安全管理器中securityManager.setSessionManager(sessionManager());//将自定义的redis缓存管理器注册到安全管理器中securityManager.setCacheManager(cacheManager());return securityManager;}//3.配置shiro的过滤器工厂/*** 再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制**/@Beanpublic ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {//1.创建过滤器工厂ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();//2.设置安全管理器filterFactory.setSecurityManager(securityManager);//3.通用配置(跳转登录页面,未授权跳转的页面)filterFactory.setLoginUrl("/autherror?code=1");//跳转url地址filterFactory.setUnauthorizedUrl("/autherror?code=2");//未授权的url//4.设置过滤器集合Map<String,String> filterMap = new LinkedHashMap<>();//anon -- 匿名访问filterMap.put("/sys/login","anon");filterMap.put("/autherror","anon");//注册//authc -- 认证之后访问(登录)filterMap.put("/**","authc");//perms -- 具有某中权限 (使用注解配置授权)filterFactory.setFilterChainDefinitionMap(filterMap);return filterFactory;}@Value("${spring.redis.host}")private String host;@Value("${spring.redis.port}")private int port;/*** 1.redis的控制器,操作redis*/public RedisManager redisManager() {RedisManager redisManager = new RedisManager();redisManager.setHost(host);redisManager.setPort(port);return redisManager;}/*** 2.sessionDao*/public RedisSessionDAO redisSessionDAO() {RedisSessionDAO sessionDAO = new RedisSessionDAO();sessionDAO.setRedisManager(redisManager());return sessionDAO;}/*** 3.会话管理器*/public DefaultWebSessionManager sessionManager() {CustomSessionManager sessionManager = new CustomSessionManager();//sessionManager.setSessionIdCookieEnabled(false);sessionManager.setSessionIdUrlRewritingEnabled(false);sessionManager.setSessionDAO(redisSessionDAO());return sessionManager;}/*** 4.缓存管理器*/public RedisCacheManager cacheManager() {RedisCacheManager redisCacheManager = new RedisCacheManager();redisCacheManager.setRedisManager(redisManager());return redisCacheManager;}//开启对shior注解的支持@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();advisor.setSecurityManager(securityManager);return advisor;}
}

由于再zuul网关中已经进行了统一的权限校验,那么其它微服务的权限校验就可以关闭了。

传递敏感header

经过测试可以发现在网关中明明已经具备了权限,可以在具体的微服务中还是会告知权限不足或者没有 找到相关用户。这是因为在Zuul进行请求转发的时候,会把header清空,为了传递原始的header信息 到最终的微服务,在配置加上:


zuul.routes.xxx.sentiviteHeaders:	#将指定路由的敏感头设置为空
zuul.routes.xxx.customSensitiveHeaders: true #对指定路由开启自定义敏感头

完整的gate配置文件

#注册到eureka的服务地址
eureka:client:service-url:defaultZone: http://127.0.0.1:6868/eureka/instance:preferIpAddress : trueinstance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
#服务配置
server:port: 9090
#spring配置
spring:#1.应用配置application:name: ihrm-gate #指定服务名redis:host: 127.0.0.1port: 6379
#配置路由规则
zuul:routes:#路由id,随便写ihrm-company:path: /company/** #需要映射的路径地址#url: http://127.0.0.1:9001 #映射路径对应的实际微服务的url路径serviceId: ihrm-company#zuul 自动的会删除请求的前缀 http://127.0.0.1:9001/companystripPrefix: false #不删除请求前缀#处理敏感头信息sentiviteHeaders:   #将指定路由的敏感头设置为空customSensitiveHeaders: true #对指定路由开启自定义敏感头ihrm-system: #系统path: /sys/** #配置请求URL的请求规则serviceId: ihrm-system #指定Eureka注册中心中的服务idstripPrefix: falsesentiviteHeaders:   #将指定路由的敏感头设置为空customSensitiveHeaders: true #对指定路由开启自定义敏感头ihrm-employee: #员工path: /employees/** #配置请求URL的请求规则serviceId: ihrm-employee #指定Eureka注册中心中的服务idstripPrefix: falsesentiviteHeaders:   #将指定路由的敏感头设置为空customSensitiveHeaders: true #对指定路由开启自定义敏感头ihrm-social-securitys: #社保path: /social_securitys/** #配置请求URL的请求规则serviceId: ihrm-social-securitys #指定Eureka注册中心中的服务idstripPrefix: falsesentiviteHeaders:   #将指定路由的敏感头设置为空customSensitiveHeaders: true #对指定路由开启自定义敏感头ihrm-atte-cfg: #社保path: /cfg/** #配置请求URL的请求规则serviceId: ihrm-attendance #指定Eureka注册中心中的服务idstripPrefix: falsesentiviteHeaders:   #将指定路由的敏感头设置为空customSensitiveHeaders: true #对指定路由开启自定义敏感头ihrm-atte-attendances: #社保path: /attendances/** #配置请求URL的请求规则serviceId: ihrm-attendance #指定Eureka注册中心中的服务idstripPrefix: falsesentiviteHeaders:   #将指定路由的敏感头设置为空customSensitiveHeaders: true #对指定路由开启自定义敏感头

社保管理

需求分析

完成社保模板相关代码开发:

  • 企业员工参保设置

  • 企业月度社保明细

  • 企业社保归档数据

数据库表

  • 社保归档表


CREATE TABLE `ss_archive` (
`id` varchar(40) NOT NULL COMMENT 'id',
`company_id` varchar(40) NOT NULL COMMENT '企业id',
`years_month` varchar(255) NOT NULL COMMENT '年月',
`creation_time` date NOT NULL COMMENT '创建时间',
`enterprise_payment` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '企业缴纳',
`personal_payment` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '个人缴纳',
`total` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '合计', PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='社保-归档表'
  • 社保-归档详情表


CREATE TABLE `ss_archive_detail` (
`id` varchar(40) NOT NULL COMMENT 'id',
`archive_id` varchar(40) NOT NULL COMMENT '归档id',
`user_id` varchar(40) DEFAULT NULL COMMENT '用户id',
`username` varchar(255) DEFAULT NULL COMMENT '用户名称',
`time_of_entry` varchar(255) DEFAULT NULL COMMENT '入职时间',
`mobile` varchar(255) DEFAULT NULL COMMENT '手机号',
`id_number` varchar(255) DEFAULT NULL COMMENT '身份证号',
`the_highest_degree_of_education` varchar(255) DEFAULT NULL COMMENT '学历',
`opening_bank` varchar(255) DEFAULT NULL COMMENT '开户行',
`bank_card_number` varchar(255) DEFAULT NULL COMMENT '银行卡号',
`first_level_department` varchar(255) DEFAULT NULL COMMENT '一级部门',
`two_level_department` varchar(255) DEFAULT NULL COMMENT '二级部门',
`working_city` varchar(255) DEFAULT NULL COMMENT '工作城市',
`social_security_computer_number` varchar(255) DEFAULT NULL COMMENT '社保电脑号',
`provident_fund_account` varchar(255) DEFAULT NULL COMMENT '公积金账号',
`leave_date` varchar(255) DEFAULT NULL COMMENT '离职时间',
`household_registration_type` varchar(255) DEFAULT NULL COMMENT '户籍类型',
`participating_in_the_city` varchar(255) DEFAULT NULL COMMENT '参保城市',
`social_security_month` varchar(255) DEFAULT NULL COMMENT '社保月份',
`social_security_base` decimal(10,2) DEFAULT NULL COMMENT '社保基数',
`social_security` decimal(10,2) DEFAULT NULL COMMENT '社保合计',
`social_security_enterprise` decimal(10,2) DEFAULT NULL COMMENT '社保企业',
`social_security_individual` decimal(10,2) DEFAULT NULL COMMENT '社保个人',
`provident_fund_city` varchar(255) DEFAULT NULL COMMENT '公积金城市',
`provident_fund_month` varchar(255) DEFAULT NULL COMMENT '公积金月份',
`provident_fund_base` decimal(10,2) DEFAULT NULL COMMENT '公积金基数',
`accumulation_fund_enterprise_base` decimal(10,2) DEFAULT NULL COMMENT '公积金企业基数',
`proportion_of_provident_fund_enterprises` decimal(10,2) DEFAULT NULL COMMENT '公积金企业比例',
`individual_base_of_provident_fund` decimal(10,2) DEFAULT NULL COMMENT '公积金
个人基数',
`personal_ratio_of_provident_fund` decimal(10,2) DEFAULT NULL COMMENT '公积金个人比例',
`total_provident_fund` decimal(10,2) DEFAULT NULL COMMENT '公积金合计',
`provident_fund_enterprises` decimal(10,2) DEFAULT NULL COMMENT '公积金企业',
`provident_fund_individual` decimal(10,2) DEFAULT NULL COMMENT '公积金个人',
`pension_enterprise_base` decimal(10,2) DEFAULT NULL COMMENT '养老企业基数',
`proportion_of_pension_enterprises` decimal(10,2) DEFAULT NULL COMMENT '养老企业比例',
`pension_enterprise` decimal(10,2) DEFAULT NULL COMMENT '养老企业',
`personal_pension_base` decimal(10,2) DEFAULT NULL COMMENT '养老个人基数',
`personal_pension_ratio` decimal(10,2) DEFAULT NULL COMMENT '养老个人比例',
`old_age_individual` decimal(10,2) DEFAULT NULL COMMENT '养老个人',
`unemployment_enterprise_base` decimal(10,2) DEFAULT NULL COMMENT '失业企业基数',
`proportion_of_unemployed_enterprises` decimal(10,2) DEFAULT NULL COMMENT '失业企业比例',
`unemployed_enterprise` decimal(10,2) DEFAULT NULL COMMENT '失业企业',
`the_number_of_unemployed_individuals` decimal(10,2) DEFAULT NULL COMMENT '失业个人基数',
`percentage_of_unemployed_individuals` decimal(10,2) DEFAULT NULL COMMENT '失业个人比例',
`unemployed_individual` decimal(10,2) DEFAULT NULL COMMENT '失业个人',
`medical_enterprise_base` decimal(10,2) DEFAULT NULL COMMENT '医疗企业基数',
`proportion_of_medical_enterprises` decimal(10,2) DEFAULT NULL COMMENT '医疗企业比例',
`medical_enterprise` decimal(10,2) DEFAULT NULL COMMENT '医疗企业',
`medical_personal_base` decimal(10,2) DEFAULT NULL COMMENT '医疗个人基数',
`medical_personal_ratio` decimal(10,2) DEFAULT NULL COMMENT '医疗个人比例',
`medical_individual` decimal(10,2) DEFAULT NULL COMMENT '医疗个人',
`base_of_industrial_injury_enterprises` decimal(10,2) DEFAULT NULL COMMENT '工伤企业基数',
`proportion_of_industrial_injury_enterprises` decimal(10,2) DEFAULT NULL COMMENT '工伤企业比例',
`industrial_injury_enterprise` decimal(10,2) DEFAULT NULL COMMENT '工伤企业',
`fertility_enterprise_base` decimal(10,2) DEFAULT NULL COMMENT '生育企业基数',
`proportion_of_fertility_enterprises` decimal(10,2) DEFAULT NULL COMMENT '生育企业比例',
`childbearing_enterprise` decimal(10,2) DEFAULT NULL COMMENT '生育企业',
`base_of_serious_illness` decimal(10,2) DEFAULT NULL COMMENT '大病企业基数',
`proportion_of_seriously_ill_enterprises` decimal(10,2) DEFAULT NULL COMMENT '大病企业比例',
`big_disease_enterprise` decimal(10,2) DEFAULT NULL COMMENT '大病企业',
`personal_base_of_serious_illness` decimal(10,2) DEFAULT NULL COMMENT '大病个人基数',
`personal_proportion_of_serious_illness` decimal(10,2) DEFAULT NULL COMMENT '大病个人比例',
`a_person_of_great_disease` decimal(10,2) DEFAULT NULL COMMENT '大病个人',
`provident_fund_notes` text COMMENT '公积金备注',
`social_security_notes` text COMMENT '社保备注', PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='社保-归档详情'
  • 社保-城市与缴费项目关联表


CREATE TABLE `ss_city_payment_item` (
`id` varchar(40) NOT NULL,
`city_id` varchar(40) NOT NULL COMMENT '城市id',
`payment_item_id` varchar(40) NOT NULL COMMENT '缴费项目id',
`switch_company` tinyint(1) NOT NULL COMMENT '企业是否缴纳开关,0为禁用,1为启用',
`scale_company` decimal(6,2) DEFAULT NULL COMMENT '企业比例',
`switch_personal` tinyint(1) NOT NULL COMMENT '个人是否缴纳开关,0为禁用,1为启用',
`scale_personal` decimal(6,2) DEFAULT NULL COMMENT '个人比例', PRIMARY KEY (`id`),
UNIQUE KEY `UK_CID_PIID` (`city_id`,`payment_item_id`) USING BTREE COMMENT '城市id与缴费项目id组合唯一'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='社保-城市与缴费项目关联表'
  • 社保-企业设置信息


CREATE TABLE `ss_company_settings` (
`company_id` varchar(40) NOT NULL COMMENT '企业id',
`is_settings` tinyint(1) NOT NULL DEFAULT '0' COMMENT '0是未设置,1是已设置',
`data_month` varchar(40) NOT NULL COMMENT '当前显示报表月份', PRIMARY KEY (`company_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='社保-企业设置信息'
  • 社保-缴费项目


CREATE TABLE `ss_payment_item` (
`id` varchar(40) NOT NULL COMMENT 'id',
`name` varchar(255) NOT NULL COMMENT '缴费项目名称',
`switch_company` tinyint(1) NOT NULL DEFAULT '0' COMMENT '企业是否缴纳开关,0为禁用,1为启用',
`scale_company` decimal(6,2) NOT NULL DEFAULT '0.00' COMMENT '企业比例',
`switch_personal` tinyint(1) NOT NULL DEFAULT '0' COMMENT '个人是否缴纳开关,0为禁用,1为启用',
`scale_personal` decimal(6,2) NOT NULL DEFAULT '0.00' COMMENT '个人比例', PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='社保-缴费项目'
  • 社保-用户社保信息表


CREATE TABLE `ss_user_social_security` (
`user_id` varchar(40) NOT NULL COMMENT '用户id',
`enterprises_pay_social_security_this_month` tinyint(1) NOT NULL DEFAULT '0' COMMENT '本月是否缴纳社保 0为不缴纳 1为缴纳',
`enterprises_pay_the_provident_fund_this_month` tinyint(1) NOT NULL DEFAULT '0' COMMENT '本月是否缴纳公积金 0为不缴纳 1为缴纳',
`participating_in_the_city_id` varchar(40) NOT NULL COMMENT '参保城市id',
`social_security_type` tinyint(1) NOT NULL DEFAULT '2' COMMENT '参保类型 1为首次开户 2为非首次开户',
`household_registration_type` tinyint(1) NOT NULL COMMENT '户籍类型 1为本市城镇 2
为本市农村 3为外埠城镇 4为外埠农村',
`social_security_base` int(8) NOT NULL COMMENT '社保基数',
`industrial_injury_ratio` decimal(6,2) DEFAULT NULL COMMENT '工伤比例',
`social_security_notes` varchar(300) DEFAULT NULL COMMENT '社保备注',
`provident_fund_city_id` varchar(40) NOT NULL COMMENT '公积金城市id',
`provident_fund_base` int(8) NOT NULL COMMENT '公积金基数',
`enterprise_proportion` decimal(6,2) NOT NULL COMMENT '公积金企业比例',
`personal_proportion` decimal(6,2) NOT NULL COMMENT '公积金个人比例',
`enterprise_provident_fund_payment` decimal(8,2) NOT NULL COMMENT '公积金企业缴纳数额',
`personal_provident_fund_payment` decimal(8,2) NOT NULL COMMENT '公积金个人缴纳数额',
`provident_fund_notes` varchar(300) DEFAULT NULL COMMENT '公积金备注',
`create_time` datetime NOT NULL COMMENT '创建时间',
`last_modify_time` datetime NOT NULL COMMENT '最后修改时间',
`social_security_switch_update_time` datetime NOT NULL COMMENT '社保是否缴纳变更时间',
`provident_fund_switch_update_time` datetime NOT NULL COMMENT '公积金是否缴纳变更时间',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='社保-用户社保信息表'

搭建环境

  1. 使用代码生成工具,根据数据库表生成最基本的实体类,dao接口和service层代码。 略

  1. 创建社保管理模块ihrm_social_securitys,并将自动生成的代码依次copy到响应的包下。

  1. 修改zuul网关,添加社保相关的请求转发


ihrm-social-securitys: #企业
path: /social_securitys/** #配置请求URL的请求规则
serviceId: ihrm-social-securitys #指定Eureka注册中心中的服务id strip-prefix: false
sentiviteHeaders: customSensitiveHeaders: true

社保列表

企业社保设置

企业第一次进入社保页面,会要求输入制作社保记录的日期


/**
* 获取企业是否设置社保
* @return
*/
@RequestMapping(value = "/settings", method = RequestMethod.GET)
public Result getSettings() throws Exception {CompanySettings companySettings =
companySettingsService.findById(companyId);return new Result(ResultCode.SUCCESS, companySettings);
}
/**
* 保存企业社保设置
*/
@RequestMapping(value = "/settings", method = RequestMethod.POST)
public Result saveSettings(@RequestBody CompanySettings companySettings){companySettings.setCompanyId(companyId);companySettingsService.save(companySettings);return new Result(ResultCode.SUCCESS);
}

查询所有参保人员数据列表

社保设置

获取不同城市的社保缴费项目


findPaymentItemByCityId

展示员工社保数据


findById

设置员工参保数据


/**
* 保存用户社保信息
*/
@ApiOperation(value=" 保 存 用 户 社 保 信 息 ",httpMethod = "PUT") @RequestMapping(value = "/{userId}", method = RequestMethod.PUT)
public Result save(@RequestBody UserSocialSecurity userSocialSecurity) { userSocialService.save(userSocialSecurity);
return new Result(ResultCode.SUCCESS);
}

相关文章:

API网关与社保模块

API网关与社保模块 理解zuul网关的作用完成zuul网关的搭建 实现社保模块的代码开发 zuul网关 在学习完前面的知识后&#xff0c;微服务架构已经初具雏形。但还有一些问题&#xff1a;不同的微服务一般会有不同的网 络地址&#xff0c;客户端在访问这些微服务时必须记住几十甚至…...

linux 安装 docker

linux 安装 docker docker及版本一键安装docker(本人使用的是手动安装)Docker手动安装 docker及版本 Docker从17.03版本之后分为CE&#xff08;Community Edition: 社区版&#xff09;和EE&#xff08;Enterprise Edition: 企业版&#xff09;。相对于社区版本&#xff0c;企业…...

整数转罗马数字

题目&#xff1a; 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 …...

利用爬虫采集音频信息完整代码示例

以下是一个使用WWW::RobotRules和duoip.cn/get_proxy的Perl下载器程序&#xff1a; #!/usr/bin/perluse strict; use warnings; use WWW::RobotRules; use LWP::UserAgent; use HTTP::Request; use HTTP::Response;# 创建一个UserAgent对象 my $ua LWP::UserAgent->new();#…...

WebSocket: 实时通信的新维度

介绍&#xff1a; 在现代Web应用程序中&#xff0c;实时通信对于提供即时更新和交互性至关重要。传统的HTTP协议虽然适合请求-响应模式&#xff0c;但对于需要频繁数据交换的场景并不理想。而WebSocket技术的出现填补了这个空白&#xff0c;为Web开发者们带来了一种高效、实时的…...

postgresql(openGauss)模糊匹配参数

被pg系这个show要求精准匹配参数恶心的不轻。 原理是用.psqlrc&#xff08;openGauss用.gsqlrc&#xff09;文件set一个select常量进去&#xff0c;需要用&#xff1a;调用这个常量。理论上也可以增强其他的各种功能。 我在openGauss做的一个例子 .gsqlrc&#xff08;.psqlrc…...

jdk 加密 aes jar包解决

JDK1.8.0_151的无限制强度加密策略文件变动 JDK1.8.0_151无需去官网下载 local_policy.jar US_export_policy.jar这个jar包&#xff0c;只需要修改Java\jdk1.8.0_151\jre\lib\security这目录下的java.security文件配置即可。 随着越来越多的第三方工具只支持 JDK8&#xff0c…...

C++ Primer 第十一章 关联容器 重点解读

1 map自定义排序 #include <map> #include <iostream> #include <functional> using namespace std; int main() {function<bool(pair<int, int>, pair<int, int>)> cmp [&](pair<int, int> p1, pair<int, int> p2) -&g…...

MySQL 8 - 能够成功创建其他用户但无法修改 root 用户的密码

问题&#xff1a; 创建其他用户就可以&#xff0c;为什么修改root 密码不可以&#xff1f; 如果能够成功创建其他用户但无法修改 root 用户的密码&#xff0c;这可能是因为 MySQL 8 及更高版本引入了一个名为"caching_sha2_password"的身份验证插件作为默认设置&…...

k8s kubernetes 1.23.6 + flannel公网环境安装

准备环境&#xff0c;必须是同一个云服务厂商&#xff0c;如&#xff1a;华为&#xff0c;阿里、腾讯等&#xff0c;不要存在跨平台安装K8S&#xff0c;跨平台安装需要处理网络隧道才能实现所有节点在一个网络集群中&#xff0c;这里推荐使用同一家云服务厂商安装即可 这里使用…...

博客系统中的加盐算法

目录 一、为什么要对密码进行加盐加密&#xff1f; 1、明文 2、传统的 MD5 二、加盐加密 1、加盐算法实现思路 2、加盐算法解密思路 3、加盐算法代码实现 三、使用 Spring Security 加盐 1、引入 Spring Security 框架 2、排除 Spring Security 的自动加载 3、调用 S…...

同花顺动态Cookie反爬JS逆向分析

文章目录 1. 写在前面2. 请求分析3. Hook Cookie4. 补环境 1. 写在前面 最近有位朋友在大A失意&#xff0c;突发奇想自己闲来无事想要做一个小工具&#xff0c;监测一下市场行情的数据。自己再分析分析&#xff0c;虽是一名程序员但苦于对爬虫领域相关的技术不是特别熟悉。最后…...

异步加载JS的方法

异步加载 JavaScript (JS) 文件是提高网页性能的一种常用技术&#xff0c;这样可以使页面在等待 JS 文件加载和执行时不会阻塞。以下是一些异步加载 JS 的方法&#xff1a; 使用 <script> 标签的 async 属性 通过将 <script> 标签的 async 属性设为 true&#xf…...

IO/NIO交互模拟及渐进式实现

IO IO Server public class SocketServer {public static void main(String[] args) {//server编号和client编号对应&#xff0c;优缺点注释在server端//server1();//server2();server3();}/*** server1的缺点&#xff1a;* 1、accept()方法阻塞了线程&#xff0c;要等客户端…...

springboot+html实现密码重置功能

目录 登录注册&#xff1a; 前端&#xff1a; chnangePssword.html 后端&#xff1a; controller: Mapper层&#xff1a; 逻辑&#xff1a; 登录注册&#xff1a; https://blog.csdn.net/m0_67930426/article/details/133849132 前端&#xff1a; 通过点击忘记密码跳转…...

LeetCode 2525. 根据规则将箱子分类【模拟】1301

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

atcoder [Road of the King] 题解(DP好题)

题面 简要题意&#xff1a;有一个 n n n 个点的图&#xff0c;目前一条边都没有。有一个人在 1 1 1 号点要进行 m m m 次移动&#xff0c; 终点不必是 1 1 1 号点。加入第 i i i 次的从 u u u 移动到了 v v v&#xff0c; 那么 u u u 到 v v v 之间出现一条有向边。问…...

CImageList 图像列表

一、CImageList类Create函数参数解析 BOOL Create(int cx,int cy,UINT nFlags,int nInitial,int nGrow ); 1.1&#xff09; cx,cy&#xff1a;图片的实际像素宽与高&#xff1b; nFlags&#xff1a;创建图像列表的类型,包括4/8/16/24/32/位色&#xff1b; nFlags确定建立图…...

【OpenGL】四、坐标系统和摄像机

坐标转换 文章目录 坐标转换坐标系统的转换局部空间(Local Space&#xff09;->世界空间(World Space)世界空间(World Space)->观察空间&#xff08;View Space/View Space&#xff09;裁剪空间(Clip Space)MVP矩阵 坐标系统的转换 了解坐标系统和空间变换之前需要先了解…...

使用vcpkg管理依赖第三库

文章目录 使用vcpkg管理依赖第三库vcpkg安装vcpkg经典模式使用从仓库列表搜索依赖项从某个基线版本的列表中查询某个依赖项信息安装依赖库 vcpkg清单模式的使用vcpkg清单模式的使用例子说明 使用vcpkg管理依赖第三库 vcpkg 有两种操作模式&#xff1a;经典模式和清单模式。 在…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...