Commit 6d70a0dc authored by 黎博's avatar 黎博

Merge branch 'master' into auto

# Conflicts:
#	pom.xml
parents 992765bf 3132ba91
......@@ -116,13 +116,6 @@
<version>4.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.testng/testng -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>7.3.0</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
......
......@@ -28,7 +28,7 @@ public class HttpLogAspect {
private static final Logger logger = LoggerFactory.getLogger(HttpLogAspect.class);
@Pointcut("execution(public * cn.qg.holmes.controller..*.*(..))")
@Pointcut("execution(public * cn.qg.holmes.controller.mock..*(..))")
public void httpRequestLog() {}
/**
......
package cn.qg.holmes.config;
import cn.qg.holmes.interceptor.RuleEngineInterceptor;
import cn.qg.holmes.interceptor.YeebaoInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
......@@ -17,8 +18,14 @@ public class InterceptorConfig implements WebMvcConfigurer {
return new YeebaoInterceptor();
}
@Bean
public RuleEngineInterceptor ruleEngineInterceptor() {
return new RuleEngineInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(yeebaoInterceptor()).addPathPatterns("/mock/tzt-api/**", "/mock/balance-board/**");
registry.addInterceptor(ruleEngineInterceptor()).addPathPatterns("/rule_engine/**");
}
}
package cn.qg.holmes.controller.jira;
import cn.qg.holmes.common.JsonResult;
import cn.qg.holmes.entity.jira.DingRobot;
import cn.qg.holmes.service.jira.DingRobotService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/jira")
public class JiraWebhookController {
@Autowired
DingRobotService dingRobotService;
/**
* jira webhook
* @param request
*/
@PostMapping("/webhook")
public void jiraWebhook(HttpServletRequest request) {
try {
BufferedReader br = request.getReader();
StringBuilder jiraData = new StringBuilder();
String str = "";
while((str = br.readLine()) != null){
jiraData.append(str);
}
br.close();
dingRobotService.sendMsgToDing(String.valueOf(jiraData));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 项目机器人列表
* @param pageNum 第几页
* @param pageSize 每页多少个
* @return
*/
@GetMapping("/list/robot")
public JsonResult getProjectRobotList(Integer pageNum, Integer pageSize) {
IPage<DingRobot> page = new Page<>(pageNum, pageSize);
IPage<DingRobot> projectRobotIPage = dingRobotService.page(page);
Map<String, Object> map = new HashMap<>();
map.put("total", projectRobotIPage.getTotal());
map.put("list", projectRobotIPage.getRecords());
return JsonResult.buildSuccessResult(map);
}
/**
* 新增项目机器人
* @param dingRobot 项目机器人实体
* @return
*/
@PostMapping("/add/robot")
public JsonResult addProjectRobot(@RequestBody DingRobot dingRobot) {
if (dingRobot.getProjectName() == null) {
return JsonResult.buildErrorStateResult("项目名称不能为空!", false);
}
if (dingRobot.getDingUrl() == null) {
return JsonResult.buildErrorStateResult("钉钉url不能为空!", false);
}
return JsonResult.buildSuccessResult(dingRobotService.save(dingRobot));
}
/**
* 修改项目机器人
* @param dingRobot 项目机器人实体
* @return
*/
@PostMapping("/modify/robot")
public JsonResult editProjectRobot(@RequestBody DingRobot dingRobot) {
if (dingRobot.getId() == null) {
return JsonResult.buildErrorStateResult("id不能为空!", false);
}
if (dingRobot.getProjectName() == null) {
return JsonResult.buildErrorStateResult("项目名称不能为空!", false);
}
if (dingRobot.getDingUrl() == null) {
return JsonResult.buildErrorStateResult("钉钉url不能为空!", false);
}
return JsonResult.buildSuccessResult(dingRobotService.updateById(dingRobot));
}
/**
* 删除项目机器人
* @param projectRobotId 项目机器人实体id
* @return
*/
@GetMapping("/delete/robot")
public JsonResult deleteProjectRobot(Integer projectRobotId) {
if (dingRobotService.getById(projectRobotId) == null) {
return JsonResult.buildErrorStateResult("项目机器人不存在!", false);
}
return JsonResult.buildSuccessResult(dingRobotService.removeById(projectRobotId));
}
}
......@@ -43,7 +43,7 @@ public class MockController {
IPage<Mock> page = new Page<>(pageNum, pageSize);
IPage<Mock> pageEntity;
if (module != null) {
QueryWrapper queryWrapper = new QueryWrapper();
QueryWrapper<Mock> queryWrapper = new QueryWrapper();
queryWrapper.eq("module", module);
pageEntity = mockService.page(page, queryWrapper);
} else {
......
package cn.qg.holmes.entity.jira;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
@TableName(value = "ding_robot")
public class DingRobot {
@TableId(type = IdType.AUTO)
private Integer id;
private String projectName;
private String dingUrl;
private String creator;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}
package cn.qg.holmes.interceptor;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class InterceptorUtils {
/**
* 修改返回响应
* @param response HttpServletResponse
* @param result 返回的json或字符串
*/
public static void constructResponse(HttpServletResponse response, String result) {
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
// response.setContentType("application/json; charset=utf-8");
try {
writer = response.getWriter();
writer.print(result);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
}
/**
* 修改返回响应
* @param response HttpServletResponse
* @param result 返回的json或字符串
* @param contentType content-type
*/
public static void constructResponse(HttpServletResponse response, String result, String contentType) {
PrintWriter writer = null;
response.setCharacterEncoding("UTF-8");
response.setContentType(contentType);
try {
writer = response.getWriter();
writer.print(result);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
}
/**
* 将HttpServletRequest的parameterMap由Map<String, String[]>转换成Map<String, Object>
* @param parameterMap request.getParameterMap()
* @return
*/
public static Map<String, Object> convertParameterMap(Map<String, String[]> parameterMap) {
Map<String, Object> map = new HashMap<>();
for (Map.Entry<String, String[]> entry: parameterMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue()[0];
map.put(key, value);
}
return map;
}
/**
* 解析从数据库获取的响应,赋对应的值
* @param requestMap 请求Map
* @param responseMap 响应Map
* @return
*/
public static Map<String, Object> disposeResponseMap(Map<String, Object> requestMap, Map<String, Object> responseMap) {
for (Map.Entry<String, Object> entry: responseMap.entrySet()) {
if (entry.getValue() instanceof List) {
List<Map> list = (List) entry.getValue();
for (Map<String, Object> map: list) {
for (Map.Entry<String, Object> entry2: map.entrySet()) {
String value2 = entry2.getValue().toString();
if (value2.startsWith("$request")) {
entry2.setValue(requestMap.get(value2.split("\\.")[1]));
}
}
}
} else if (entry.getValue() instanceof String) {
String value = entry.getValue().toString();
if (value.startsWith("$request")) {
entry.setValue(requestMap.get(value.split("\\.")[1]));
}
if (value.equals("true")) {
entry.setValue(true);
}
if (value.equals("false")) {
entry.setValue(false);
}
}
}
return responseMap;
}
}
package cn.qg.holmes.interceptor;
import cn.qg.holmes.entity.mock.Mock;
import cn.qg.holmes.mapper.mock.MockMapper;
import cn.qg.holmes.utils.HttpClientUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* 风控相关接口拦截器
* @author libo
*/
@Slf4j
public class RuleEngineInterceptor implements HandlerInterceptor {
@Autowired
MockMapper mockMapper;
@Value("${early.settle.channel}")
private String earlySettleChannel;
public Map<String, Object> convertParameterMap(Map<String, String[]> parameterMap) {
Map<String, Object> map = new HashMap<>();
for (Map.Entry<String, String[]> entry: parameterMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue()[0];
map.put(key, value);
}
return map;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String uri = request.getRequestURI();
Map<String, String[]> parameterMap = request.getParameterMap();
Map<String, Object> requestMap = convertParameterMap(parameterMap);
QueryWrapper<Mock> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("url", uri);
Mock mock = mockMapper.selectOne(queryWrapper);
String mockData = null;
if (mock.getFlag() == 0) {
mockData = mock.getFail();
}
if (mock.getFlag() == 1) {
mockData = mock.getSuccess();
}
if (uri.equals("/rule_engine/middle_office/audit")) {
Map<String, Object> auditMap = JSON.parseObject(mockData, Map.class);
Map<String, Object> responseMap = handleRiskAudit(requestMap, auditMap);
InterceptorUtils.constructResponse(response, JSON.toJSONString(responseMap), "application/json; charset=utf-8");
return false;
}
InterceptorUtils.constructResponse(response, mockData, "application/json; charset=utf-8");
return true;
}
/**
* 处理风控审核参数
* @param requestMap HttpServletRequest请求参数Map
* @return
*/
public Map<String, Object> handleRiskAudit(Map<String, Object> requestMap, Map<String, Object> auditData) {
Map<String, Object> bodyMap = new HashMap<>();
Map<String, Object> resultMap = new HashMap<>();
String bizType = requestMap.get("bizType").toString();
String bizChannel = requestMap.get("bizChannel").toString();
String uuid = requestMap.get("uuid").toString();
String bizNo = requestMap.get("bizNo").toString();
String sceneId = requestMap.get("sceneId").toString();
resultMap.put("code", 0);
resultMap.put("msg", "success");
bodyMap.put("msg", "success");
bodyMap.put("fundRate", null);
bodyMap.put("secondaryValidation", "-1");
bodyMap.put("amountRate", null);
bodyMap.put("isWhiteBlackListHit", null);
bodyMap.put("openingValidity", "15");
bodyMap.put("creditLevel", null);
bodyMap.put("isFuseModuleHit", null);
bodyMap.put("callbackUrl", null);
bodyMap.put("amountTermLimits", null);
bodyMap.put("bizType", bizType);
bodyMap.put("bizChannel", bizChannel);
bodyMap.put("uuid", uuid);
bodyMap.put("bizNo", bizNo);
bodyMap.put("sceneId", sceneId);
bodyMap.put("amount", null);
bodyMap.put("xycreditScore", null);
bodyMap.put("exportVccTag", null);
bodyMap.put("term", null);
bodyMap.put("validity", "30");
bodyMap.put("deadLine", "4102415999000");
bodyMap.put("financeProducts", null);
bodyMap.put("otherInformation", null);
bodyMap.put("extData", null);
bodyMap.put("success", true);
bodyMap.put("refuseReason", null);
bodyMap.put("allowInstalment", null);
bodyMap.put("allowInstalmentTerms", null);
bodyMap.put("quotaPaymentAmount", null);
bodyMap.put("auditResult", true);
// 授信额度审核
if (sceneId.equals("0")) {
// vcc
String callbackUrl = requestMap.get("callbackUrl").toString();
if (callbackUrl.contains("talos")) {
vccRiskAuthAmountCompletion(callbackUrl, bizChannel, uuid, bizNo, (Integer) auditData.get("vccAuditAmount"), (Boolean) auditData.get("vccAuditResult"));
}
// 一单一审现金贷
if (bizType.equals("0")) {
}
}
// KA准入审核, sceneId=2
if (sceneId.equals("2")) {
bodyMap.put("auditResult", auditData.get("KaAuditResult"));
}
// vcc账户冻结审核
if (sceneId.equals("8")) {
}
// vcc账户解冻审核
if (sceneId.equals("9")) {
}
// vcc账单分期审核, sceneId=11
if (bizType.equals("8") && sceneId.equals("11")) {
bodyMap.put("allowInstalment", 1);
bodyMap.put("allowInstalmentTerms", "3,6,9,12");
}
// vcc支付限额审核, sceneId=12
if (bizType.equals("8") && sceneId.equals("12")) {
bodyMap.put("auditResult", auditData.get("vccQuotaPayAuditResult")); // true-允许使用额度支付, false-不允许使用额度支付
bodyMap.put("quotaPaymentAmount", auditData.get("vccQuotaPaymentAmount").toString()); // quotaPaymentAmount
}
// 提前结清审核,如果渠道不在apollo配置里,则审核拒绝
if (sceneId.equals("14")) {
String[] earlySettleChannelArray = earlySettleChannel.split(",");
if (!Arrays.asList(earlySettleChannelArray).contains(bizChannel)) {
bodyMap.put("auditResult", false);
}
}
resultMap.put("body", bodyMap);
return resultMap;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
log.info("本次请求返回响应:{}", response);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception {
}
/**
* vcc风控授信回调
* @param callbackUrl 回调url
* @param bizChannel 渠道号
* @param uuid uuid
* @param riskNo 授信单号
* @param amount 授信金额
* @param auditResult 授信结果,true/false
*/
public static void vccRiskAuthAmountCompletion(String callbackUrl,String bizChannel, String uuid, String riskNo, Integer amount, boolean auditResult) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + 15);
long openingDeadLine = calendar.getTimeInMillis();
Calendar calendar2 = Calendar.getInstance();
calendar2.add(Calendar.YEAR, 1);
Long deadLine = calendar2.getTimeInMillis();
Map<String, Object> params = new HashMap<>();
params.put("amount", amount);
params.put("auditResult", auditResult);
params.put("bizChannel", bizChannel);
params.put("bizNo", riskNo);
params.put("code", 0);
params.put("deadLine", deadLine);
params.put("openingDeadLine", openingDeadLine); // 开户失败有效期
params.put("success", true);
params.put("uuid", uuid);
params.put("sceneId", 0);
params.put("allowInstalment", 1); // 1-允许分期,0-不允许分期
params.put("allowInstalmentTerms", "3,6,9,12"); // 允许分期的期数
Map<String, Object> headers = new HashMap<>();
headers.put("Content-Type", "application/x-www-form-urlencoded");
JSONObject result = HttpClientUtils.doPost(callbackUrl, params, headers);
log.info("vcc风控授信回调参数:{}", params);
log.info("vcc风控授信回调结果:{}", result);
}
public static void quotaAuthAmountAuditNotify(String callbackUrl, String uuid, Integer bizChannel, Integer fundId, String bizNo, Integer bizType, Integer creditAmount, Integer term, boolean auditResult) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + 30);
Long deadLine = calendar.getTimeInMillis();
Map<String, Object> headers = new HashMap<>();
headers.put("Content-Type", "application/x-www-form-urlencoded");
Map<String, Object> params = new HashMap<>();
params.put("code", 0);
params.put("msg", "success");
params.put("bizChannel", bizChannel); // 渠道号
params.put("uuid", uuid);
params.put("bizNo", bizNo);
params.put("bizType", bizType); // 业务类型: 0-现金分期一单一审,……
params.put("auditResult", auditResult);
params.put("amount", creditAmount);
params.put("deadLine", deadLine);
params.put("extData", "");
params.put("otherInformation", "");
JSONArray financeProducts = createFinanceProducts(fundId, term);
params.put("financeProducts", financeProducts);
HttpClientUtils.doPost(callbackUrl, params, headers);
log.info("现金分期风控授信回调:{}", params);
}
public static JSONArray createFinanceProducts(Integer fundId, Integer term) {
JSONArray financeProducts = new JSONArray();
JSONObject financeProductsObject = new JSONObject();
JSONArray terms = new JSONArray();
financeProductsObject.put("max", 10000);
financeProductsObject.put("min", 10000);
JSONObject firstTerm = new JSONObject();
firstTerm.put("term", term);
JSONArray fundInfoList = new JSONArray();
JSONObject fundInfoObject = new JSONObject();
fundInfoObject.put("fundId", fundId);
fundInfoObject.put("rate", 0);
fundInfoObject.put("rateType", 1);
fundInfoObject.put("priority", 1);
fundInfoObject.put("feeType", 1);
// 如果是云南信托,需要该参数
if (fundId == 1040) {
fundInfoObject.put("fundProductId", 1061);
}
// 平顶山银行
if (fundId == 1030) {
fundInfoObject.put("fundProductId", 1060);
}
fundInfoList.add(fundInfoObject);
firstTerm.put("fundInfo", fundInfoList);
terms.add(firstTerm);
financeProductsObject.put("terms", terms);
financeProducts.add(financeProductsObject);
return financeProducts;
}
}
package cn.qg.holmes.mapper.jira;
import cn.qg.holmes.entity.jira.DingRobot;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface DingRobotMapper extends BaseMapper<DingRobot> {
}
package cn.qg.holmes.service.jira;
import cn.qg.holmes.entity.jira.DingRobot;
import com.baomidou.mybatisplus.extension.service.IService;
public interface DingRobotService extends IService<DingRobot> {
Boolean sendMsgToDing(String jiraData);
}
package cn.qg.holmes.service.jira.impl;
import cn.qg.holmes.entity.jira.DingRobot;
import cn.qg.holmes.mapper.jira.DingRobotMapper;
import cn.qg.holmes.service.jira.DingRobotService;
import cn.qg.holmes.utils.DingdingUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jayway.jsonpath.JsonPath;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@Slf4j
public class DingRobotServiceImpl extends ServiceImpl<DingRobotMapper, DingRobot> implements DingRobotService {
@Autowired
DingRobotMapper dingRobotMapper;
@Override
public Boolean sendMsgToDing(String jiraData) {
log.info("收到jira bug提交:{}", jiraData);
String webhookEvent = JsonPath.read(jiraData, "$.webhookEvent");
if (StringUtils.equals(webhookEvent, "jira:issue_created")) {
String creator = JsonPath.read(jiraData, "$.issue.fields.creator.displayName");
String assignee = JsonPath.read(jiraData, "$.issue.fields.assignee.displayName");
String key = JsonPath.read(jiraData, "$.issue.key");
String summary = JsonPath.read(jiraData, "$.issue.fields.summary");
String priority = JsonPath.read(jiraData, "$.issue.fields.priority.name");
String module = JsonPath.read(jiraData, "$.issue.fields.components[0].name");
String robotUrl = null;
List<DingRobot> dingRobots = dingRobotMapper.selectList(null);
for (DingRobot dingRobot : dingRobots) {
String projectName = "【" + dingRobot.getProjectName() + "】";
if (summary.contains(projectName)) {
robotUrl = dingRobot.getDingUrl();
break;
}
}
if (robotUrl != null) {
String markdownMsg = DingdingUtils.buildMarkdownMsg(key, summary, creator, assignee, priority, module);
return DingdingUtils.sendToDingding(markdownMsg, robotUrl);
}
}
return false;
}
}
package cn.qg.holmes.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class DingdingUtils {
public static boolean sendToDingding(String jsonString, String webhook) {
Map<String, Object> headers = new HashMap<>();
headers.put("Content-Type", "application/json; charset=utf-8");
JSONObject result = HttpClientUtils.doPostJson(webhook, jsonString, headers);
log.info("发送给钉钉: {}, 内容:{}, 钉钉返回结果:{}", webhook, jsonString, result);
return result.get("errmsg").equals("ok");
}
public static String buildMarkdownMsg(String key, String summary, String creator, String assignee, String priority, String module) {
Map<String, Object> markdown = new HashMap<>();
Map<String, String> content = new HashMap<>();
markdown.put("msgtype", "markdown");
String title = creator + "提交了BUG:" + key;
String issueUrl = "http://jira2.quantgroup.cn/browse/" + key;
content.put("title", title);
content.put("text", "### " + title + "\n"
+ "#### 概要:[" + summary + "](" + issueUrl + ")"+ "\n"
+ "- 优先级:" + priority + "\n"
+ "- 模块:" + module + "\n"
+ "- 经办人:" + assignee);
markdown.put("markdown", content);
return JSON.toJSONString(markdown);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment