作者 朱兆平

brench-update:

0. 基于forWechatServer的子开发分支,属于NMMS-MANAGE新舱单管理的子分支
1. 转关运抵列表接口增加数据权限过滤.

Signed-off-by: mrz <17966059@qq.com>
  1 +# 转关运抵申报管理分支
  2 +- 将与仓单管理辅助分支分离
  3 +- 数据库使用国产数据库kingbaseES
@@ -37,23 +37,28 @@ spring: @@ -37,23 +37,28 @@ spring:
37 #eureka主机名,会在控制页面中显示 37 #eureka主机名,会在控制页面中显示
38 #DEV环境关闭注册。 38 #DEV环境关闭注册。
39 features: 39 features:
40 - enabled: false 40 + enabled: true
41 discovery: 41 discovery:
42 - enabled: false 42 + enabled: true
43 service-registry: 43 service-registry:
44 auto-registration: 44 auto-registration:
45 - enabled: false 45 + enabled: true
46 46
47 datasource: 47 datasource:
48 type: com.alibaba.druid.pool.DruidDataSource 48 type: com.alibaba.druid.pool.DruidDataSource
  49 + # kingbase
  50 + driver-class-name: com.kingbase8.Driver
  51 + url: jdbc:kingbase8://192.168.1.74:54321/CGONMS
  52 + username: cgonms
  53 + password: vmvnv1v2
49 #oracle 54 #oracle
50 - driver-class-name: oracle.jdbc.OracleDriver 55 +# driver-class-name: oracle.jdbc.OracleDriver
51 # url: jdbc:oracle:thin:@192.168.1.199:10069:CGODB 56 # url: jdbc:oracle:thin:@192.168.1.199:10069:CGODB
52 # username: CGONMS 57 # username: CGONMS
53 # password: 1q2w3e4r 58 # password: 1q2w3e4r
54 - url: jdbc:oracle:thin:@118.31.66.166:17005:ORCLL  
55 - username: CGONMS  
56 - password: vmvnv1v2 59 +# url: jdbc:oracle:thin:@192.168.1.253:1522:ORCLL
  60 +# username: CGONMS
  61 +# password: vmvnv1v2
57 #spring datasource mysql,注意编码配置,缺少数据库编码配置容易引起中文入库乱码 62 #spring datasource mysql,注意编码配置,缺少数据库编码配置容易引起中文入库乱码
58 # url: jdbc:mysql://127.0.0.1:3307/statistics?useUnicode=true&characterEncoding=utf8 63 # url: jdbc:mysql://127.0.0.1:3307/statistics?useUnicode=true&characterEncoding=utf8
59 # username: root 64 # username: root
@@ -108,7 +113,8 @@ mybatis: @@ -108,7 +113,8 @@ mybatis:
108 pagehelper: 113 pagehelper:
109 #auto-dialect: true 114 #auto-dialect: true
110 #auto-runtime-dialect: true 115 #auto-runtime-dialect: true
111 - helper-dialect: oracle 116 +# helper-dialect: oracle
  117 + helper-dialect: postgresql
112 reasonable: true 118 reasonable: true
113 support-methods-arguments: true 119 support-methods-arguments: true
114 params: count=countSql 120 params: count=countSql
@@ -194,8 +200,15 @@ mq: @@ -194,8 +200,15 @@ mq:
194 username: admin 200 username: admin
195 password: admin 201 password: admin
196 feign: 202 feign:
  203 + client:
  204 + config:
  205 + default:
  206 + connectTimeout: 600000
  207 + readTimeout: 15000
  208 + httpclient:
  209 + connection-timeout: 15000
197 hystrix: 210 hystrix:
198 - enabled: true 211 + enabled: false
199 inport-url: http://nmms1.15miaoo.com:17999 212 inport-url: http://nmms1.15miaoo.com:17999
200 info: 213 info:
201 version: 1.0 214 version: 1.0
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 </parent> 12 </parent>
13 <groupId>com.tianbo</groupId> 13 <groupId>com.tianbo</groupId>
14 <artifactId>nmms-manage</artifactId> 14 <artifactId>nmms-manage</artifactId>
15 - <version>1.2-SNAPSHOT</version> 15 + <version>1.3-kingbase-SNAPSHOT</version>
16 <name>nmms-manage</name> 16 <name>nmms-manage</name>
17 <description>nmms management system</description> 17 <description>nmms management system</description>
18 <properties> 18 <properties>
@@ -142,10 +142,19 @@ @@ -142,10 +142,19 @@
142 <!--</dependency>--> 142 <!--</dependency>-->
143 <!-- oracle--> 143 <!-- oracle-->
144 <!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8 --> 144 <!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8 -->
  145 +<!-- <dependency>-->
  146 +<!-- <groupId>com.oracle.database.jdbc</groupId>-->
  147 +<!-- <artifactId>ojdbc6</artifactId>-->
  148 +<!-- <version>11.2.0.4</version>-->
  149 +<!-- </dependency>-->
  150 +
  151 +
145 <dependency> 152 <dependency>
146 - <groupId>com.oracle.database.jdbc</groupId>  
147 - <artifactId>ojdbc6</artifactId>  
148 - <version>11.2.0.4</version> 153 + <groupId>cn.com.kingbase</groupId>
  154 + <artifactId>kingbase8</artifactId>
  155 + <version>8.6.0</version>
  156 + <scope>system</scope>
  157 + <systemPath>${project.basedir}/lib/kingbase8-8.6.0.jar</systemPath>
149 </dependency> 158 </dependency>
150 <!-- https://mvnrepository.com/artifact/com.oracle.ojdbc/orai18n --> 159 <!-- https://mvnrepository.com/artifact/com.oracle.ojdbc/orai18n -->
151 <!-- <dependency>--> 160 <!-- <dependency>-->
1 -# 通用IMF接收客户端框架  
2 -  
3 -* 集成IMFjar包  
4 -* 集成Spring boot 及 srping cloud  
5 -* 集成websocket  
6 - * 可以在线查看imf客户端运行情况 web访问路径/log/imf,可查看项目logs目录下的imf.log  
  1 +# 转关运抵管理服务
@@ -4,6 +4,8 @@ @@ -4,6 +4,8 @@
4 */ 4 */
5 package com.tianbo.analysis; 5 package com.tianbo.analysis;
6 6
  7 +import org.apache.ibatis.plugin.Interceptor;
  8 +import org.apache.ibatis.session.SqlSessionFactory;
7 import org.mybatis.spring.annotation.MapperScan; 9 import org.mybatis.spring.annotation.MapperScan;
8 import org.springframework.boot.SpringApplication; 10 import org.springframework.boot.SpringApplication;
9 import org.springframework.boot.autoconfigure.SpringBootApplication; 11 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -11,8 +13,8 @@ import org.springframework.boot.web.client.RestTemplateBuilder; @@ -11,8 +13,8 @@ import org.springframework.boot.web.client.RestTemplateBuilder;
11 import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 13 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
12 import org.springframework.cloud.client.loadbalancer.LoadBalanced; 14 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
13 import org.springframework.cloud.openfeign.EnableFeignClients; 15 import org.springframework.cloud.openfeign.EnableFeignClients;
  16 +import org.springframework.context.ConfigurableApplicationContext;
14 import org.springframework.context.annotation.Bean; 17 import org.springframework.context.annotation.Bean;
15 -import org.springframework.context.annotation.ComponentScan;  
16 import org.springframework.transaction.annotation.EnableTransactionManagement; 18 import org.springframework.transaction.annotation.EnableTransactionManagement;
17 import org.springframework.web.client.RestTemplate; 19 import org.springframework.web.client.RestTemplate;
18 20
@@ -25,7 +27,10 @@ import org.springframework.web.client.RestTemplate; @@ -25,7 +27,10 @@ import org.springframework.web.client.RestTemplate;
25 public class NmmsAdminApplication { 27 public class NmmsAdminApplication {
26 28
27 public static void main(String[] args) { 29 public static void main(String[] args) {
28 - SpringApplication.run(NmmsAdminApplication.class, args); 30 + ConfigurableApplicationContext run = SpringApplication.run(NmmsAdminApplication.class, args);
  31 + Interceptor permissionInterceptor = (Interceptor) run.getBean("dataPermissionInterceptor");
  32 + //这种方式添加mybatis拦截器保证在pageHelper前执行
  33 + run.getBean(SqlSessionFactory.class).getConfiguration().addInterceptor(permissionInterceptor);
29 } 34 }
30 35
31 @Bean 36 @Bean
  1 +package com.tianbo.analysis.annotation;
  2 +
  3 +import java.lang.annotation.*;
  4 +
  5 +@Retention(RetentionPolicy.RUNTIME)
  6 +@Target(ElementType.METHOD)
  7 +@Documented
  8 +// 指名数据库查询方法需要和权限挂钩
  9 +public @interface DataPermission {
  10 +}
  11 +
1 package com.tianbo.analysis.controller; 1 package com.tianbo.analysis.controller;
2 2
3 import com.github.pagehelper.PageInfo; 3 import com.github.pagehelper.PageInfo;
4 -import com.tianbo.analysis.model.MANIFEST_AIR_CHANGE;  
5 import com.tianbo.analysis.model.ResultJson; 4 import com.tianbo.analysis.model.ResultJson;
6 import com.tianbo.analysis.model.TRANSTOARRIVEEXPORT; 5 import com.tianbo.analysis.model.TRANSTOARRIVEEXPORT;
7 import com.tianbo.analysis.service.TransArriveExportService; 6 import com.tianbo.analysis.service.TransArriveExportService;
8 -import com.tianbo.analysis.tools.TransArriveTools; 7 +
9 import com.tianbo.util.Date.DateUtil; 8 import com.tianbo.util.Date.DateUtil;
10 import io.swagger.annotations.Api; 9 import io.swagger.annotations.Api;
11 import io.swagger.annotations.ApiOperation; 10 import io.swagger.annotations.ApiOperation;
12 import org.apache.commons.lang.StringUtils; 11 import org.apache.commons.lang.StringUtils;
13 import org.springframework.beans.factory.annotation.Autowired; 12 import org.springframework.beans.factory.annotation.Autowired;
14 import org.springframework.web.bind.annotation.*; 13 import org.springframework.web.bind.annotation.*;
15 - 14 +import javax.servlet.http.HttpServletRequest;
16 import java.util.Date; 15 import java.util.Date;
17 import java.util.List; 16 import java.util.List;
18 -import java.util.UUID; 17 +
19 18
20 @Api(description = "转关运抵申报") 19 @Api(description = "转关运抵申报")
21 @RestController 20 @RestController
22 @RequestMapping("/trans/") 21 @RequestMapping("/trans/")
23 public class TransArriveExportController { 22 public class TransArriveExportController {
  23 +
24 @Autowired 24 @Autowired
25 TransArriveExportService transArriveExportService; 25 TransArriveExportService transArriveExportService;
  26 +
26 @ApiOperation(value = "新增转关运抵申报") 27 @ApiOperation(value = "新增转关运抵申报")
27 @PostMapping("/addTrans") 28 @PostMapping("/addTrans")
28 public ResultJson addTrans(@RequestBody TRANSTOARRIVEEXPORT transtoarriveexport){ 29 public ResultJson addTrans(@RequestBody TRANSTOARRIVEEXPORT transtoarriveexport){
@@ -57,10 +58,14 @@ public class TransArriveExportController { @@ -57,10 +58,14 @@ public class TransArriveExportController {
57 @RequestParam(value = "username", required = false) String username, 58 @RequestParam(value = "username", required = false) String username,
58 @RequestParam(value = "trnmode", required = false) String trnmode, 59 @RequestParam(value = "trnmode", required = false) String trnmode,
59 @RequestParam(value = "unloadcode", required = false) String unloadcode, 60 @RequestParam(value = "unloadcode", required = false) String unloadcode,
  61 + @RequestParam(value = "billno", required = false) String billno,
60 @RequestParam(value = "startDate", required = false) String startDate, 62 @RequestParam(value = "startDate", required = false) String startDate,
61 @RequestParam(value = "endDate", required = false) String endDate, 63 @RequestParam(value = "endDate", required = false) String endDate,
62 @RequestParam(value = "pageNum",required = false,defaultValue = "1") int pageNum, 64 @RequestParam(value = "pageNum",required = false,defaultValue = "1") int pageNum,
63 - @RequestParam(value = "pageSize",required = false,defaultValue = "100") int pageSize){ 65 + @RequestParam(value = "pageSize",required = false,defaultValue = "10") int pageSize){
  66 +
  67 +
  68 +
64 TRANSTOARRIVEEXPORT trans=new TRANSTOARRIVEEXPORT(); 69 TRANSTOARRIVEEXPORT trans=new TRANSTOARRIVEEXPORT();
65 if(StringUtils.isNotEmpty(endDate) && StringUtils.isNotEmpty(startDate)){ 70 if(StringUtils.isNotEmpty(endDate) && StringUtils.isNotEmpty(startDate)){
66 Date start = DateUtil.parseDate(startDate,"yyyy-MM-dd"); 71 Date start = DateUtil.parseDate(startDate,"yyyy-MM-dd");
@@ -70,9 +75,13 @@ public class TransArriveExportController { @@ -70,9 +75,13 @@ public class TransArriveExportController {
70 } 75 }
71 trans.setCustomscode(customscode); 76 trans.setCustomscode(customscode);
72 trans.setUsername(username); 77 trans.setUsername(username);
  78 + trans.setBillno(billno);
73 trans.setTrnmode(trnmode); 79 trans.setTrnmode(trnmode);
74 trans.setUnloadcode(unloadcode); 80 trans.setUnloadcode(unloadcode);
75 PageInfo<TRANSTOARRIVEEXPORT> pageInfo = transArriveExportService.selectTrans(trans,pageNum,pageSize); 81 PageInfo<TRANSTOARRIVEEXPORT> pageInfo = transArriveExportService.selectTrans(trans,pageNum,pageSize);
  82 +
  83 + List<TRANSTOARRIVEEXPORT> list = pageInfo.getList();
  84 +
76 return new ResultJson("200","success",pageInfo); 85 return new ResultJson("200","success",pageInfo);
77 } 86 }
78 @ApiOperation(value = "转关运抵申报") 87 @ApiOperation(value = "转关运抵申报")
1 package com.tianbo.analysis.dao; 1 package com.tianbo.analysis.dao;
2 2
  3 +import com.tianbo.analysis.annotation.DataPermission;
3 import com.tianbo.analysis.model.MANIFEST_AIR_CHANGE; 4 import com.tianbo.analysis.model.MANIFEST_AIR_CHANGE;
4 import com.tianbo.analysis.model.TRANSTOARRIVEEXPORT; 5 import com.tianbo.analysis.model.TRANSTOARRIVEEXPORT;
5 6
@@ -20,6 +21,7 @@ public interface TRANSTOARRIVEEXPORTMapper { @@ -20,6 +21,7 @@ public interface TRANSTOARRIVEEXPORTMapper {
20 //更新发送状态 21 //更新发送状态
21 int updateStatusByPrimaryKey(TRANSTOARRIVEEXPORT record); 22 int updateStatusByPrimaryKey(TRANSTOARRIVEEXPORT record);
22 23
  24 + @DataPermission
23 List<TRANSTOARRIVEEXPORT> selectTrans(TRANSTOARRIVEEXPORT record); 25 List<TRANSTOARRIVEEXPORT> selectTrans(TRANSTOARRIVEEXPORT record);
24 26
25 List<TRANSTOARRIVEEXPORT> selectListByAutoIDS(List<String> idList); 27 List<TRANSTOARRIVEEXPORT> selectListByAutoIDS(List<String> idList);
  1 +package com.tianbo.analysis.feign;
  2 +
  3 +import com.tianbo.analysis.feign.fallback.UserCenterFallbackFactory;
  4 +import com.tianbo.analysis.feign.interceptor.TokenInterceptor;
  5 +import com.tianbo.analysis.model.ResultJson;
  6 +import org.springframework.cloud.openfeign.FeignClient;
  7 +import org.springframework.stereotype.Component;
  8 +import org.springframework.web.bind.annotation.GetMapping;
  9 +import org.springframework.web.bind.annotation.RequestHeader;
  10 +import org.springframework.web.bind.annotation.RequestParam;
  11 +import org.springframework.web.bind.annotation.ResponseBody;
  12 +
  13 +@Component
  14 +//CLOUD-USER-CENTER
  15 +@FeignClient(name = "CLOUD-USER-CENTER",
  16 + fallbackFactory = UserCenterFallbackFactory.class,
  17 + configuration = TokenInterceptor.class
  18 +)
  19 +public interface UserCenterAPI {
  20 +
  21 + @ResponseBody
  22 + @GetMapping("/perm/getUserPermByToken")
  23 + ResultJson getDataPerm(@RequestParam("path") String path, @RequestHeader("Authorization") String token);
  24 +
  25 +}
  1 +package com.tianbo.analysis.feign.fallback;
  2 +
  3 +import com.tianbo.analysis.feign.UserCenterAPI;
  4 +import com.tianbo.analysis.model.ResultJson;
  5 +import feign.hystrix.FallbackFactory;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +@Slf4j
  10 +@Component
  11 +public class UserCenterFallbackFactory implements FallbackFactory<UserCenterAPI> {
  12 + @Override
  13 + public UserCenterAPI create(Throwable throwable) {
  14 + log.error("调用用户中心数据权限接口异常",throwable);
  15 + return new UserCenterAPI() {
  16 + @Override
  17 + public ResultJson getDataPerm(String path,String token) {
  18 + return new ResultJson("400","用户中心数据权限接口访问失败");
  19 + }
  20 + };
  21 + }
  22 +}
  1 +package com.tianbo.analysis.feign.interceptor;
  2 +
  3 +import feign.RequestInterceptor;
  4 +import feign.RequestTemplate;
  5 +import org.springframework.context.annotation.Bean;
  6 +import org.springframework.context.annotation.Configuration;
  7 +
  8 +import java.util.Collection;
  9 +
  10 +@Configuration
  11 +public class TokenInterceptor {
  12 +
  13 + @Bean
  14 + public RequestInterceptor requestInterceptor() {
  15 + return new RequestInterceptor() {
  16 + @Override
  17 + public void apply(RequestTemplate requestTemplate) {
  18 + Collection<String> requestVariables = requestTemplate.getRequestVariables();
  19 + for (String requestVariable : requestVariables) {
  20 + System.out.println("requestVariable = " + requestVariable);
  21 + }
  22 + System.out.println("我调用了远程feign接口 token信息注入");
  23 + }
  24 + };
  25 + }
  26 +}
  1 +package com.tianbo.analysis.intercept;
  2 +
  3 +import com.alibaba.fastjson.JSONArray;
  4 +import com.alibaba.fastjson.JSONObject;
  5 +import com.tianbo.analysis.thread.SessionUserContext;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +import net.sf.jsqlparser.expression.Expression;
  8 +import net.sf.jsqlparser.parser.CCJSqlParserUtil;
  9 +import net.sf.jsqlparser.schema.Table;
  10 +import net.sf.jsqlparser.statement.Statement;
  11 +import net.sf.jsqlparser.statement.select.Join;
  12 +import net.sf.jsqlparser.statement.select.PlainSelect;
  13 +import net.sf.jsqlparser.statement.select.Select;
  14 +import net.sf.jsqlparser.statement.select.SelectItem;
  15 +import org.apache.ibatis.cache.CacheKey;
  16 +import org.apache.ibatis.executor.Executor;
  17 +import org.apache.ibatis.mapping.BoundSql;
  18 +import org.apache.ibatis.mapping.MappedStatement;
  19 +import org.apache.ibatis.plugin.Interceptor;
  20 +import org.apache.ibatis.plugin.Intercepts;
  21 +import org.apache.ibatis.plugin.Invocation;
  22 +import org.apache.ibatis.plugin.Signature;
  23 +import org.apache.ibatis.session.ResultHandler;
  24 +import org.apache.ibatis.session.RowBounds;
  25 +import org.springframework.stereotype.Component;
  26 +
  27 +import java.text.SimpleDateFormat;
  28 +import java.util.Date;
  29 +import java.util.List;
  30 +
  31 +@Intercepts({
  32 + @Signature(type= Executor.class,
  33 + method = "query",
  34 + args = {MappedStatement.class,Object.class, RowBounds.class, ResultHandler.class}),
  35 + @Signature(type= Executor.class,
  36 + method = "query",
  37 + args = {MappedStatement.class,
  38 + Object.class,
  39 + RowBounds.class,
  40 + ResultHandler.class,
  41 + CacheKey.class,
  42 + BoundSql.class
  43 + })
  44 + })
  45 +@Component
  46 +@Slf4j
  47 +public class DataPermissionInterceptor implements Interceptor {
  48 +
  49 + @Override
  50 + public Object intercept(Invocation invocation) throws Throwable {
  51 + //从invocation搞到sql
  52 + String processSql = ExecutorPluginUtils.getSqlByInvocation(invocation);
  53 + //复制原sql,用于产生新sql
  54 + String sql2Reset = processSql;
  55 + Statement statement = CCJSqlParserUtil.parse(processSql);
  56 + //获取mybatis绑定SQL配置信息也就是XML中的具体执行相关
  57 + MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
  58 +
  59 + /** 得到spring上下文,
  60 + 如果后端未用分页,则这步可以省略
  61 + 在项目启动类下完成该配置
  62 + ConfigurableApplicationContext run = SpringApplication.run(Application.class, args);
  63 + Interceptor permissionInterceptor = (Interceptor) run.getBean("dataPermissionInterceptor");
  64 + 这种方式添加mybatis拦截器保证在pageHelper前执行
  65 + run.getBean(SqlSessionFactory.class).getConfiguration().addInterceptor(permissionInterceptor);
  66 + **/
  67 +
  68 + if (ExecutorPluginUtils.isAreaTag(mappedStatement)) {
  69 + /**
  70 + * 用户数据权限范围判定,即行数据权限判定
  71 + * 根据判定结果进行dataScope的值set
  72 + */
  73 + // 存储用户行权限的LIST
  74 + /**
  75 + *
  76 + * 判定
  77 + * 场景一: 用户未配置数据权限,rowPermList 为空
  78 + * 场景二: 用户配置了数据权限,rowPermList 有值,包含 对应数据字段列 条件信息
  79 + * 场景三: 用户配置了数据权限,rowPermList 没值, 权限判定具有关键字标识的 如: * / ALL等
  80 + * todo: 条件值怎么获取?
  81 + */
  82 + String dataScope = "els";
  83 + JSONArray rowPermList = SessionUserContext.getSessionUser();
  84 + //取出来后 清理
  85 + SessionUserContext.clearSessionUser();
  86 + if (rowPermList!=null && !rowPermList.isEmpty()) {
  87 + // 用户配置了数据权限
  88 + //获取该用户所具有的角色的数据权限dataScope
  89 + dataScope = "usr";
  90 + }else {
  91 + //用户未配置数据权限
  92 + dataScope = "*";
  93 + }
  94 +
  95 + String deptsUser= "admin";
  96 + //因数据敏感省略
  97 + //获取该用户的所在公司或部门下的所有人 in 条件 包含()封装
  98 + //例如 StringBuffer orgBuffer = new StringBuffer();
  99 + // orgBuffer.append("(");
  100 + //String collect = allUserByOrgs.stream().map(String::valueOf).collect(Collectors.joining(","));
  101 + //orgBuffer.append(collect).append(")");
  102 + //String orgsUser = orgBuffer.toString();
  103 + String orgsUser = "45,46,47";
  104 + try {
  105 + if (statement instanceof Select) {
  106 + Select selectStatement = (Select) statement;
  107 + //其中的PlainSelect 可以拿到sql语句的全部节点信息,具体各位可以看源码
  108 + PlainSelect plain = (PlainSelect) selectStatement.getSelectBody();
  109 + //获取所有外连接
  110 + List<Join> joins = plain.getJoins();
  111 + //获取到原始sql语句
  112 + String sql = processSql;
  113 + StringBuffer whereSql = new StringBuffer();
  114 + switch (dataScope) {
  115 + /**
  116 + * 这里dataScope 范围 *: 所有数据权限 ,usr: 本人 ,dep(department):部门及分部门(递归) ,com(company):公司及分公司(递归)
  117 + * els : 未配置
  118 + * 所有数据权限作用在人上,因此sql用 in
  119 + */
  120 + case "*":
  121 + whereSql.append("1=1");
  122 + break;
  123 + case "usr":
  124 + if(joins==null || joins.isEmpty()){
  125 + String and = " and ";
  126 + for (int i = 0; i < rowPermList.size(); i++) {
  127 + JSONObject o = (JSONObject)rowPermList.get(i);
  128 + if (i==0){
  129 + whereSql
  130 + //条件字段
  131 + .append(o.get("colName"))
  132 + .append(" = ")
  133 + // 条件值
  134 + .append(getSqlValue(o.get("colValue")));
  135 + }else {
  136 + whereSql.append(and)
  137 + //条件字段
  138 + .append(o.get("colName"))
  139 + .append(" = ")
  140 + // 条件值
  141 + .append(getSqlValue(o.get("colValue")));
  142 + }
  143 +
  144 + }
  145 + }else{
  146 + for (Join join : joins) {
  147 + Table rightItem = (Table) join.getRightItem();
  148 + //匹配表名
  149 + if(rightItem.getName().equals("sec_user")){
  150 + //获取别名
  151 + if(rightItem.getAlias()!=null){
  152 + //适配用户ID 样例
  153 + whereSql.append(rightItem.getAlias().getName()).append(".USERNAME = ").append(45);
  154 + }else {
  155 + whereSql.append("id = ").append(deptsUser);
  156 + }
  157 +
  158 + }
  159 + }
  160 + }
  161 + break;
  162 + case "dep":
  163 + for (Join join : joins) {
  164 + Table rightItem = (Table) join.getRightItem();
  165 + if(rightItem.getName().equals("sec_user")){
  166 + if(rightItem.getAlias()!=null){
  167 + whereSql.append(rightItem.getAlias().getName()).append(".id in ").append(deptsUser);
  168 + }else {
  169 + whereSql.append("id in ").append(deptsUser);
  170 + }
  171 +
  172 + }
  173 + }
  174 + break;
  175 + case "com":
  176 + for (Join join : joins) {
  177 + Table rightItem = (Table) join.getRightItem();
  178 + if(rightItem.getName().equals("sec_user")){
  179 + if(rightItem.getAlias()!=null){
  180 + whereSql.append(rightItem.getAlias().getName()).append(".id in ").append(orgsUser);
  181 + }else {
  182 + whereSql.append("id in ").append(deptsUser);
  183 + }
  184 +
  185 + }
  186 + }
  187 + break;
  188 + default:
  189 + whereSql.append("1=2");
  190 + break;
  191 + }
  192 +
  193 + /**
  194 + * 获取where节点
  195 + * 行访问权限相关
  196 + * 重新拼接where 语句 需要注意不要破坏where 查询条件的顺序,为了配合索引提高查询效率
  197 + */
  198 + Expression where = plain.getWhere();
  199 + if (where == null) {
  200 + if (whereSql.length() > 0) {
  201 + Expression expression = CCJSqlParserUtil
  202 + .parseCondExpression(whereSql.toString());
  203 + Expression whereExpression = (Expression) expression;
  204 + plain.setWhere(whereExpression);
  205 + }
  206 + } else {
  207 + if (whereSql.length() > 0) {
  208 + //where条件之前存在,需要重新进行拼接
  209 + whereSql.append(" and ( " + where.toString() + " )");
  210 + } else {
  211 + //新增片段不存在,使用之前的sql
  212 + whereSql.append(where.toString());
  213 + }
  214 + Expression expression = CCJSqlParserUtil
  215 + .parseCondExpression(whereSql.toString());
  216 + plain.setWhere(expression);
  217 + }
  218 + sql2Reset = selectStatement.toString();
  219 + }
  220 +
  221 + } catch (Exception e) {
  222 + log.error("[SQl-Interceptor-ERR]-",e);
  223 + e.printStackTrace();
  224 + }
  225 + }
  226 + // 替换sql
  227 + ExecutorPluginUtils.resetSql2Invocation(invocation, sql2Reset);
  228 + //放行
  229 + Object proceed = invocation.proceed();
  230 + return proceed;
  231 + }
  232 +
  233 + private String getSqlValue(Object value) {
  234 + if (value instanceof String) {
  235 + return "'" + value + "'";
  236 + }else if (value instanceof Date) {
  237 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
  238 + return "'" + sdf.format((Date) value) + "'";
  239 + } else {
  240 + return value.toString();
  241 + }
  242 + }
  243 +}
  1 +package com.tianbo.analysis.intercept;
  2 +
  3 +import com.tianbo.analysis.annotation.DataPermission;
  4 +import org.apache.ibatis.mapping.BoundSql;
  5 +import org.apache.ibatis.mapping.MappedStatement;
  6 +import org.apache.ibatis.mapping.SqlCommandType;
  7 +import org.apache.ibatis.mapping.SqlSource;
  8 +import org.apache.ibatis.plugin.Invocation;
  9 +import org.apache.ibatis.reflection.DefaultReflectorFactory;
  10 +import org.apache.ibatis.reflection.MetaObject;
  11 +import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
  12 +import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
  13 +
  14 +import java.lang.reflect.Method;
  15 +import java.lang.reflect.Type;
  16 +import java.sql.SQLException;
  17 +import java.util.Arrays;
  18 +import java.util.Objects;
  19 +
  20 +public class ExecutorPluginUtils {
  21 +
  22 + /**
  23 + * 获取sql语句
  24 + * @param invocation
  25 + * @return
  26 + */
  27 + public static String getSqlByInvocation(Invocation invocation) {
  28 + final Object[] args = invocation.getArgs();
  29 + MappedStatement ms = (MappedStatement) args[0];
  30 + Object parameterObject = args[1];
  31 + BoundSql boundSql = ms.getBoundSql(parameterObject);
  32 + return boundSql.getSql();
  33 + }
  34 +
  35 + /**
  36 + * 包装sql后,重置到invocation中
  37 + * @param invocation
  38 + * @param sql
  39 + * @throws SQLException
  40 + */
  41 + public static void resetSql2Invocation(Invocation invocation, String sql) throws SQLException {
  42 + final Object[] args = invocation.getArgs();
  43 + MappedStatement statement = (MappedStatement) args[0];
  44 + Object parameterObject = args[1];
  45 + BoundSql boundSql = statement.getBoundSql(parameterObject);
  46 + MappedStatement newStatement = newMappedStatement(statement, new BoundSqlSqlSource(boundSql));
  47 + MetaObject msObject = MetaObject.forObject(newStatement, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(),new DefaultReflectorFactory());
  48 + msObject.setValue("sqlSource.boundSql.sql", sql);
  49 + args[0] = newStatement;
  50 + }
  51 +
  52 +
  53 + private static MappedStatement newMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
  54 + MappedStatement.Builder builder =
  55 + new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
  56 + builder.resource(ms.getResource());
  57 + builder.fetchSize(ms.getFetchSize());
  58 + builder.statementType(ms.getStatementType());
  59 + builder.keyGenerator(ms.getKeyGenerator());
  60 + if (ms.getKeyProperties() != null && ms.getKeyProperties().length != 0) {
  61 + StringBuilder keyProperties = new StringBuilder();
  62 + for (String keyProperty : ms.getKeyProperties()) {
  63 + keyProperties.append(keyProperty).append(",");
  64 + }
  65 + keyProperties.delete(keyProperties.length() - 1, keyProperties.length());
  66 + builder.keyProperty(keyProperties.toString());
  67 + }
  68 + builder.timeout(ms.getTimeout());
  69 + builder.parameterMap(ms.getParameterMap());
  70 + builder.resultMaps(ms.getResultMaps());
  71 + builder.resultSetType(ms.getResultSetType());
  72 + builder.cache(ms.getCache());
  73 + builder.flushCacheRequired(ms.isFlushCacheRequired());
  74 + builder.useCache(ms.isUseCache());
  75 +
  76 + return builder.build();
  77 + }
  78 +
  79 + /**
  80 + * 是否标记为区域字段
  81 + * @return
  82 + */
  83 + public static boolean isAreaTag( MappedStatement mappedStatement) throws ClassNotFoundException {
  84 + String id = mappedStatement.getId();
  85 + //获取类名
  86 + String className = id.substring(0, id.lastIndexOf("."));
  87 + Class clazz = Class.forName(className);
  88 + //获取方法名
  89 + String methodName = id.substring(id.lastIndexOf(".") + 1);
  90 + //这里是博主工作需求,防止pagehelper那里未生效
  91 + if(methodName.contains("_COUNT")){
  92 + methodName=methodName.replace("_COUNT","");
  93 + }
  94 + String m=methodName;
  95 + Class<?> classType = Class.forName(id.substring(0,mappedStatement.getId().lastIndexOf(".")));
  96 +
  97 + //获取对应拦截方法名
  98 + String mName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1);
  99 + //这里是博主工作需求,防止pagehelper那里未生效
  100 + if(mName.contains("_COUNT")){
  101 + mName=mName.replace("_COUNT","");
  102 + }
  103 + boolean ignore = false;
  104 + //获取该类(接口)的所有方法,如果你查询的方法就写在该类,就不需要下面的if判断
  105 + Method[] declaredMethods = classType.getDeclaredMethods();
  106 + Method declaredMethod = Arrays.stream(declaredMethods).filter(it -> it.getName().equals(m)).findFirst().orElse(null);
  107 + //该判断是拿到该接口的超类的方法,博主的查询方法就在超类里,因此需要利用下面代码来获取对应方法
  108 + if (declaredMethod == null) {
  109 + Type[] genericInterfaces = clazz.getGenericInterfaces();
  110 + declaredMethod = Arrays.stream(genericInterfaces).map(e ->
  111 + {
  112 + Method[] declaredMethods1 = ((Class) e).getDeclaredMethods();
  113 + return Arrays.stream(declaredMethods1).filter(it -> it.getName().equals(m)).findFirst().orElse(null);
  114 +
  115 + }).filter(Objects::nonNull).findFirst().orElse(null);
  116 + }
  117 + if(declaredMethod!=null){
  118 + //查询方法是否被permission标记注解
  119 + ignore = declaredMethod.isAnnotationPresent(DataPermission.class);
  120 + }
  121 + return ignore;
  122 + }
  123 +
  124 +
  125 + /**
  126 + * 是否标记为区域字段
  127 + * @return
  128 + */
  129 + public static boolean isAreaTagIngore( MappedStatement mappedStatement) throws ClassNotFoundException {
  130 + String id = mappedStatement.getId();
  131 + String className = id.substring(0, id.lastIndexOf("."));
  132 + Class clazz = Class.forName(className);
  133 + String methodName = id.substring(id.lastIndexOf(".") + 1);
  134 + Class<?> classType = Class.forName(id.substring(0,mappedStatement.getId().lastIndexOf(".")));
  135 + //获取对应拦截方法名
  136 + String mName = mappedStatement.getId().substring(mappedStatement.getId().lastIndexOf(".") + 1);
  137 + boolean ignore = false;
  138 + Method[] declaredMethods = classType.getDeclaredMethods();
  139 + Method declaredMethod = Arrays.stream(declaredMethods).filter(it -> it.getName().equals(methodName)).findFirst().orElse(null);
  140 + if (declaredMethod == null) {
  141 + Type[] genericInterfaces = clazz.getGenericInterfaces();
  142 + declaredMethod = Arrays.stream(genericInterfaces).map(e ->
  143 + {
  144 + Method[] declaredMethods1 = ((Class) e).getDeclaredMethods();
  145 + return Arrays.stream(declaredMethods1).filter(it -> it.getName().equals(methodName)).findFirst().orElse(null);
  146 +
  147 + }).filter(Objects::nonNull).findFirst().orElse(null);
  148 + }
  149 + ignore = declaredMethod.isAnnotationPresent(DataPermission.class);
  150 + return ignore;
  151 + }
  152 +
  153 +
  154 + public static String getOperateType(Invocation invocation) {
  155 + final Object[] args = invocation.getArgs();
  156 + MappedStatement ms = (MappedStatement) args[0];
  157 + SqlCommandType commondType = ms.getSqlCommandType();
  158 + if (commondType.compareTo(SqlCommandType.SELECT) == 0) {
  159 + return "select";
  160 + }
  161 + return null;
  162 + }
  163 + // 定义一个内部辅助类,作用是包装sq
  164 + static class BoundSqlSqlSource implements SqlSource {
  165 + private BoundSql boundSql;
  166 + public BoundSqlSqlSource(BoundSql boundSql) {
  167 + this.boundSql = boundSql;
  168 + }
  169 + @Override
  170 + public BoundSql getBoundSql(Object parameterObject) {
  171 + return boundSql;
  172 + }
  173 + }
  174 +}
  1 +package com.tianbo.analysis.intercept;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONArray;
  5 +import com.alibaba.fastjson.JSONObject;
  6 +import com.tianbo.analysis.feign.UserCenterAPI;
  7 +import com.tianbo.analysis.model.ResultJson;
  8 +import com.tianbo.analysis.thread.SessionUserContext;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.beans.factory.annotation.Autowired;
  11 +import org.springframework.core.env.Environment;
  12 +import org.springframework.stereotype.Component;
  13 +import org.springframework.util.AntPathMatcher;
  14 +import org.springframework.web.servlet.HandlerInterceptor;
  15 +
  16 +import javax.annotation.PostConstruct;
  17 +import javax.servlet.http.HttpServletRequest;
  18 +import javax.servlet.http.HttpServletResponse;
  19 +
  20 +
  21 +@Slf4j
  22 +@Component
  23 +public class UserCenterHanlerInterceptor implements HandlerInterceptor {
  24 +
  25 + private static UserCenterHanlerInterceptor _THIS;
  26 +
  27 + @Autowired
  28 + private Environment environment;
  29 +
  30 + @Autowired
  31 + private UserCenterAPI userCenterAPI;
  32 +
  33 +
  34 + @PostConstruct
  35 + public void init(){
  36 + _THIS = this;
  37 + }
  38 +
  39 + @Override
  40 + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  41 + String serviceName = _THIS.environment.getProperty("spring.application.name");
  42 + String permPath = "/" + serviceName + request.getRequestURI();
  43 + log.info("path = {}, serviceName= {}",request.getRequestURI(),serviceName);
  44 + AntPathMatcher pathMatcher = new AntPathMatcher();
  45 + boolean match = pathMatcher.match(permPath, request.getRequestURI());
  46 +
  47 + String authHeader = request.getHeader("Authorization");
  48 + if (authHeader != null && authHeader.startsWith("Bearer ")) {
  49 +
  50 + ResultJson resultJson = _THIS.userCenterAPI.getDataPerm(permPath, authHeader);
  51 + if (resultJson.getData()!=null){
  52 +
  53 + }
  54 + JSONObject user = (JSONObject) JSON.toJSON(resultJson.getData());
  55 + log.info(resultJson.toString());
  56 + }
  57 +
  58 + /**
  59 + * 根据访问接口地址和token信息获取用户权限信息
  60 + * 参数为request 中的接口地址和的 auth 的token信息
  61 + * 样例实体类如下:
  62 + */
  63 +
  64 + String userDataPermJsonDemoStr = "{\n" +
  65 + "\t\"username\":\"nmms\",\n" +
  66 + "\t\"userId\": \"80\",\n" +
  67 + "\t\"userDataPerm\":{\n" +
  68 + "\t\t\"rowCondition\": \"usr\",\n" +
  69 + "\t\t\"rowDataPermConditions\":[\n" +
  70 + "\t\t\t{\n" +
  71 + "\t\t\t\t\"colName\": \"USERNAME\"\n" +
  72 + "\t\t\t},\n" +
  73 + "\t\t\t{\n" +
  74 + "\t\t\t\t\"colName\": \"BILLNO\"\n" +
  75 + "\t\t\t}\n" +
  76 + "\t\t],\n" +
  77 + "\t}\t\n" +
  78 + "}";
  79 + JSONObject userInfo = JSONObject.parseObject(userDataPermJsonDemoStr);
  80 +
  81 +
  82 + JSONObject userDataPerm = userInfo.getJSONObject("userDataPerm");
  83 + String rowCondition = userDataPerm.getString("rowCondition");
  84 + JSONArray rowDataPermConditions = userDataPerm.getJSONArray("rowDataPermConditions");
  85 +
  86 + JSONObject userDataPermModel = new JSONObject();
  87 + userDataPermModel.put("colName","USERNAME");
  88 +
  89 + //获取token中的user的值
  90 + userDataPermModel.put("colValue","nmms");
  91 +// JSONObject userDataPermModel1 = new JSONObject();
  92 +// userDataPermModel1.put("colName","BILLNO");
  93 +// userDataPermModel1.put("colValue","78464771722");
  94 +
  95 + JSONArray userDataPermArray = new JSONArray();
  96 + userDataPermArray.add(userDataPermModel);
  97 +// userDataPermArray.add(userDataPermModel1);
  98 + SessionUserContext.setSessionUser(userDataPermArray);
  99 + log.info("进入HTTPServletRequest 拦截器");
  100 + return true;
  101 + }
  102 +}
  1 +package com.tianbo.analysis.intercept;
  2 +
  3 +import org.springframework.context.annotation.Configuration;
  4 +import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
  5 +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
  6 +
  7 +@Configuration
  8 +public class UserCenterInterceptorConfig implements WebMvcConfigurer {
  9 +
  10 + @Override
  11 + public void addInterceptors(InterceptorRegistry registry) {
  12 + UserCenterHanlerInterceptor userCenterHanlerInterceptor = new UserCenterHanlerInterceptor();
  13 + registry.addInterceptor(userCenterHanlerInterceptor).addPathPatterns("/trans/selectTrans");
  14 + }
  15 +}
@@ -60,4 +60,12 @@ public class ResultJson<T> implements Serializable{ @@ -60,4 +60,12 @@ public class ResultJson<T> implements Serializable{
60 this.code = responseReason.getCode(); 60 this.code = responseReason.getCode();
61 this.msg = responseReason.getMsg(); 61 this.msg = responseReason.getMsg();
62 } 62 }
  63 +
  64 + @Override
  65 + public String toString() {
  66 + return "ResultJson{" +
  67 + "code='" + code + '\'' +
  68 + ", msg='" + msg + '\'' +
  69 + '}';
  70 + }
63 } 71 }
  1 +package com.tianbo.analysis.thread;
  2 +
  3 +import com.alibaba.fastjson.JSONArray;
  4 +import com.alibaba.fastjson.JSONObject;
  5 +
  6 +public class SessionUserContext {
  7 +
  8 + private static final ThreadLocal<JSONArray> SESSION_USER_THREAD_LOCAL = new ThreadLocal();
  9 +
  10 + public static void setSessionUser(JSONArray sessionUser){
  11 + SESSION_USER_THREAD_LOCAL.set(sessionUser);
  12 + }
  13 +
  14 + public static void clearSessionUser(){
  15 + SESSION_USER_THREAD_LOCAL.remove();
  16 + }
  17 +
  18 + public static JSONArray getSessionUser(){
  19 + return (JSONArray) SESSION_USER_THREAD_LOCAL.get();
  20 + }
  21 +
  22 + /** 下面可以添加获取用户ID或者用户名的方法例子:
  23 + *
  24 + public static Integer getSessionUserid(){
  25 + JSONArray sessionUser = getSessionUser();
  26 + return sessionUser.getInteger("userid");
  27 + }
  28 +
  29 + */
  30 +}
@@ -109,6 +109,9 @@ @@ -109,6 +109,9 @@
109 <if test="unloadcode != null and unloadcode != ''" > 109 <if test="unloadcode != null and unloadcode != ''" >
110 and UnloadCode = #{unloadcode,jdbcType=VARCHAR} 110 and UnloadCode = #{unloadcode,jdbcType=VARCHAR}
111 </if> 111 </if>
  112 + <if test="billno != null and billno != ''" >
  113 + and BillNo = #{billno,jdbcType=VARCHAR}
  114 + </if>
112 <if test="creattimeStart != null and creattimeEnd != null" > 115 <if test="creattimeStart != null and creattimeEnd != null" >
113 and CREATTIME between #{creattimeStart,jdbcType=TIMESTAMP} and #{creattimeEnd,jdbcType=TIMESTAMP} 116 and CREATTIME between #{creattimeStart,jdbcType=TIMESTAMP} and #{creattimeEnd,jdbcType=TIMESTAMP}
114 </if> 117 </if>
  1 +import com.tianbo.analysis.NmmsAdminApplication;
  2 +import lombok.extern.slf4j.Slf4j;
  3 +import org.junit.jupiter.api.Test;
  4 +import org.springframework.beans.factory.annotation.Autowired;
  5 +import org.springframework.boot.test.context.SpringBootTest;
  6 +import org.springframework.core.env.Environment;
  7 +import org.springframework.util.AntPathMatcher;
  8 +
  9 +@SpringBootTest(classes = NmmsAdminApplication.class)
  10 +@Slf4j
  11 +public class DataPermissionTest {
  12 +
  13 + @Autowired
  14 + private Environment environment;
  15 +
  16 + @Test
  17 + public void dataPermission(){
  18 + AntPathMatcher antPathMatcher = new AntPathMatcher();
  19 + String serviceName = environment.getProperty("spring.application.name");
  20 + }
  21 +}