release: merge to master.

Signed-off-by: feihu.wang <wfh45678@163.com>
This commit is contained in:
feihu.wang
2019-11-18 10:34:16 +08:00
49 changed files with 1339 additions and 165 deletions

View File

@@ -5,6 +5,7 @@
A real-time risk analysis engine,which can update risk rule in real-time and make it effective immediately.
It applies to the anti-fraud application perfectly.
The project code called Radar, like the code, monitor the transaction at the back.
## 项目特点
* 实时风控特殊场景可以做到100ms内响应
@@ -15,6 +16,13 @@ The project code called Radar, like the code, monitor the transaction at the bac
* NoSQL易扩展高性能
* 配置简单,开箱即用!
## 相关站点
Github: https://github.com/wfh45678/radar
Gitee: https://gitee.com/freshday/radar // 码云为镜像网站,贡献代码请提交到 github
官网: http://radar.pgmmer.top
Wiki: https://gitee.com/freshday/radar/wikis/home
## 背景
伴随着移动互联网的高速发展,羊毛党快速崛起,从一平台到另一个平台,所过之处一地鸡毛,这还不是最可怕的,
随之而来的黑产令大部分互联网应用为之胆寒通常新上线的APP的福利比较大风控系统不完善BUG 被发现的频率也比较高,
@@ -96,19 +104,15 @@ https://gitee.com/freshday/radar/wikis/manual?sort_id=1637446
建议大家自行注册用户,避免使用同样的测试账号受干扰.
## 未完待续
### 小迭代
* React 版本升级v15.0.0
* 集成嵌入式redis版本本地调试的时候就不用再单独部署redis
* 集成 JWT(JSON WEB TOKEN),前后端分离标准化
* 插件配置管理,可以集成其他中间件的数据能力
* 支持Flink增加特征abstraction的提取基于Flink 的实现,以应对时间窗口相对较短,实时性要求更高的情况。
### 重大特性
* 支持机器学习
* 数据分析平台
## 致谢
感恩 XWF 团队,感谢参入的每一位小伙伴,后续征得同意后会一一列出名字。
感恩 XWF 团队,感谢参入的每一位小伙伴,后续征得同意后会一一列出名字。
千面怪, 烈日下的从容, DerekDingLu, king, sanying2012, 紫泉夜, 玄梦
成书平, 徐帅...
## Contact to
如果喜欢本项目Star支持一下, 让更多人了解本项目,谢谢!

View File

@@ -19,13 +19,14 @@
</parent>
<groupId>com.pgmmers</groupId>
<artifactId>radar</artifactId>
<version>1.0.1-SNAPSHOT</version>
<version>1.0.2-SNAPSHOT</version>
<name>radar</name>
<description>Demo project for Spring Boot</description>
<packaging>pom</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<tomcat.version>8.5.37</tomcat.version>
</properties>

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>radar</artifactId>
<groupId>com.pgmmers</groupId>
<version>1.0.1-SNAPSHOT</version>
<version>1.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>radar-admin</artifactId>
@@ -13,7 +13,6 @@
<packaging>jar</packaging>
<properties>
</properties>
<dependencies>
@@ -44,6 +43,11 @@
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/tk.mybatis/mapper -->
<dependency>

View File

@@ -2,6 +2,7 @@ package com.pgmmers.radar.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.pgmmers.radar.dal.bean.AbstractionQuery;
import com.pgmmers.radar.enums.PluginType;
import com.pgmmers.radar.service.common.CommonResult;
@@ -19,6 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@RestController
@RequestMapping("/services/v1/abstraction")
@@ -70,21 +72,20 @@ public class AbstractionApiController {
// 2、PREPARE
ds = new DataColumnInfo(DataType.PREITEMS.getDesc(), DataType.PREITEMS.getName());
List<PreItemVO> listPreItem = preItemService.listPreItem(modelId);
if(listPreItem!=null&&listPreItem.size()!=0){
if(listPreItem != null && listPreItem.size()!= 0){
for (PreItemVO preItem : listPreItem) {
PluginType pt = PluginType.get(preItem.getPlugin());
if (StringUtils.isNoneBlank(pt.getType())) {
if (StringUtils.isNotEmpty(pt.getType()) && pt.getType().equals("JSON")) {
//load http request data
JsonNode json = preItem.getConfigJson();
List<DataColumnInfo> children = new ArrayList<>();
extractMetaColumn(ds, preItem, json.toString(), children);
} else if (StringUtils.isNotEmpty(pt.getType())) {
ds.addChildren(preItem.getLabel(), preItem.getDestField(), pt.getType());
} else {
List<DataColumnInfo> children = new ArrayList<>();
JSONArray array = JSONArray.parseArray(pt.getMeta());
for (int i = 0; i < array.size(); i++) {
JSONObject obj = array.getJSONObject(i);
children.add(new DataColumnInfo(obj.getString("title"), obj.getString("column"), obj
.getString("type")));
}
ds.addChildren(preItem.getLabel(), preItem.getDestField(), children);
}
extractMetaColumn(ds, preItem, pt.getMeta(), children);
}
}
list.add(ds);
}
@@ -95,7 +96,17 @@ public class AbstractionApiController {
return result;
}
@PutMapping
private void extractMetaColumn(DataColumnInfo ds, PreItemVO preItem, String jsonStr, List<DataColumnInfo> children) {
JSONArray array = JSONArray.parseArray(jsonStr);
for (int i = 0; i < array.size(); i++) {
JSONObject obj = array.getJSONObject(i);
children.add(new DataColumnInfo(obj.getString("title"), obj.getString("column"), obj
.getString("type")));
}
ds.addChildren(preItem.getLabel(), preItem.getDestField(), children);
}
@PutMapping
public CommonResult save(@RequestBody AbstractionVO abstraction) {
return abstractionService.save(abstraction);
}

View File

@@ -3,6 +3,7 @@ package com.pgmmers.radar.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.pgmmers.radar.dal.bean.ActivationQuery;
import com.pgmmers.radar.enums.FieldType;
import com.pgmmers.radar.enums.PluginType;
@@ -67,17 +68,16 @@ public class ActivationApiController {
List<PreItemVO> listPreItem = preItemService.listPreItem(modelId);
for (PreItemVO preItem : listPreItem) {
PluginType pt = PluginType.get(preItem.getPlugin());
if (StringUtils.isNoneBlank(pt.getType())) {
if (StringUtils.isNotEmpty(pt.getType()) && pt.getType().equals("JSON")) {
//load http request data
JsonNode json = preItem.getConfigJson();
List<DataColumnInfo> children = new ArrayList<>();
extractMetaColumn(ds, preItem, json.toString(), children);
} else if (StringUtils.isNotEmpty(pt.getType())) {
ds.addChildren(preItem.getLabel(), preItem.getDestField(), pt.getType());
} else {
List<DataColumnInfo> children = new ArrayList<>();
JSONArray array = JSONArray.parseArray(pt.getMeta());
for (int i = 0; i < array.size(); i++) {
JSONObject obj = array.getJSONObject(i);
children.add(new DataColumnInfo(obj.getString("title"), obj.getString("column"), obj
.getString("type")));
}
ds.addChildren(preItem.getLabel(), preItem.getDestField(), children);
extractMetaColumn(ds, preItem, pt.getMeta(), children);
}
}
list.add(ds);
@@ -133,5 +133,15 @@ public class ActivationApiController {
@PostMapping("/updateOrder")
public CommonResult updateOrder(@RequestParam Long activationId, @RequestParam String ruleOrder) {
return activationService.updateOrder(activationId,ruleOrder);
}
}
private void extractMetaColumn(DataColumnInfo ds, PreItemVO preItem, String jsonStr, List<DataColumnInfo> children) {
JSONArray array = JSONArray.parseArray(jsonStr);
for (int i = 0; i < array.size(); i++) {
JSONObject obj = array.getJSONObject(i);
children.add(new DataColumnInfo(obj.getString("title"), obj.getString("column"), obj
.getString("type")));
}
ds.addChildren(preItem.getLabel(), preItem.getDestField(), children);
}
}

View File

@@ -1,19 +1,30 @@
package com.pgmmers.radar.controller;
import com.pgmmers.radar.dal.bean.DataListQuery;
import com.pgmmers.radar.service.common.CommonResult;
import com.pgmmers.radar.service.model.DataListsService;
import com.pgmmers.radar.util.ExcelImportUtil;
import com.pgmmers.radar.util.ExportExcelInfo;
import com.pgmmers.radar.vo.model.DataListsVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/services/v1/datalist")
@Api(value = "DataListsApi", description = "黑白名单列表接口相关操作", tags = {"数据列表API"})
public class DataListApiController {
public static Logger logger = LoggerFactory.getLogger(DataListApiController.class);
@Autowired
private DataListsService dataListsService;
@@ -49,4 +60,47 @@ public class DataListApiController {
return dataListsService.delete(id);
}
/**
*
* 批量导入黑/白名单管理
* @param file 文件
* @param modelId 模型ID
* @return
* @author xushuai
*/
@PostMapping(value = "/batchImportData")
public CommonResult batchImportData(@ApiParam(value = "file detail") @RequestPart("file") MultipartFile file, @RequestParam(value = "modelId", required = true)Long modelId) {
CommonResult result = new CommonResult();
result.setSuccess(false);
String fileName = file.getOriginalFilename();
if (fileName != null && !(fileName.contains(".xls") || fileName.contains(".xlsx"))) {
result.setMsg("传入的件格式有误!");
return result;
}
ExportExcelInfo<DataListsVO> info = getImportMeta();
List<Map<String, Object>> listError = new ArrayList<>();
List<DataListsVO> list = null;
try {
list = ExcelImportUtil.excelToList(file.getInputStream(), info, listError, DataListsVO.class);
} catch (Exception e) {
logger.error("导入Excel失败:" + e.getMessage());
}
if (list == null || list.size() == 0) {
result.setMsg("无导入数据!");
return result;
}
if (list.size() > 1000) {
result.setMsg("最大导入不能超过" + 1000 + "");
return result;
}
return dataListsService.batchImportData(list, modelId);
}
private ExportExcelInfo<DataListsVO> getImportMeta() {
ExportExcelInfo<DataListsVO> info = new ExportExcelInfo<DataListsVO>(null);
info.addExcelColumn("备注", "comment");
info.addExcelColumn("列表名", "label");
info.addExcelColumn("名单类型", "listType");
return info;
}
}

View File

@@ -4,16 +4,28 @@ package com.pgmmers.radar.controller;
import com.pgmmers.radar.dal.bean.DataListRecordQuery;
import com.pgmmers.radar.service.common.CommonResult;
import com.pgmmers.radar.service.model.DataListsService;
import com.pgmmers.radar.util.ExcelImportUtil;
import com.pgmmers.radar.util.ExportExcelInfo;
import com.pgmmers.radar.vo.model.DataListRecordVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/services/v1/datalistrecord")
@Api(value = "DataListRecordApi", description = "列表内容维护接口相关操作", tags = {"列表内容API"})
public class DataListRecordApiController {
public static Logger logger = LoggerFactory.getLogger(DataListRecordApiController.class);
@Autowired
private DataListsService dataListsService;
@@ -45,4 +57,46 @@ public class DataListRecordApiController {
return dataListsService.deleteRecord(id);
}
/**
*
* 批量导入黑/白名单管理
* @param file 文件
* @param dataListId 数据列表ID
* @return
* @author xushuai
*/
@PostMapping(value = "/batchImportDataRecord")
public CommonResult batchImportDataRecord(@ApiParam(value = "file detail") @RequestPart("file") MultipartFile file, @RequestParam(value = "dataListId", required = true)Long dataListId) {
CommonResult result = new CommonResult();
result.setSuccess(false);
String fileName = file.getOriginalFilename();
if (fileName != null && !(fileName.contains(".xls") || fileName.contains(".xlsx"))) {
result.setMsg("传入的件格式有误!");
return result;
}
ExportExcelInfo<DataListRecordVO> info = getImportMeta();
List<Map<String, Object>> listError = new ArrayList<>();
List<DataListRecordVO> list = null;
try {
list = ExcelImportUtil.excelToList(file.getInputStream(), info, listError, DataListRecordVO.class);
} catch (Exception e) {
logger.error("导入Excel失败:" + e.getMessage());
}
if (list == null || list.size() == 0) {
result.setMsg("无导入数据!");
return result;
}
if (list.size() > 1000) {
result.setMsg("最大导入不能超过" + 1000 + "");
return result;
}
return dataListsService.batchImportDataRecord(list, dataListId);
}
private ExportExcelInfo<DataListRecordVO> getImportMeta() {
ExportExcelInfo<DataListRecordVO> info = new ExportExcelInfo<DataListRecordVO>(null);
info.addExcelColumn("dataRecord", "dataRecord");
return info;
}
}

View File

@@ -260,7 +260,6 @@ public class EventApiController {
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

View File

@@ -0,0 +1,64 @@
package com.pgmmers.radar.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 优化参数名称
* @author xushuai
*/
public class CamelUtil {
public static final char UNDERLINE = '_';
public static String camelToUnderline(String param) {
if (param == null || "".equals(param.trim())) {
return "";
}
int len = param.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
char c = param.charAt(i);
if (Character.isUpperCase(c)) {
sb.append(UNDERLINE);
sb.append(Character.toLowerCase(c));
} else {
sb.append(c);
}
}
return sb.toString();
}
public static String underlineToCamel(String param) {
if (param == null || "".equals(param.trim())) {
return "";
}
int len = param.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
char c = param.charAt(i);
if (c == UNDERLINE) {
if (++i < len) {
sb.append(Character.toUpperCase(param.charAt(i)));
}
} else {
sb.append(c);
}
}
return sb.toString();
}
public static String underlineToCamel2(String param) {
if (param == null || "".equals(param.trim())) {
return "";
}
StringBuilder sb = new StringBuilder(param);
Matcher mc = Pattern.compile("_").matcher(param);
int i = 0;
while (mc.find()) {
int position = mc.end() - (i++);
//String.valueOf(Character.toUpperCase(sb.charAt(position)));
sb.replace(position - 1, position + 1, sb.substring(position, position + 1).toUpperCase());
}
return sb.toString();
}
}

View File

@@ -0,0 +1,21 @@
package com.pgmmers.radar.util;
/**
* Excel字段类型
* @author xushuai
*/
public enum EnumExcelColumnType {
ColumnType_Double(0),
ColumnType_Date(1),
ColumnType_Calendar(2),
ColumnType_String(3),
ColumnType__BOOLEAN(4),
ColumnType_ERROR(5);
private int RowId;
private EnumExcelColumnType(int id) {
RowId = id;
}
public int GetValue() {
return RowId;
}
}

View File

@@ -0,0 +1,128 @@
package com.pgmmers.radar.util;
import org.springframework.util.StringUtils;
/**
* 列信息整理
* @author xushuai
*/
public class ExcelColumn<T> {
String text;
String tableName;
String columnName;
String camelColumnName;
EnumExcelColumnType columnType;
boolean isNull=true;
int orderIndex;
FunctionFormatter<Object, T, Integer, Object> formatter;
double columnWidth;
public ExcelColumn()
{
}
public ExcelColumn(String columnName, String tableName, String text)
{
this.columnName=columnName;
this.camelColumnName= CamelUtil.underlineToCamel(this.columnName);
this.tableName=tableName;
this.text=text;
}
public ExcelColumn(String columnName, String tableName, String text, boolean isNull) {
this(columnName, tableName, text);
this.isNull = isNull;
}
public ExcelColumn(String columnName, int orderIndex, String tableName, String text)
{
this.columnName=columnName;
this.camelColumnName= CamelUtil.underlineToCamel(this.columnName);
this.orderIndex=orderIndex;
this.tableName=tableName;
this.text=text;
}
public ExcelColumn(String columnName, int orderIndex, String tableName, String text, boolean isNull)
{
this(columnName,orderIndex,tableName,text);
this.isNull=isNull;
}
public ExcelColumn(String columnName, int orderIndex, String tableName, String text, EnumExcelColumnType columnType, boolean isNull)
{
this(columnName,orderIndex,tableName,text);
this.columnType=columnType;
this.isNull=isNull;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
private String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getCamelColumnName() {
if(StringUtils.isEmpty(camelColumnName))
{
return this.getColumnName();
}
return camelColumnName;
}
public void setCamelColumnName(String camelColumnName) {
this.camelColumnName = camelColumnName;
}
public EnumExcelColumnType getColumnType() {
return columnType;
}
public void setColumnType(EnumExcelColumnType columnType) {
this.columnType = columnType;
}
public boolean isNull() {
return isNull;
}
public void setNull(boolean aNull) {
isNull = aNull;
}
public int getOrderIndex() {
return orderIndex;
}
public void setOrderIndex(int orderIndex) {
this.orderIndex = orderIndex;
}
public FunctionFormatter<Object, T, Integer, Object> getFormatter() {
return formatter;
}
public void setFormatter(FunctionFormatter<Object, T, Integer, Object> formatter) {
this.formatter = formatter;
}
public double getColumnWidth() {
return columnWidth;
}
public void setColumnWidth(double columnWidth) {
this.columnWidth = columnWidth;
}
}

View File

@@ -0,0 +1,198 @@
package com.pgmmers.radar.util;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.ss.usermodel.*;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 将导入的文件列信息转换为model
* @author xushuai
*/
public class ExcelImportUtil {
public static <TModel> List<TModel> excelToList(
HttpServletRequest request,
ExportExcelInfo<TModel> info,List<Map<String, Object>> listErrorMap,Class<TModel> entityClass
) throws Exception {
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
String fileName= multiRequest.getFileNames().next();
MultipartFile multipartFile=multiRequest.getFile(fileName);
// MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
// MultipartFile File= multiRequest.getMultiFileMap().;
// request.get
//
// multiRequest.getMultiFileMap().f
//取得上传文件流
InputStream in =multipartFile.getInputStream() ;
return excelToList(in, info, listErrorMap, entityClass);
}
public static <TModel> List<TModel> excelToList(
InputStream in,
ExportExcelInfo<TModel> info,List<Map<String, Object>> listErrorMap,Class<TModel> entityClass
) throws Exception {
//定义要返回的list
List<TModel> resultList = new ArrayList<TModel>();
String sheetName = info.getSheet();
//根据Excel数据源创建WorkBook
Workbook wb = WorkbookFactory.create(in);
// HSSFWorkbook wb = new HSSFWorkbook(in);
//获取工作表
Sheet sheet;
if (wb.getNumberOfSheets() > 1 && !sheetName.equals("")) {
sheet = wb.getSheet(sheetName);
} else {
sheet = wb.getSheetAt(0);
}
importSheet(sheet, info, resultList, listErrorMap, entityClass);
return resultList;
}
public static <TModel> void importSheet(Sheet productSheet, ExportExcelInfo<TModel> info, List<TModel> listTModel, List<Map<String, Object>> listErrorMap, Class<TModel> entityClass) throws Exception {
importSheet(productSheet, info, listTModel, listErrorMap, entityClass,0);
}
/**
* @param productSheet listTModel
* @param listTModel 导入集合
* @param listErrorMap 导入错误集合
* @throws Exception
*/
public static <TModel> void importSheet(Sheet productSheet, ExportExcelInfo<TModel> info, List<TModel> listTModel, List<Map<String, Object>> listErrorMap, Class<TModel> entityClass, int columnRowIndex) throws Exception {
int LastCellNum = productSheet.getRow(0).getLastCellNum();//列数量
Row rowColumn = productSheet.getRow(columnRowIndex);//excel列所在行
Map<String, Integer> mapExcelColumn = new HashMap<>();//excel 列名字和列索引对应 key:excel列名字 value:excel列索引
for (int i = 0; i < LastCellNum; i++) {
mapExcelColumn.put(ExcelUtils.getString(rowColumn, i), i);
}
Map<String, Field> mapFiled = getMapFiled(entityClass);
//TModel 所有属性字段Field key: 字段名
int LastRowNum = productSheet.getLastRowNum();//excel最后一行
TModel model;
String errorMsg=null;
for (int i = columnRowIndex + 1; i <= LastRowNum; i++) {
Row row = productSheet.getRow(i);//获取行
model = entityClass.newInstance();
if(row!=null) {
errorMsg = rowToModel(mapExcelColumn, info, row, model, mapFiled);//行转model
} else {errorMsg=null;}
if (!StringUtils.isEmpty(errorMsg)) {//转换失败 保存错误行
Map<String, Object> errorMap = getErrorMap(row, mapExcelColumn);//row转map
errorMap.put("errorMsg", errorMsg);
listErrorMap.add(errorMap);//加入转换错误行集合
} else {//转换成功
listTModel.add(model);
}
}
}
private static <TModel> Map<String, Field> getMapFiled(Class<TModel> entityClass) {
Map<String, Field> mapFiled = new HashMap<>();
List<Field> listField = ReflectUtil.getListField(entityClass);
for (Field field : listField) {
mapFiled.put(field.getName(), field);
}
return mapFiled;
}
/**
* 行转model
*/
static <TModel> String rowToModel(Map<String, Integer> mapExcelColumn, ExportExcelInfo<TModel> info, Row row, TModel model, Map<String, Field> mapFiled) throws Exception {
String errorMsg = "";
boolean hasValue = false;
for (ExcelColumn column : info.getListColumn()) {
if (mapExcelColumn.containsKey(column.getText())) {
if (!mapFiled.containsKey(column.getCamelColumnName())) {
throw new Exception(model.getClass().getName() + "不存在字段" + column.getCamelColumnName());
}
Field field = mapFiled.get(column.getCamelColumnName());
String content = getString(row.getCell(mapExcelColumn.get(column.getText())));
if (!column.isNull()) {
if (StringUtils.isEmpty(content)) {
errorMsg += column.getCamelColumnName() + "不能为空";
}
}
try {
if (!StringUtils.isEmpty(content)) {
hasValue = true;
ReflectUtil.setFieldValueByName(field, content.trim(), model);
}
} catch (Exception e) {
errorMsg += column.getCamelColumnName() + ":" + e.getMessage();
}
}
}
if(!hasValue){
errorMsg +="该表格中有空行";
}
return errorMsg;
}
static Map<String, Object> getErrorMap(Row row, Map<String, Integer> mapExcelColumn) {
Map<String, Object> map = new HashMap<>();
for (String key : mapExcelColumn.keySet()) {
Cell cell = row.getCell(mapExcelColumn.get(key));
map.put(key, getString(cell));
}
return map;
}
static String getString(Cell cell) {
String result = "";
if (cell == null) return result;
switch (cell.getCellType()) {
case HSSFCell.CELL_TYPE_NUMERIC:// 数字类型
//1、判断是否是数值格式
if (HSSFDateUtil.isCellDateFormatted(cell)) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
double value = cell.getNumericCellValue();
Date date = org.apache.poi.ss.usermodel.DateUtil.getJavaDate(value);
result = sdf.format(date);
} else {
Double value = cell.getNumericCellValue();
DecimalFormat format = new DecimalFormat();
format.applyPattern("###################.###################");
result = format.format(value);
}
break;
case HSSFCell.CELL_TYPE_STRING:// String类型
result = cell.getRichStringCellValue().toString();
break;
case HSSFCell.CELL_TYPE_FORMULA://公式型
//读公式计算值
try {
double value = cell.getNumericCellValue();
if (Double.isNaN(value)) {//如果获取的数据值为非法值,则转换为获取字符串 //result.equals("NaN")
result = cell.getRichStringCellValue().toString();
} else {
DecimalFormat format = new DecimalFormat();
format.applyPattern("###################.###################");
result = format.format(value);
}
} catch (Exception ex) {
result = cell.getRichStringCellValue().toString();
}
break;
case HSSFCell.CELL_TYPE_BLANK:
result = "";
break;
default:
result = "";
break;
}
return result;
}
}

View File

@@ -0,0 +1,113 @@
package com.pgmmers.radar.util;
import java.util.ArrayList;
import java.util.List;
/**
* 导入Excel列信息
* @author xushuai
*/
public class ExportExcelInfo<TRow> {
public ExportExcelInfo(List<TRow> dataSource) {
this.setDataSource(dataSource);
}
List<ExcelColumn<TRow>> listColumn = new ArrayList<ExcelColumn<TRow>>();
String fileName;
List<TRow> dataSource;
String Sheet = "sheet1";
int columnType;//列的类型 0:text(文本) 1:columnName
public int getColumnType() {
return columnType;
}
public void setColumnType(int columnType) {
this.columnType = columnType;
}
boolean IsDisplayColumnName = false;
public boolean isDisplayColumnName() {
return IsDisplayColumnName;
}
public void setDisplayColumnName(boolean displayColumnName) {
IsDisplayColumnName = displayColumnName;
}
public String getSheet() {
return Sheet;
}
public void setSheet(String sheet) {
Sheet = sheet;
}
public List<TRow> getDataSource() {
return dataSource;
}
public void setDataSource(List<TRow> dataSource) {
this.dataSource = dataSource;
}
public List<ExcelColumn<TRow>> getListColumn() {
return listColumn;
}
public void setListColumn(List<ExcelColumn<TRow>> listColumn) {
this.listColumn = listColumn;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public void addExcelColumn(ExcelColumn column) {
listColumn.add(column);
}
public ExcelColumn<TRow> addExcelColumn(String text, String columnName) {
ExcelColumn<TRow> column = new ExcelColumn<TRow>();
column.setText(text);
column.setColumnName(columnName);
column.setColumnType(EnumExcelColumnType.ColumnType_String);
this.getListColumn().add(column);
return column;
}
public ExcelColumn addExcelColumn(String text, String columnName, EnumExcelColumnType columnType) {
ExcelColumn<TRow> column = addExcelColumn(text, columnName);
column.setColumnType(columnType);
return column;
}
public ExcelColumn<TRow> addExcelColumn(String text, String columnName, FunctionFormatter<Object, TRow, Integer, Object> formatter) {
ExcelColumn<TRow> column = addExcelColumn(text, columnName);
column.setFormatter(formatter);
return column;
}
public ExcelColumn<TRow> addExcelColumn(String text, String columnName, FunctionFormatter<Object, TRow, Integer, Object> formatter, EnumExcelColumnType columnType) {
ExcelColumn column = addExcelColumn(text, columnName, formatter);
column.setColumnType(columnType);
return column;
}
public ExcelColumn<TRow> getErrorColumn() {
ExcelColumn<TRow> column = new ExcelColumn<TRow>();
column.setText("异常信息");
column.setColumnName("errorMsg");//errorMsg
column.setColumnType(EnumExcelColumnType.ColumnType_String);
column.setCamelColumnName("errorMsg");
return column;
}
}

View File

@@ -0,0 +1,9 @@
package com.pgmmers.radar.util;
/**
* @author xushuai
*/
@FunctionalInterface
public interface FunctionFormatter<TValue,TRow,TIndex,R> {
R apply(TValue value, TRow row, TIndex index);
}

View File

@@ -0,0 +1,155 @@
package com.pgmmers.radar.util;
import com.pgmmers.radar.dal.util.JsonUtils;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* 根据字段名获取字段
* @author xushuai
*/
public class ReflectUtil {
public static void setFieldValueByName(Field field, Object fieldValue, Object o) throws Exception {
field.setAccessible(true);
//获取字段类型
Class<?> fieldType = field.getType();
//根据字段类型给字段赋值
if (String.class == fieldType) {
field.set(o, String.valueOf(fieldValue));
} else if ((Integer.TYPE == fieldType)
|| (Integer.class == fieldType)) {
field.set(o, Integer.parseInt(fieldValue.toString()));
} else if ((Long.TYPE == fieldType)
|| (Long.class == fieldType)) {
field.set(o, Long.valueOf(fieldValue.toString()));
} else if ((Float.TYPE == fieldType)
|| (Float.class == fieldType)) {
field.set(o, Float.valueOf(fieldValue.toString()));
} else if ((Short.TYPE == fieldType)
|| (Short.class == fieldType)) {
field.set(o, Short.valueOf(fieldValue.toString()));
} else if ((Byte.TYPE == fieldType)
|| (Byte.class == fieldType)) {
field.set(o, Byte.valueOf(fieldValue.toString()));
}
else if ((Double.TYPE == fieldType)
|| (Double.class == fieldType)) {
field.set(o, Double.valueOf(fieldValue.toString()));
} else if (Character.TYPE == fieldType) {
if ((fieldValue != null) && (fieldValue.toString().length() > 0)) {
field.set(o, fieldValue.toString().charAt(0));
}
} else if (BigDecimal.class == fieldType) {
Long v1 = Long.valueOf(fieldValue.toString());
field.set(o, BigDecimal.valueOf(v1));
} else if (Date.class == fieldType) {
field.set(o, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(fieldValue.toString()));
} else if (boolean.class == fieldType) {
if ("1".equals(fieldValue)) {
field.set(o, true);
}
if ("0".equals(fieldValue)) {
field.set(o, false);
}
field.set(o, Boolean.valueOf(fieldValue.toString()));
} else if (String[].class == fieldType) {
String[] arr = JsonUtils.fromJson(fieldValue.toString(), String[].class);
field.set(o, arr);
} else {
field.set(o, fieldValue);
}
}
public static List<Field> getListField(Class<?> clazz) {
Field[] selfFields = clazz.getDeclaredFields();
List<Field> list = new ArrayList<>(Arrays.asList(selfFields));
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null && superClazz != Object.class) {
List<Field> listSuperField = getListField(superClazz);
for (Field field : listSuperField) {
list.add(field);
}
}
return list;
}
/**
* 根据字段名获取字段
*
* @param fieldName 字段名
* @param clazz 包含该字段的类
* @return 字段
*/
public static Field getFieldByName(String fieldName, Class<?> clazz) {
//拿到本类的所有字段
Field[] selfFields = clazz.getDeclaredFields();
//如果本类中存在该字段,则返回
for (Field field : selfFields) {
if (field.getName().equals(fieldName)) {
return field;
}
}
//否则,查看父类中是否存在此字段,如果有则返回
Class<?> superClazz = clazz.getSuperclass();
if (superClazz != null && superClazz != Object.class) {
return getFieldByName(fieldName, superClazz);
}
//如果本类和父类都没有,则返回空
return null;
}
/**
* getFieldValueByNameSequence
*
* @param fieldNameSequence 带路径的属性名或简单属性名
* @param o 对象
* @return 属性值
* @throws Exception 根据带路径或不带路径的属性名获取属性值
* 即接受简单属性名如userName等又接受带路径的属性名如student.department.name等
*/
public static Object getFieldValueByNameSequence(String fieldNameSequence, Object o) throws Exception {
Object value;
//将fieldNameSequence进行拆分
String[] attributes = fieldNameSequence.split("\\.");
if (attributes.length == 1) {
value = getFieldValueByName(fieldNameSequence, o);
} else {
//根据属性名获取属性对象
Object fieldObj = getFieldValueByName(attributes[0], o);
String subFieldNameSequence = fieldNameSequence.substring(fieldNameSequence.indexOf(".") + 1);
value = getFieldValueByNameSequence(subFieldNameSequence, fieldObj);
}
return value;
}
/*<-------------------------辅助的私有方法----------------------------------------------->*/
/**
* 根据字段名获取字段值
*
* @param fieldName 字段名
* @param o 对象
* @return 字段值
*/
public static Object getFieldValueByName(String fieldName, Object o) throws Exception {
Object value;
Field field = getFieldByName(fieldName, o.getClass());
if (field == null) {
throw new Exception(o.getClass().getSimpleName() + "类不存在字段名 " + fieldName);
}
value = getValueByField(fieldName, o, field);
return value;
}
private static Object getValueByField(String fieldName, Object o, Field field) throws IllegalAccessException {
field.setAccessible(true);
return field.get(o);
}
}

View File

@@ -1,3 +1,3 @@
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>风控引擎管理平台</title> <link rel="shortcut icon" href="/images/anquan.png"> <!--[if lt IE 10]>
<script src="https://as.alipayobjects.com/g/component/??console-polyfill/0.2.2/index.js,es5-shim/4.5.7/es5-shim.min.js,es5-shim/4.5.7/es5-sham.min.js,html5shiv/3.7.2/html5shiv.min.js,media-match/2.0.2/media.match.min.js"></script>
<![endif]--> <link href="./index.b4475d72-1.css" rel="stylesheet"><link href="./index.b4475d72-2.css" rel="stylesheet"><link href="./index.b4475d72-3.css" rel="stylesheet"></head> <body> <div id="react-content"></div> <script type="text/javascript" src="./main.b4475d72.js"></script></body> </html>
<![endif]--> <link href="./index.3b7ff13c-1.css" rel="stylesheet"><link href="./index.3b7ff13c-2.css" rel="stylesheet"><link href="./index.3b7ff13c-3.css" rel="stylesheet"></head> <body> <div id="react-content"></div> <script type="text/javascript" src="./main.3b7ff13c.js"></script></body> </html>

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,7 @@
<parent>
<artifactId>radar</artifactId>
<groupId>com.pgmmers</groupId>
<version>1.0.1-SNAPSHOT</version>
<version>1.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -9,6 +9,8 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.List;
import java.util.Map;
@@ -112,4 +114,45 @@ public class ExcelUtils {
}
}
/**
* 从 row 的第 index 列,获取字符串值
*
* @param row 目标行
* @param index 目标列
* @return 字符串值
* @author xushuai
*/
public static String getString(Row row, int index) {
return getString(row, index, null);
}
/**
* 从 row 的第 index 列,获取字符串值
*
* @param row 目标行
* @param index 目标列
* @param numberFormat 对原值为数字时的,数字格式化格式
* @return 字符串值
* @author xushuai
*/
public static String getString(Row row, int index, String numberFormat) {
Cell cell = row.getCell(index);
if (cell == null) return null;
switch (cell.getCellType()) {
case Cell.CELL_TYPE_NUMERIC:
double val = cell.getNumericCellValue();
if (numberFormat == null)
return String.valueOf(val);
NumberFormat formatter = new DecimalFormat(numberFormat);
return formatter.format(val);
case Cell.CELL_TYPE_STRING:
return cell.getStringCellValue();
case Cell.CELL_TYPE_FORMULA:
return cell.getStringCellValue();
default:
return null;
}
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>radar</artifactId>
<groupId>com.pgmmers</groupId>
<version>1.0.1-SNAPSHOT</version>
<version>1.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -233,7 +233,7 @@ public class ModelDalImpl implements ModelDal {
PreItemVO vo = null;
for (PreItemPO po : itemPOList) {
vo = new PreItemVO();
BeanUtils.copyProperties(po, vo);
vo = POVOUtils.copyFromPreItemPO(po);
itemList.add(vo);
}
return itemList;

View File

@@ -5,6 +5,7 @@ import com.github.pagehelper.PageHelper;
import com.pgmmers.radar.dal.bean.PageResult;
import com.pgmmers.radar.dal.bean.PreItemQuery;
import com.pgmmers.radar.dal.model.PreItemDal;
import com.pgmmers.radar.dal.util.POVOUtils;
import com.pgmmers.radar.mapper.PreItemMapper;
import com.pgmmers.radar.model.PreItemPO;
import com.pgmmers.radar.vo.model.PreItemVO;
@@ -34,7 +35,8 @@ public class PreItemDalImpl implements PreItemDal {
PreItemPO preItem = preItemMapper.selectByPrimaryKey(id);
if (preItem != null) {
PreItemVO preItemVO = new PreItemVO();
BeanUtils.copyProperties(preItem, preItemVO);
//BeanUtils.copyProperties(preItem, preItemVO);
preItemVO = POVOUtils.copyFromPreItemPO(preItem);
return preItemVO;
}
return null;
@@ -63,8 +65,8 @@ public class PreItemDalImpl implements PreItemDal {
List<PreItemVO> listVO = new ArrayList<PreItemVO>();
for (PreItemPO preItemPO : page.getResult()) {
PreItemVO preItemVO = new PreItemVO();
BeanUtils.copyProperties(preItemPO, preItemVO);
PreItemVO preItemVO ;
preItemVO = POVOUtils.copyFromPreItemPO(preItemPO);
listVO.add(preItemVO);
}
@@ -75,15 +77,15 @@ public class PreItemDalImpl implements PreItemDal {
@Override
public int save(PreItemVO preItem) {
PreItemPO preItemPO = new PreItemPO();
BeanUtils.copyProperties(preItem, preItemPO);
PreItemPO preItemPO ;
preItemPO = POVOUtils.copyFromPreItemVO(preItem);
Date sysDate = new Date();
int count = 0;
if (preItemPO.getId() == null) {
preItemPO.setCreateTime(sysDate);
preItemPO.setUpdateTime(sysDate);
count = preItemMapper.insertSelective(preItemPO);
preItem.setId(preItemPO.getId());// 返回id
preItem.setId(preItemPO.getId());
} else {
preItemPO.setUpdateTime(sysDate);
count = preItemMapper.updateByPrimaryKeySelective(preItemPO);

View File

@@ -0,0 +1,62 @@
package com.pgmmers.radar.dal.util;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.Map;
/**
* json对象转换
* @author xushuai
*/
public class JsonUtils {
public JsonUtils() {
}
public static String toJson(Object object) {
try {
return (new ObjectMapper()).setSerializationInclusion(Include.NON_NULL).writeValueAsString(object);
} catch (JsonProcessingException var2) {
throw new RuntimeException(var2);
}
}
public static <E> E fromJson(String json, Class<E> type) {
try {
return (new ObjectMapper()).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).readValue(json, type);
} catch (IOException var3) {
throw new RuntimeException(var3);
}
}
public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
return (new ObjectMapper()).getTypeFactory().constructParametricType(collectionClass, elementClasses);
}
public static String toJsonString(Object object) {
try {
return (new ObjectMapper()).writeValueAsString(object);
} catch (JsonProcessingException var2) {
var2.printStackTrace();
return null;
}
}
public static Map writeJsonToMap(String json) {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
Map map = null;
try {
map = (Map)mapper.readValue(json, Map.class);
return map;
} catch (IOException var4) {
throw new RuntimeException(var4);
}
}
}

View File

@@ -4,15 +4,14 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.pgmmers.radar.model.AbstractionPO;
import com.pgmmers.radar.model.MobileInfoPO;
import com.pgmmers.radar.model.ModelPO;
import com.pgmmers.radar.model.RulePO;
import com.pgmmers.radar.model.*;
import com.pgmmers.radar.vo.data.MobileInfoVO;
import com.pgmmers.radar.vo.model.AbstractionVO;
import com.pgmmers.radar.vo.model.ModelVO;
import com.pgmmers.radar.vo.model.PreItemVO;
import com.pgmmers.radar.vo.model.RuleVO;
import jdk.nashorn.internal.parser.JSONParser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import java.io.IOException;
@@ -89,4 +88,34 @@ public class POVOUtils {
}
return po;
}
public static PreItemPO copyFromPreItemVO(PreItemVO vo) {
PreItemPO po = new PreItemPO();
BeanUtils.copyProperties(vo, po);
try {
if (vo.getConfigJson() != null) {
String str = objectMapper.writeValueAsString(vo.getConfigJson());
po.setConfigJson(str);
}
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return po;
}
public static PreItemVO copyFromPreItemPO(PreItemPO po) {
PreItemVO vo = new PreItemVO();
BeanUtils.copyProperties(po, vo);
JsonNode json = null;
try {
if (!StringUtils.isEmpty(po.getConfigJson())) {
json = objectMapper.readTree(po.getConfigJson());
}
} catch (IOException e) {
e.printStackTrace();
}
vo.setConfigJson(json);
return vo;
}
}

View File

@@ -16,13 +16,13 @@ public enum PluginType {
"ip2location",
"IP转换成地址",
null,
"[{\"column\":\"country\", \"title\":\"国家\", \"type\":\"STRING\"},{\"column\":\"provice\", \"title\":\"省份\", \"type\":\"STRING\"},{\"column\":\"city\", \"title\":\"城市\", \"type\":\"STRING\"}]"), //
"[{\"column\":\"country\", \"title\":\"国家\", \"type\":\"STRING\"},{\"column\":\"province\", \"title\":\"省份\", \"type\":\"STRING\"},{\"column\":\"city\", \"title\":\"城市\", \"type\":\"STRING\"}]"), //
GPS2LOCATION(
2,
"gps2location",
"GPS转换成地址",
null,
"[{\"column\":\"country\", \"title\":\"国家\", \"type\":\"STRING\"},{\"column\":\"provice\", \"title\":\"省份\", \"type\":\"STRING\"},{\"column\":\"city\", \"title\":\"城市\", \"type\":\"STRING\"}]"), //
"[{\"column\":\"country\", \"title\":\"国家\", \"type\":\"STRING\"},{\"column\":\"province\", \"title\":\"省份\", \"type\":\"STRING\"},{\"column\":\"city\", \"title\":\"城市\", \"type\":\"STRING\"}]"), //
ALLINONE(3, "allInOne", "字段合并", "STRING", null), //
SUBSTRING(4, "subString", "字符串截短", "STRING", null), //
MOBILE2LOCATION(
@@ -30,9 +30,10 @@ public enum PluginType {
"mobile2location",
"手机号码归属地",
null,
"[{\"column\":\"country\", \"title\":\"国家\", \"type\":\"STRING\"},{\"column\":\"provice\", \"title\":\"省份\", \"type\":\"STRING\"},{\"column\":\"city\", \"title\":\"城市\", \"type\":\"STRING\"}]"), //
"[{\"column\":\"country\", \"title\":\"国家\", \"type\":\"STRING\"},{\"column\":\"province\", \"title\":\"省份\", \"type\":\"STRING\"},{\"column\":\"city\", \"title\":\"城市\", \"type\":\"STRING\"}]"), //
SENSITIVE_TIME(6, "getSensitiveTime", "敏感时间段(小时)", "STRING", null),
DATEFORMAT(7, "formatDate", "日期时间格式化", "STRING", null),
HTTP_UTIL(8, "httpRequest", "HttpUtil", "JSON", null),
;
private Integer key;

View File

@@ -1,4 +1,7 @@
package com.pgmmers.radar.vo.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.Serializable;
import java.util.Date;
@@ -22,6 +25,10 @@ public class PreItemVO implements Serializable{
private String plugin;
private String reqType = "GET";
@JsonProperty
private JsonNode configJson;
private Integer status;
@@ -141,6 +148,22 @@ public class PreItemVO implements Serializable{
public void setSourceLabel(String sourceLabel) {
this.sourceLabel = sourceLabel;
}
public JsonNode getConfigJson() {
return configJson;
}
public void setConfigJson(JsonNode configJson) {
this.configJson = configJson;
}
public String getReqType() {
return reqType;
}
public void setReqType(String reqType) {
this.reqType = reqType;
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>radar</artifactId>
<groupId>com.pgmmers</groupId>
<version>1.0.1-SNAPSHOT</version>
<version>1.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>radar-dao</artifactId>
@@ -79,7 +79,7 @@
<dependency>
<groupId>com.pgmmers</groupId>
<artifactId>radar-commons</artifactId>
<version>0.0.1</version>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>

View File

@@ -49,6 +49,15 @@ public class PreItemPO {
@Column(name = "PLUGIN")
private String plugin;
@Column(name = "CONFIG_JSON")
private String configJson;
/**
* 请求方式
*/
@Column(name = "REQ_TYPE")
private String reqType;
@Column(name = "STATUS")
private Integer status;
@@ -194,6 +203,38 @@ public class PreItemPO {
this.plugin = plugin;
}
/**
* @return CONFIG_JSON
*/
public String getConfigJson() {
return configJson;
}
/**
* @param configJson
*/
public void setConfigJson(String configJson) {
this.configJson = configJson;
}
/**
* 获取请求方式
*
* @return REQ_TYPE - 请求方式
*/
public String getReqType() {
return reqType;
}
/**
* 设置请求方式
*
* @param reqType 请求方式
*/
public void setReqType(String reqType) {
this.reqType = reqType;
}
/**
* @return STATUS
*/

View File

@@ -13,6 +13,8 @@
<result column="LABEL" jdbcType="VARCHAR" property="label" />
<result column="ARGS" jdbcType="VARCHAR" property="args" />
<result column="PLUGIN" jdbcType="VARCHAR" property="plugin" />
<result column="CONFIG_JSON" jdbcType="VARCHAR" property="configJson" />
<result column="REQ_TYPE" jdbcType="VARCHAR" property="reqType" />
<result column="STATUS" jdbcType="INTEGER" property="status" />
<result column="CREATE_TIME" jdbcType="TIMESTAMP" property="createTime" />
<result column="UPDATE_TIME" jdbcType="TIMESTAMP" property="updateTime" />

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>radar</artifactId>
<groupId>com.pgmmers</groupId>
<version>1.0.1-SNAPSHOT</version>
<version>1.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -0,0 +1,25 @@
package com.pgmmers.radar.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
//ms
factory.setReadTimeout(5000);
factory.setConnectTimeout(5000);
return factory;
}
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>radar</artifactId>
<groupId>com.pgmmers</groupId>
<version>1.0.1-SNAPSHOT</version>
<version>1.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -61,5 +61,10 @@
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@@ -120,7 +120,7 @@ public class AntiFraudServiceImpl implements AntiFraudService {
jsonInfo.get(sourceField[1]).toString());
break;
case ALLINONE:
List<Object> values = new ArrayList<Object>();
List<Object> values = new ArrayList<>();
for (String field : sourceField) {
values.add(jsonInfo.get(field));
}
@@ -142,11 +142,16 @@ public class AntiFraudServiceImpl implements AntiFraudService {
millis = Long.parseLong(jsonInfo.get(sourceField[0]).toString());
transfer = pluginService.formatDate(millis, formatStr);
break;
case HTTP_UTIL:
String url = item.getArgs();
String reqType = item.getReqType();
String arg = jsonInfo.get(sourceField[0]).toString();
transfer = pluginService.httpRequest(url, reqType, arg);
break;
default:
}
result.put(item.getDestField(), transfer);
//result.put(plugin.getFieldName(), transfer);
}
return result;
}

View File

@@ -1,6 +1,7 @@
package com.pgmmers.radar.service.impl.engine;
import com.alibaba.fastjson.JSONObject;
import com.pgmmers.radar.enums.CombineType;
import com.pgmmers.radar.service.data.MobileInfoService;
import com.pgmmers.radar.service.engine.PluginService;
@@ -17,7 +18,9 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.PostConstruct;
import java.util.Calendar;
@@ -37,6 +40,9 @@ public class PluginServiceImpl implements PluginService {
@Autowired
private MobileInfoService mobileInfoService;
@Autowired
private RestTemplate restTemplate;
@PostConstruct
public void init() {
try {
@@ -53,14 +59,13 @@ public class PluginServiceImpl implements PluginService {
if (!Util.isIpAddress(ip)) {
return null;
}
;
try {
DataBlock block = ipSearcher.memorySearch(ip);
String[] detail = block.getRegion().split("\\|");
location = new Location();
location.setCountry(detail[0]);
location.setRegion(detail[1]);
location.setProvice(detail[2]);
location.setProvince(detail[2]);
location.setCity(detail[3]);
location.setAddress(detail[4]);
} catch (Exception e) {
@@ -72,7 +77,7 @@ public class PluginServiceImpl implements PluginService {
@Override
public Location gps2location(String lng, String lat) {
// TODO Auto-generated method stub
// TODO 可以参考 http://jwd.funnyapi.com/#/index , 最好是本地库。
return null;
}
@@ -111,7 +116,7 @@ public class PluginServiceImpl implements PluginService {
MobileInfoVO vo = mobileInfoService.getMobileInfoByMobile(mobile);
Location location = new Location();
if (vo != null) {
location.setProvice(vo.getProvince());
location.setProvince(vo.getProvince());
location.setCity(vo.getCity());
location.setCountry("中国");
}
@@ -131,4 +136,16 @@ public class PluginServiceImpl implements PluginService {
return dateStr;
}
@Override
public JSONObject httpRequest(String url, String reqType, String... args) {
HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(url, HttpMethod.valueOf(reqType), entity, JSONObject.class, args);
logger.info("http plugin:{}\n{}\n {}", url, args, responseEntity.toString());
if (responseEntity.getStatusCode() == HttpStatus.OK) {
return responseEntity.getBody();
}
return null;
}
}

View File

@@ -1,7 +1,6 @@
package com.pgmmers.radar.service.impl.model;
import com.alibaba.fastjson.JSON;
import com.pgmmers.radar.dal.bean.DataListQuery;
import com.pgmmers.radar.dal.bean.DataListRecordQuery;
import com.pgmmers.radar.dal.model.DataListDal;
@@ -279,4 +278,45 @@ public class DataListsServiceImpl implements DataListsService, SubscribeHandle {
Map<String, Object> listMap = dataListRecordCacheMap.get(modelId);
return listMap;
}
@Override
public CommonResult batchImportData(List<DataListsVO> list, Long modelId) {
CommonResult result = new CommonResult();
for (DataListsVO data : list) {
data.setStatus(1);
data.setName("");
data.setModelId(modelId);
int count = dataListDal.save(data);
if (count > 0) {
if(StringUtils.isEmpty(data.getName())){
data.setName("dataList_"+data.getId());
dataListDal.save(data);
}
// 通知更新
data.setOpt("new");
cacheService.publishDataList(data);
}
}
result.setSuccess(true);
result.setMsg("导入成功");
return result;
}
@Override
public CommonResult batchImportDataRecord(List<DataListRecordVO> list, Long dataListId) {
CommonResult result = new CommonResult();
for (DataListRecordVO dataListRecord : list) {
int count = dataListDal.saveRecord(dataListRecord);
if (count > 0) {
// 通知更新
DataListsVO dataListVO = dataListDal.get(dataListRecord.getDataListId());
dataListRecord.setModelId(dataListVO.getModelId());
dataListRecord.setOpt("update");
cacheService.publishDataListRecord(dataListRecord);
}
}
result.setSuccess(true);
result.setMsg("导入成功");
return result;
}
}

View File

@@ -85,20 +85,11 @@ public class PreItemServiceImpl implements PreItemService, SubscribeHandle {
return result;
}
}
// if (preItem.getId() == null) {
// FieldQuery query = new FieldQuery();
// query.setModelId(preItem.getModelId());
// query.setFieldName(fieldName);
// PageResult<FieldVO> page = fieldDal.query(query);
// if (page != null && page.getRowCount() > 0) {
// result.setMsg("字段名已定义");
// return result;
// }
// }
int count = preItemDal.save(preItem);
if (count > 0) {
if(StringUtils.isEmpty(preItem.getDestField())){
preItem.setDestField("preItem_"+preItem.getId());
preItem.setDestField("preItem_" + preItem.getId());
preItemDal.save(preItem);
}

View File

@@ -5,7 +5,7 @@
<parent>
<artifactId>radar</artifactId>
<groupId>com.pgmmers</groupId>
<version>1.0.1-SNAPSHOT</version>
<version>1.0.2-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@@ -1,5 +1,6 @@
package com.pgmmers.radar.service.engine;
import com.alibaba.fastjson.JSONObject;
import com.pgmmers.radar.service.engine.vo.Location;
import java.util.List;
@@ -51,5 +52,22 @@ public interface PluginService {
String getSensitiveTime(Long timeMills);
/**
* date format by format str, like yyyyMMdd.
* @param timeMills
* @param format
* @return
* @author feihu.wang
*/
String formatDate(Long timeMills, String format);
/**
* http util.
* @param url
* @param reqType
* @param args
* @return
* @author feihu.wang
*/
JSONObject httpRequest(String url, String reqType, String ...args);
}

View File

@@ -6,7 +6,7 @@ public class Location {
private String region = "";
private String provice = "";
private String province = "";
private String city = "";
@@ -28,12 +28,12 @@ public class Location {
this.region = region;
}
public String getProvice() {
return provice;
public String getProvince() {
return province;
}
public void setProvice(String provice) {
this.provice = provice;
public void setProvince(String province) {
this.province = province;
}
public String getCity() {

View File

@@ -48,4 +48,7 @@ public interface DataListsService {
Map<String, Object> getDataListMap(Long modelId);
CommonResult batchImportData(List<DataListsVO> list, Long modelId);
CommonResult batchImportDataRecord(List<DataListRecordVO> list, Long dataListId);
}

View File

@@ -1,10 +0,0 @@
-- developers of radar
CREATE TABLE `contribute_info` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NAME` varchar(30) NOT NULL COMMENT '功能名称',
`CONTENT` varchar(200) NOT NULL COMMENT '功能描叙',
`DEVELOPER` varchar(60) NOT NULL COMMENT '开发者',
`RELEASE_VERSION` varchar(30) DEFAULT NULL COMMENT '发布版本',
`CREATE_TIME` datetime DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

7
sql/radar-1.0.2.sql Normal file
View File

@@ -0,0 +1,7 @@
ALTER TABLE `engine_pre_item`
MODIFY COLUMN `ARGS` varchar(250) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT '' COMMENT '参数' AFTER `LABEL`;
ALTER TABLE `engine_pre_item`
ADD COLUMN `CONFIG_JSON` varchar(250) NULL COMMENT '响应字段配置信息' AFTER `PLUGIN`;
ALTER TABLE `engine_pre_item`
ADD COLUMN `REQ_TYPE` varchar(16) NULL COMMENT '请求方式' AFTER `CONFIG_JSON`;

View File

@@ -1 +1 @@
//TODO: 项目前后端分离,此目录用于存放前端代码
//项目前后端分离,此目录用于存放前端代码

View File

@@ -22,24 +22,31 @@ export default class AddPreItem extends React.Component{
sourceLabel:'',
plugin:'',
status:1,
args:''
args:'',
reqType:'GET',
configJson:''
}
}
handleChange=(e)=>{
console.log(e,'==')
var name = e.target.name;
var value = e.target.value;
var state = this.state;
state[name] = trim(value);
state[name] = typeof value==='number'?value: trim(value);
this.setState(state);
}
handleSelect=(name,value)=>{
var state = this.state;
if(name=='plugin'){
state['sourceField']='';
state['sourceLabel']='';
state['args']='';
state['args']='';
state['status']=1;
state['configJson']='';
}
state[name] = trim(value);
@@ -74,11 +81,16 @@ export default class AddPreItem extends React.Component{
plugin:'',
status:1,
args:'',
visible:true
reqType:'GET',
visible:true,
configJson:''
})
}
handleSubmit=(validated)=>{
if(typeof JSON.parse(this.state.configJson)!='object'){
return message.error('多文本框json格式不对');
}
if(!validated){
Modal.error({
title: '提交失败',
@@ -93,10 +105,11 @@ export default class AddPreItem extends React.Component{
param.sourceField=this.state.sourceField;
param.sourceLabel=this.state.sourceLabel;
param.plugin=this.state.plugin;
param.status=this.state.status;
param.args=this.state.args;
FetchUtil('/preitem/','PUT',JSON.stringify(param),
param.status=this.state.status;
param.reqType=this.state.reqType;
param.args=this.state.args;
param.configJson=JSON.parse(this.state.configJson);
FetchUtil('/preitem/','PUT', JSON.stringify(param),
(data) => {
if(data.success){
message.success('添加成功');
@@ -175,11 +188,15 @@ export default class AddPreItem extends React.Component{
} else if (this.state.plugin=='DATEFORMAT') {
validate.args.help='请输入日期格式化字符串';
isValidated=false;
} else if (this.state.plugin=='RESTUTIL') {
validate.args.help='请输入正确的 url';
isValidated=false;
}
}
const plugin=this.state.plugin;
let fieldArr=this.state.sourceField==''?[]:this.state.sourceField.split(',');
let fieldArr=this.state.sourceField==''?[]:this.state.sourceField.split(',');
console.log( this.props.plugins)
return (
<span>
<Button onClick={this.showModal} type="primary">新增</Button>
@@ -270,7 +287,43 @@ export default class AddPreItem extends React.Component{
</Tooltip>
</Col>
</Row>
</FormItem>
</FormItem>
<FormItem required={true} {...formItemLayout} label="请求信息" style={plugin=='HTTP_UTIL'?{}:{display:"none"}} help={validate.args.help} validateStatus={validate.args.status}>
<Row>
<Col span={20}>
<Radio.Group name="reqType" onChange={this.handleChange} value={this.state.reqType}>
<Radio value={'GET'}>GET</Radio>
<Radio disabled={true} value={'POST'}>POST</Radio>
</Radio.Group>
</Col>
<Col span={2} offset={1}>
<Tooltip placement="right" title={'请求方式: POST, GET'}>
<Icon style={{fontSize:16}} type="question-circle-o" />
</Tooltip>
</Col>
</Row>
<Row>
<Col span={20}>
<Input type="text" name="args" value={this.state.args} onChange={this.handleChange}/>
</Col>
<Col span={2} offset={1}>
<Tooltip placement="right" title={'Rest url, like http://xxx/getSth?id={1}'}>
<Icon style={{fontSize:16}} type="question-circle-o" />
</Tooltip>
</Col>
</Row>
<Row>
<Col span={20}>
<Input.TextArea name="configJson" value={this.state.configJson} onChange={(e)=>this.handleChange(e)} rows={4} placeholder="请输入响应结果字段描叙信息json数组" />
</Col>
<Col span={2} offset={1}>
<Tooltip placement="right" title={'响应字段元信息, like:[{"column":"country","title":"国家","type":"STRING"},{"column":"province","title":"省份","type":"STRING"}]'}>
<Icon style={{fontSize:16}} type="question-circle-o" />
</Tooltip>
</Col>
</Row>
</FormItem>
</Form>
</Modal>
</span>

View File

@@ -23,7 +23,8 @@ export default class EditPreItem extends React.Component{
plugin:'',
status:1,
args:'',
reqType:'GET',
configJson:'',
preItem:null
}
@@ -40,8 +41,11 @@ export default class EditPreItem extends React.Component{
sourceField:preItem.sourceField,
sourceLabel:preItem.sourceLabel,
plugin:preItem.plugin,
status:preItem.status,
args:preItem.args
status:preItem.status,
reqType:preItem.reqType,
args:preItem.args,
configJson:JSON.stringify(preItem.configJson)
});
});
}
@@ -50,7 +54,7 @@ export default class EditPreItem extends React.Component{
var name = e.target.name;
var value = e.target.value;
var state = this.state;
state[name] = trim(value);
state[name] = typeof value==='number'?value: trim(value);
this.setState(state);
}
@@ -59,7 +63,8 @@ export default class EditPreItem extends React.Component{
if(name=='plugin'){
state['sourceField']='';
state['sourceLabel']='';
state['args']='';
state['args']='';
state['configJson']='';
}
state[name] = trim(value);
@@ -93,6 +98,9 @@ export default class EditPreItem extends React.Component{
}
handleSubmit=(validated)=>{
if(typeof JSON.parse(this.state.configJson)!='object'){
return message.error('多文本框json格式不对');
}
if(!validated){
Modal.error({
title: '提交失败',
@@ -109,7 +117,9 @@ export default class EditPreItem extends React.Component{
param.sourceLabel=this.state.sourceLabel;
param.plugin=this.state.plugin;
param.status=this.state.status;
param.args=this.state.args;
param.args=this.state.args;
param.reqType=this.state.reqType;
param.configJson=JSON.parse(this.state.configJson);
FetchUtil('/preitem/','PUT',JSON.stringify(param),
(data) => {
@@ -270,7 +280,45 @@ export default class EditPreItem extends React.Component{
</Tooltip>
</Col>
</Row>
</FormItem>
</FormItem>
<FormItem required={true} {...formItemLayout} label="请求信息" style={plugin=='HTTP_UTIL'?{}:{display:"none"}} help={validate.args.help} validateStatus={validate.args.status}>
<Row>
<Col span={20}>
<Radio.Group name="reqType" onChange={this.handleChange} value={this.state.reqType}>
<Radio value={'GET'}>GET</Radio>
<Radio disabled={true} value={'POST'}>POST</Radio>
</Radio.Group>
</Col>
<Col span={2} offset={1}>
<Tooltip placement="right" title={'请求方式: POST, GET'}>
<Icon style={{fontSize:16}} type="question-circle-o" />
</Tooltip>
</Col>
</Row>
<Row>
<Col span={20}>
<Input type="text" name="args" value={this.state.args} onChange={this.handleChange}/>
</Col>
<Col span={2} offset={1}>
<Tooltip placement="right" title={'Rest url, like http://xxx/getSth?id={1}'}>
<Icon style={{fontSize:16}} type="question-circle-o" />
</Tooltip>
</Col>
</Row>
<Row>
<Col span={20}>
<Input.TextArea name="configJson" value={this.state.configJson} onChange={(e)=>this.handleChange(e)} rows={4} placeholder="请输入响应结果字段描叙信息json数组" />
</Col>
<Col span={2} offset={1}>
<Tooltip placement="right" title={'响应字段元信息like:[{"column":"country","title":"国家","type":"STRING"},{"column":"province","title":"省份","type":"STRING"}]'}>
<Icon style={{fontSize:16}} type="question-circle-o" />
</Tooltip>
</Col>
</Row>
</FormItem>
</Form>
</Modal>
</span>

View File

@@ -26,7 +26,7 @@ const devWebpackConfig = merge(baseWebpackConfig, {
disableHostCheck: true, // 新增该配置项
proxy: [{
context: ["/services/v1/"],
target: "http://104.128.89.231:8080",
target: "http://10.50.3.218:8080",
changeOrigin: true,
secure: false,
onProxyRes: function (proxyRes, req, res) { //