作者 朱兆平

brench-update:

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

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