一. 项目背景:
对于原来提供给外部公司调用的接口有一个默认的接口文档(标注了默认的必填字段), 提供一个接口可配置的界面, 可以将有些非必填的值设置为必填, 还有给原来必填字段默认值或者根据其他字段的值设置当前值的赋值规则. 总结来说,有如下三条规则:
a.可以将原来接口文档里的非必填字段改成必填字段,
b.修改必填字段的默认值(外部调用不用再传此字段,系统自动按配置默认)
c.修改必填字段的默认值,根据配置的规则,根据其他字段替换掉接口字段中的值
二. 项目设计:
1.前端回显原来默认接口文档, 后端保存初始化接口文档json 格式,前端解析成页面
2.后端保存前端设置的规则并存到DB, 设计三张表: 接口初始化json存在常量表pic_b_constant, 接口配置表pic_b_interface_config, 接口配置规则表 pic_b_interface_config_template . 其中pic_b_constant存初始化接口json 文件(可以当成系统常量表使用), pic_b_interface_config表存了前端封装的全量json 信息; 接口配置规则表则是解析了前端传来的json ,保存接口对应的每条规则.
3.在管理后台产品经理可以对接口配置规则(未配置规则则按原来默认HTML样式展示)
4.代码中新建自定义注解,加到需要应用的方法上面
5.再环绕通知里面通过注解判断是否走规则. 若进入规则则按规则根据接口入参分别增加必填校验,默认值和应用规则(这里面要用到java 的反射机制)
三. 最终效果:
注:
①.因为接口入参里面嵌套了多层对象.,我们现在仅考虑到里面第二层,在注入参数值的时候要注意getDeclaredFields()和 getFields()的区别.
②在赋值的时候要根据入参类型进行赋值,不然会出现类转换异常
③处理入参为空,但是要赋默认值或者应用规则的情况
四. 相关代码如下:
- 自定义注解
import java.lang.annotation.*;
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoParamRule {
String type() default "";
}
- 应用接口上面加注解
@AutoParamRule(type = "contImp")
- 切面
package com.riskeys.pic.policyservice.aspect;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.riskeys.common.base.exception.BizException;
import com.riskeys.common.util.StringUtil;
import com.riskeys.pic.config.annotation.AutoParamRule;
import com.riskeys.pic.config.base.PicBaseRequestDTO;
import com.riskeys.pic.config.dto.newcont.apply.ApplicantInfoDTO;
import com.riskeys.pic.config.dto.newcont.apply.ApplyNewContRequestDTO;
import com.riskeys.pic.config.dto.newcont.apply.InsuredInfoDTO;
import com.riskeys.pic.config.dto.newcont.apply.PayReceivedDTO;
import com.riskeys.pic.policyservice.dao.primary.PicBInterfaceConfigMapper;
import com.riskeys.pic.policyservice.dao.primary.PicBInterfaceConfigTemplateMapper;
import com.riskeys.pic.policyservice.model.bean.PicBInterfaceConfigBean;
import com.riskeys.pic.policyservice.model.bean.PicBInterfaceConfigTemplateBean;
import com.riskeys.pic.policyservice.model.interfaceConfig.FieldRules;
import com.riskeys.pic.policyservice.util.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @ClassName AutoParamRuleAspect
* @Description
* @Author Ken
* @Date 2023/2/22 9:48
* @Version V1.0.1
*/
@Order(1)
@Component
@Slf4j
@Aspect
public class AutoParamRuleAspect {
@Resource
private PicBInterfaceConfigMapper picBInterfaceConfigMapper;
@Resource
private PicBInterfaceConfigTemplateMapper picBInterfaceConfigTemplateMapper;
@Pointcut("@annotation(com.riskeys.pic.config.annotation.AutoParamRule)")
public void serviceAspect() {
}
/**
* @return java.lang.Object
* @Title: 环绕通知
* @Author: ken
* @Description:
* @Date: 2023/3/16 15:37
* @Param: [pjp, autoParamRule
**/
@Around("serviceAspect() && @annotation(autoParamRule)")
public Object doAround(ProceedingJoinPoint pjp, AutoParamRule autoParamRule) throws Throwable {
//获取所有参数
Object[] args = pjp.getArgs();
log.info("[AutoParamRuleAspect --> around begin]- args[0]:{}", JSONObject.toJSONString(args[0]));
String type = autoParamRule.type();
if (type.equals("contImp")) {
Object object = args[0];
PicBaseRequestDTO picBaseRequestDTO = (PicBaseRequestDTO) object;
// PicBaseRequestDTO PicBaseRequestDTO = JSONObject.parseObject(object.toString(), PicBaseRequestDTO.class);
log.info("[AutoParamRuleAspect --> doAround]- picBaseRequestDTO:{}", JSONObject.toJSONString(picBaseRequestDTO));
ApplyNewContRequestDTO applyNewContRequestDTO = JSON.parseObject(JSON.toJSONString(picBaseRequestDTO.getBody()), ApplyNewContRequestDTO.class);
if (Objects.isNull(applyNewContRequestDTO)) {
log.info("[AutoParamRuleAspect --> doAround]- applyNewContRequestDTO is null");
return pjp.proceed(args);
}
ApplicantInfoDTO applicantInfoDTO = applyNewContRequestDTO.getApplicant();
List<InsuredInfoDTO> insureds = applyNewContRequestDTO.getInsureds();
PayReceivedDTO payReceivedDTO = applyNewContRequestDTO.getPayInfo();
//JSONObject extendsInfo = new JSONObject(applyNewContRequestDTO.getExtendInfo());
HashMap<String, Object> extendInfo = applyNewContRequestDTO.getExtendInfo();
//查询出所有必填字段和规则
String sourceCode = picBaseRequestDTO.getHeader().getSourceCode();
QueryWrapper<PicBInterfaceConfigBean> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("source_code", sourceCode);
queryWrapper.eq("is_delete", 0);
List<PicBInterfaceConfigBean> picBInterfaceConfigBeanList = picBInterfaceConfigMapper.selectList(queryWrapper);
if (CollectionUtils.isEmpty(picBInterfaceConfigBeanList)) {
log.info("[AutoParamRuleAspect --> doAround]- picBInterfaceConfigBeanList is null");
return pjp.proceed(args);
}
PicBInterfaceConfigBean picBInterfaceConfigBean = picBInterfaceConfigBeanList.get(0);
Integer sid = picBInterfaceConfigBean.getSid();
QueryWrapper<PicBInterfaceConfigTemplateBean> queryWrappers = new QueryWrapper<>();
queryWrappers.eq("interface_id", sid);
queryWrappers.eq("is_delete", 0);
List<PicBInterfaceConfigTemplateBean> picBInterfaceConfigTemplateBeanList = picBInterfaceConfigTemplateMapper.selectList(queryWrappers);
if (CollectionUtils.isEmpty(picBInterfaceConfigTemplateBeanList)) {
log.info("[AutoParamRuleAspect --> doAround]- picBInterfaceConfigTemplateBeanList is null");
return pjp.proceed(args);
}
ApplyNewContRequestDTO applyNewContRequestDTOs = new ApplyNewContRequestDTO();
ApplicantInfoDTO applicantInfoDTOs = new ApplicantInfoDTO();
List<InsuredInfoDTO> insuredInfoDTOs = Lists.newArrayList();
//若传入 insureds 为空时会用到
InsuredInfoDTO insured = new InsuredInfoDTO();
PayReceivedDTO payReceivedDTOs = new PayReceivedDTO();
HashMap<String, Object> extendInfos = Maps.newHashMap();
//先校验必填字段 Check required fields
List<PicBInterfaceConfigTemplateBean> addRequiredFieldList = picBInterfaceConfigTemplateBeanList.stream()
.filter(p -> p.getTemplateType().equals(3)).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(addRequiredFieldList)) {
for (PicBInterfaceConfigTemplateBean addRequiredField : addRequiredFieldList) {
String parentField = addRequiredField.getInterfaceParentField();
String currField = addRequiredField.getInterfaceField();
if ("baseInfo".equals(parentField)) {
String fieldValue = String.valueOf(getFieldValueByName(applyNewContRequestDTO, currField));
if(Objects.isNull(applyNewContRequestDTO)){
throw new BizException("基本信息为空(基本信息下有必填字段)");
}
checkRequiredFields(parentField, currField, fieldValue);
} else if ("applicant".equals(parentField)) {
String fieldValue = String.valueOf(getFieldValueByName(applicantInfoDTO, currField));
if(Objects.isNull(applicantInfoDTO)){
throw new BizException("投保人信息为空(投保人信息下有必填字段)");
}
checkRequiredFields(parentField, currField, fieldValue);
} else if ("insureds".equals(parentField)) {
if (!CollectionUtils.isEmpty(insureds)) {
for (InsuredInfoDTO insuredInfoDTO : insureds) {
String fieldValue = String.valueOf(getFieldValueByName(insuredInfoDTO, currField));
if(Objects.isNull(insuredInfoDTO)){
throw new BizException("被保人信息为空(被保人信息下有必填字段)");
}
checkRequiredFields(parentField, currField, fieldValue);
}
}
} else if ("payInfo".equals(parentField)) {
String fieldValue = String.valueOf(getFieldValueByName(payReceivedDTO, currField));
if(Objects.isNull(payReceivedDTO)){
throw new BizException("支付信息为空(支付信息下有必填字段)");
}
checkRequiredFields(parentField, currField, fieldValue);
} else if ("extendInfo".equals(parentField)) {
if(CollectionUtils.isEmpty(extendInfo)){
throw new BizException("扩展信息为空(扩展信息下有必填字段)");
}
String fieldValue = String.valueOf(extendInfo.get(currField));
checkRequiredFields(parentField, currField, fieldValue);
} else {
log.info("[AutoParamRuleAspect --> doAround]- error parentField: {} ", parentField);
}
}
}
//校验规则: 1: 设置默认值
List<PicBInterfaceConfigTemplateBean> requiredDefaultValueFieldList = picBInterfaceConfigTemplateBeanList.stream()
.filter(p -> p.getTemplateType().equals(1)).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(requiredDefaultValueFieldList)) {
for (PicBInterfaceConfigTemplateBean addRequiredField : requiredDefaultValueFieldList) {
String parentField = addRequiredField.getInterfaceParentField();
String currField = addRequiredField.getInterfaceField();
String defaultValue = addRequiredField.getDefaultValue();
if ("baseInfo".equals(parentField)) {
// 获取该类的成员变量
Field f = applyNewContRequestDTOs.getClass().getDeclaredField(currField);
// 取消语言访问检查
f.setAccessible(Boolean.TRUE);
String fieldType = f.getType().getTypeName();
// 给变量赋值 (需判断传入参数是否为空)
if(Objects.isNull(applyNewContRequestDTO)){
f.set(applyNewContRequestDTOs, ObjectUtils.convertAttributeValue(fieldType, defaultValue));
}else{
f.set(applyNewContRequestDTO, ObjectUtils.convertAttributeValue(fieldType, defaultValue));
}
} else if ("applicant".equals(parentField)) {
Field f = getAllField(applicantInfoDTOs.getClass(), currField);
f.setAccessible(Boolean.TRUE);
String fieldType = f.getType().getTypeName();
// 给变量赋值 (需判断传入参数是否为空)
if(Objects.isNull(applicantInfoDTO)){
f.set(applicantInfoDTOs, ObjectUtils.convertAttributeValue(fieldType, defaultValue));
}else{
f.set(applicantInfoDTO, ObjectUtils.convertAttributeValue(fieldType, defaultValue));
}
} else if ("insureds".equals(parentField)) {
if (!CollectionUtils.isEmpty(insureds)) {
for (InsuredInfoDTO insuredInfoDTO : insureds) {
Field f = getAllField(insuredInfoDTO.getClass(), currField);
f.setAccessible(Boolean.TRUE);
String fieldType = f.getType().getTypeName();
f.set(insuredInfoDTO, ObjectUtils.convertAttributeValue(fieldType, defaultValue));
}
}else{
Field f = getAllField(insured.getClass(), currField);
f.setAccessible(Boolean.TRUE);
String fieldType = f.getType().getTypeName();
f.set(insured, ObjectUtils.convertAttributeValue(fieldType, defaultValue));
}
} else if ("payInfo".equals(parentField)) {
Field f = payReceivedDTOs.getClass().getDeclaredField(currField);
f.setAccessible(Boolean.TRUE);
String fieldType = f.getType().getTypeName();
// 给变量赋值 (需判断传入参数是否为空)
if(Objects.isNull(payReceivedDTO)){
f.set(payReceivedDTOs, ObjectUtils.convertAttributeValue(fieldType, defaultValue));
}else{
f.set(payReceivedDTO, ObjectUtils.convertAttributeValue(fieldType, defaultValue));
}
} else if ("extendInfo".equals(parentField)) {
if(Objects.isNull(extendInfo)){
extendInfos.put(currField, defaultValue);
}else{
extendInfo.put(currField, defaultValue);
}
} else {
log.info("[AutoParamRuleAspect --> doAround]- error parentField: {} ", parentField);
}
}
}
//校验规则: 2: 替换原来的值
List<PicBInterfaceConfigTemplateBean> requiredRuleFieldList = picBInterfaceConfigTemplateBeanList.stream()
.filter(p -> p.getTemplateType().equals(2) && !StringUtil.isEmpty(p.getRule())).collect(Collectors.toList());
if (!CollectionUtils.isEmpty(requiredRuleFieldList)) {
//全部规则节点
Map<String, List<PicBInterfaceConfigTemplateBean>> map = requiredRuleFieldList.stream().collect(
Collectors.groupingBy(o -> o.getInterfaceParentField()+':'+o.getInterfaceField()));
Set<String> sets = map.keySet();
//匹配到规则的节点
Set<String> set = Sets.newHashSet();
List<String> ruleList = requiredRuleFieldList.stream().map(PicBInterfaceConfigTemplateBean::getRule).collect(Collectors.toList());
log.info("[AutoParamRuleAspect --> doAround]- ruleList: {} ", JSONObject.toJSONString(ruleList));
for (String rule : ruleList) {
FieldRules fieldRule = JSON.parseObject(rule, FieldRules.class);
//被替换值 节点信息 eg: "fieldCode": "jobInfo", "fieldCodeParentId": "extendInfo"}, "value2": "b"
String fieldCode = fieldRule.getFieldCode();
String fieldCodeParentId = fieldRule.getFieldCodeParentId();
String value2 = fieldRule.getValue2();
//替换值 节点信息 eg: "field": "contractCompanyCode", "parentId": "baseInfo", "value": "a"
String field = fieldRule.getField();
String parentId = fieldRule.getParentId();
String value = fieldRule.getValue();
if ("baseInfo".equals(fieldCodeParentId)) {
// 获取该类的成员变量
Field f = applyNewContRequestDTOs.getClass().getDeclaredField(fieldCode);
// 基准变量的值
String baseValue = "";
if ("baseInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applyNewContRequestDTO, field));
} else if ("applicant".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applicantInfoDTO, field));
} else if ("insureds".equals(parentId)) {
if (!CollectionUtils.isEmpty(insureds)) {
baseValue = String.valueOf(getFieldValueByName(insureds.get(0), field));
}
} else if ("payInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(payReceivedDTO, field));
} else if ("extendInfo".equals(parentId)) {
baseValue = String.valueOf(extendInfo.get(field));
} else {
log.info("[AutoParamRuleAspect --> doAround]- error fieldCodeParentId: {} ", fieldCodeParentId);
}
String fieldType = f.getType().getTypeName();
if (value.equals(baseValue)) {
set.add(fieldCodeParentId + ":" + fieldCode);
// 取消语言访问检查
f.setAccessible(Boolean.TRUE);
if(Objects.isNull(applyNewContRequestDTO)){
f.set(applyNewContRequestDTOs, ObjectUtils.convertAttributeValue(fieldType, value2));
}else{
f.set(applyNewContRequestDTO, ObjectUtils.convertAttributeValue(fieldType, value2));
}
}
} else if ("applicant".equals(fieldCodeParentId)) {
// 获取该类的成员变量
Field f = getAllField(applicantInfoDTOs.getClass(), fieldCode);
// 基准变量的值
String baseValue = "";
if ("baseInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applyNewContRequestDTO, field));
} else if ("applicant".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applicantInfoDTO, field));
} else if ("insureds".equals(parentId)) {
if (!CollectionUtils.isEmpty(insureds)) {
baseValue = String.valueOf(getFieldValueByName(insureds.get(0), field));
}
} else if ("payInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(payReceivedDTO, field));
} else if ("extendInfo".equals(parentId)) {
baseValue = String.valueOf(extendInfo.get(field));
} else {
log.info("[AutoParamRuleAspect --> doAround]- error fieldCodeParentId: {} ", fieldCodeParentId);
}
String fieldType = f.getType().getTypeName();
if (value.equals(baseValue)) {
set.add(fieldCodeParentId + ":" + fieldCode);
// 取消语言访问检查
f.setAccessible(Boolean.TRUE);
if(Objects.isNull(applicantInfoDTO)){
f.set(applicantInfoDTOs, ObjectUtils.convertAttributeValue(fieldType, value2));
}else{
f.set(applicantInfoDTO, ObjectUtils.convertAttributeValue(fieldType, value2));
}
}
} else if ("insureds".equals(fieldCodeParentId)) {
if (!CollectionUtils.isEmpty(insureds)) {
for (InsuredInfoDTO insuredInfoDTO : insureds) {
Field f = getAllField(insuredInfoDTO.getClass(),fieldCode);
// 基准变量的值
String baseValue = "";
if ("baseInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applyNewContRequestDTO, field));
} else if ("applicant".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applicantInfoDTO, field));
} else if ("insureds".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(insuredInfoDTO, field));
} else if ("payInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(payReceivedDTO, field));
} else if ("extendInfo".equals(parentId)) {
baseValue = String.valueOf(extendInfo.get(field));
} else {
log.info("[AutoParamRuleAspect --> doAround]- error fieldCodeParentId: {} ", fieldCodeParentId);
}
String fieldType = f.getType().getTypeName();
if (value.equals(baseValue)) {
set.add(fieldCodeParentId + ":" + fieldCode);
f.setAccessible(Boolean.TRUE);
f.set(insuredInfoDTO, ObjectUtils.convertAttributeValue(fieldType, value2));
}
}
}else{
Field f = getAllField(insured.getClass(), fieldCode);
f.setAccessible(Boolean.TRUE);
String fieldType = f.getType().getTypeName();
f.set(insured, ObjectUtils.convertAttributeValue(fieldType, value2));
}
} else if ("payInfo".equals(fieldCodeParentId)) {
// 获取该类的成员变量
Field f = payReceivedDTOs.getClass().getDeclaredField(fieldCode);
// 基准变量的值
String baseValue = "";
if ("baseInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applyNewContRequestDTO, field));
} else if ("applicant".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applicantInfoDTO, field));
} else if ("insureds".equals(parentId)) {
if (!CollectionUtils.isEmpty(insureds)) {
baseValue = String.valueOf(getFieldValueByName(insureds.get(0), field));
}
} else if ("payInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(payReceivedDTO, field));
} else if ("extendInfo".equals(parentId)) {
baseValue = String.valueOf(extendInfo.get(field));
} else {
log.info("[AutoParamRuleAspect --> doAround]- error fieldCodeParentId: {} ", fieldCodeParentId);
}
String fieldType = f.getType().getTypeName();
if (value.equals(baseValue)) {
set.add(fieldCodeParentId + ":" + fieldCode);
// 取消语言访问检查
f.setAccessible(Boolean.TRUE);
if(Objects.isNull(payReceivedDTO)){
f.set(payReceivedDTOs, ObjectUtils.convertAttributeValue(fieldType, value2));
}else{
f.set(payReceivedDTO, ObjectUtils.convertAttributeValue(fieldType, value2));
}
} else {
log.info("[AutoParamRuleAspect --> doAround]- error fieldCodeParentId: {} ", fieldCodeParentId);
}
} else if ("extendInfo".equals(fieldCodeParentId)) {
// 基准变量的值
String baseValue = "";
if ("baseInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applyNewContRequestDTO, field));
} else if ("applicant".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(applicantInfoDTO, field));
} else if ("insureds".equals(parentId)) {
if (!CollectionUtils.isEmpty(insureds)) {
baseValue = String.valueOf(getFieldValueByName(insureds.get(0), field));
}
} else if ("payInfo".equals(parentId)) {
baseValue = String.valueOf(getFieldValueByName(payReceivedDTO, field));
} else if ("extendInfo".equals(parentId)) {
baseValue = String.valueOf(extendInfo.get(field));
} else {
log.info("[AutoParamRuleAspect --> doAround]- error fieldCodeParentId: {} ", fieldCodeParentId);
}
if (value.equals(baseValue)) {
set.add(fieldCodeParentId + ":" + fieldCode);
extendInfo.put(fieldCode, value2);
if(Objects.isNull(extendInfo)){
extendInfos.put(fieldCode, value2);
}else{
extendInfo.put(fieldCode, value2);
}
} else {
log.info("[AutoParamRuleAspect --> doAround]- error fieldCodeParentId: {} ", fieldCodeParentId);
}
}
}
sets.removeAll(set);
if(!CollectionUtils.isEmpty(sets)){
Iterator it = sets.iterator();
while(it.hasNext()){
String [] fields = it.next().toString().split(":");
String parentField = fields[0];
String currField = fields[1];
String msg = String.format("参数父节点 ParentField: %s->当前节点currField: %s设置了规则,但未匹配到任何规则,请检查规则设置", parentField, currField);
throw new BizException(msg);
}
}
}
//判断传入字段为空b
if(Objects.isNull(applicantInfoDTO)){
applyNewContRequestDTO.setApplicant(applicantInfoDTOs);
}else{
applyNewContRequestDTO.setApplicant(applicantInfoDTO);
}
if(CollectionUtils.isEmpty(insureds)){
insuredInfoDTOs.add(insured);
applyNewContRequestDTO.setInsureds(insuredInfoDTOs);
}else{
applyNewContRequestDTO.setInsureds(insureds);
}
if(Objects.isNull(applicantInfoDTO)){
applyNewContRequestDTO.setApplicant(applicantInfoDTOs);
}else{
applyNewContRequestDTO.setApplicant(applicantInfoDTO);
}
if(Objects.isNull(extendInfo)){
applyNewContRequestDTO.setExtendInfo(extendInfos);
}else{
applyNewContRequestDTO.setExtendInfo(extendInfo);
}
picBaseRequestDTO.setBody(Objects.isNull(applyNewContRequestDTO)?applyNewContRequestDTOs:applyNewContRequestDTO);
args[0] = picBaseRequestDTO;
}
log.info("[AutoParamRuleAspect --> around end]- args[0]:{}", JSONObject.toJSONString(args[0]));
return pjp.proceed(args);
}
/**
* @Title: 校验必填字段
* @Author: ken
* @Description:
* @Date: 2023/3/24 18:46
* @Param: [parentField, currField, fieldValue]
* @return void
**/
private void checkRequiredFields(String parentField, String currField, String fieldValue) {
log.info("[AutoParamRuleAspect --> doAround]- parentField:{}, fieldValue: {} ", parentField, fieldValue);
if (StringUtil.isEmpty(fieldValue)) {
throw new BizException("参数父节点 ParentField:" + parentField + "->当前节点currField:" + currField + "不能为空");
}
}
/**
* @return java.lang.Object
* @Title: changObjectValue
* @Author: ken
* @Description: .getSuperclass()
* @Date: 2023/3/18 16:13
* @Param: [obj, filedName, afterValue]
**/
private Object changObjectValue(Object obj, String filedName, Object afterValue) throws Exception {
//获取父类的字段,因为capCode放在在基类里面,这里就直接获取父类的Class了,
//参数只在当前类的可以添加当前类的逻辑
Field[] fieldInfo = obj.getClass().getDeclaredFields();
for (Field field : fieldInfo) {
if (filedName.equals(field.getName())) {
//成员变量为private,故必须进行此操
field.setAccessible(true);
Object fieldValue = field.get(obj);
field.set(obj, afterValue);
break;
}
}
return obj;
}
/**
* 获取对象指定属性的值
*
* @param o 对象
* @param fieldName 要获取值的属性
* 返回值:对象指定属性的值
*/
public Object getFieldValueByName(Object o, String fieldName) {
try {
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + fieldName.substring(1);
Method method = o.getClass().getMethod(getter, new Class[]{});
Object value = method.invoke(o, new Object[]{});
return value;
} catch (Exception e) {
log.error("AutoParamRuleAspect --> getFieldValueByName error:{}", e.getMessage(), e);
return null;
}
}
/**
* @return java.lang.reflect.Field
* @Title: 根据属性名获取字段(当前类及父类)
* @Author: ken
* @Description:
* @Date: 2023/3/24 14:41
* @Param: [clazz, filedName]
**/
public static Field getAllField(Class<?> clazz, String filedName) {
try {
if (clazz != null) {
return clazz.getDeclaredField(filedName);
}
} catch (NoSuchFieldException e) {
return getAllField(clazz.getSuperclass(), filedName);
}
return null;
}
}
仅供参考.
公众号搜索: 果酱桑,一起成长,一起进步!
附 示例接口:
请求方式 POST
参数类型 `["application/json"]
接口描述 产品中心保单导入
请求报文体
ApplyNewContRequestDTO
参数名称 | 参数说明 | 是否必须 | 数据类型 | schema |
contNo | 保单号 | true | string | |
contractCompanyCode | 签约机构编码 | true | string | 必填代码上没有控制,如果传的话 会校验是否在 pic_b_insurance_company(保险公司定义表)是否存在 |
sessionId | 可回溯会话id | false | string | |
versionId | 可回溯版本id | false | string | |
actualPrem | 实付保费 | true | int | 单位(分) |
amount | 保额 | true | Long | 单位(分) |
prem | 保费金额 | true | int | 单位(分) |
productCode | 产品编码 | true | string | 由阳光提供 |
planCode | 计划编码 | true | string | 由阳光提供 |
applyDate | 投保时间 | true | string | 格式:yyyy-MM-dd HH:mm:ss |
contAcceptDate | 保单承保日期 | true | string | 格式:yyyy-MM-dd HH:mm:ss |
efftiveDate | 保单起期 | true | string | 格式:yyyy-MM-dd HH:mm:ss |
expireDate | 保单失效日期 | true | string | 格式:yyyy-MM-dd HH:mm:ss |
insurancePeriod | 保险期间 | true | int | 保单的保障期限。配合保险期间单位使用,例如:保险期间单位为:Y,保险期间:1.则1年 |
insuranceUnit | 保险期间单位 | true | string | 见6.5期间单位 |
payIntv | 缴费频率 | true | string | 缴费方式 见6.6缴费频率 |
payPeriod | 缴费期间 | true | int | 配合缴费期间单位使用,例如:缴费期间单位为:Y,缴费期间:1.则1年缴 |
payPeriodUnit | 缴费期间单位 | true | string | 见6.5期间单位 |
applicant | 投保人信息 | true | ApplicantInfoDTO | ApplicantInfoDTO |
payInfo | 订单回录:支付数据 | false | PayReceivedDTO | PayReceivedDTO |
insureds | 被保人列表 | true | array | InsuredInfoDTO |
extendInfo | 扩展信息 | false | object | 见扩展信息说明 |
commissionRate | 佣金比例 | false | String | 例:佣金比例为30%,则传30 |
commissionPrem | 佣金费佣金金额_含税 | false | String | 单位(分) |
settlementDate | 结算时间 | false | String | 由阳光提供,格式:yyyy-MM-dd HH:mm:ss |
projectMainId | 项目编码 | false | String | 由阳光提供 |
ApplicantInfoDTO
参数名称 | 参数说明 | 是否必须 | 数据类型 | schema |
appType | 投保人类型 | true | string | "01", "个人","02", "企业" |
name | 投保人名称 | true | string | |
gender | 性别 | false | string | 见6.7性别 证件非身份证必传 |
birthday | 生日 | false | string | 证件非身份证必传,yyyy-MM-dd |
certNo | 证件号码 | true | string | |
certType | 证件类型 | true | string | 见6.2证件类型 |
height | 身高 | false | integer(int32) | |
weight | 体重 | false | number | |
phone | 手机号 | false | string | |
| 邮箱 | false | string | |
nationality | 国籍 | false | string | |
certValidDate | 证件有效期 | false | string | yyyy-MM-dd |
longTremFlag | 证件长期有效标记 | false | string | |
nameEn | 英文姓名 | false | string | |
nameItem | 名 | false | string | |
nameItemEn | 英文名 | false | string | |
surname | 姓 | false | string | |
surnameEn | 英文姓 | false | string | |
extendInfo | 拓展json字段 | false | object |
InsuredInfoDTO
参数名称 | 参数说明 | 是否必须 | 数据类型 | schema |
name | 被保人名称 | true | string | |
gender | 性别 | false | string | 证件非身份证必传 |
birthday | 生日 | false | string | 证件非身份证必传,yyyy-MM-dd |
certNo | 证件号码 | true | string | |
certType | 证件类型 | true | string | 见6.2证件类型 |
certValidDate | 证件有效期 | false | string | yyyy-MM-dd |
longTremFlag | 证件长期有效标记 | false | string | |
phone | 手机号 | false | string | |
| 邮箱 | false | string | |
medicalInsurance | 医保状态 | false | string | 见6.9有无医保 |
socialInsurance | 社保状态 | false | string | 见6.8有无社保 |
marriage | 婚姻状况 | false | string | |
nationality | 国籍 | false | string | |
fixedFlag | 是否固定收入标记 | false | string | |
familyAnnualIncome | 家庭年收入 | false | string | |
annualIncome | 年收入 | false | string | |
relaWithApp | 与投保人关系 | true | string | 见6.3关系类型 |
relaWithMainIns | 与主被保人关系 | false | string | 见6.3关系类型 |
height | 身高 | false | integer(int32) | |
weight | 体重 | false | BigDecimal | |
prem | 被保人保费 | true | integer(int32) | 单位(分) |
amount | 被保人保额 | true | integer(int32) | 单位(分) |
nameEn | 英文姓名 | false | string | |
nameItem | 名 | false | string | |
nameItemEn | 英文名 | false | string | |
surname | 姓 | false | string | |
surnameEn | 英文姓 | false | string | |
benefitType | 受益人类型 | true | string | "01", "法定","02", "指定"。如指定受益人 需传受益人列表benefits 相关参数 |
benefits | 受益人列表 | false | array | BenefitInfoDTO,如指定受益人类型:02-指定,则必传 |
riskList | 险种列表 | false | array | RiskInfoDTO |
signPath | 签名影像 | false | string | |
filePathBack | 影像反面地址 | false | string | |
filePathFront | 影像正面地址 | false | string | |
extendInfo | 拓展json字段 | false | object | 见扩展信息说明 |
BenefitInfoDTO
参数名称 | 参数说明 | 是否必须 | 数据类型 | schema |
name | 受益人姓名 | false | string | |
nameEn | 英文姓名 | false | string | |
nameItem | 名 | false | string | |
nameItemEn | 英文名 | false | string | |
surname | 姓 | false | string | |
surnameEn | 英文姓 | false | string | |
gender | 性别 | true | string | |
birthday | 生日 | false | string | |
certNo | 证件号码 | true | string | |
certType | 证件类型 | true | string | 见6.2证件类型 |
certValidDate | 证件有效期 | false | string | |
longTremFlag | 证件长期有效标记 | false | string | |
phone | 手机号 | false | string | |
| 邮箱 | false | string | |
nationality | 国籍 | false | string | |
percent | 受益份额 | true | integer(int32) | 0~100,加总=100 |
priority | 受益顺序 | true | integer(int32) | |
relationWithInured | 与被保人关系 | true | string | 见6.3关系类型 |
signPath | 签名影像地址 | false | string | |
filePathBack | 影像反面地址 | false | string | |
filePathFront | 影像正面地址 | false | string | |
extendInfo | 拓展json字段 | false | object |
RiskInfoDTO
参数名称 | 参数说明 | 是否必须 | 数据类型 | schema |
riskCode | 险种编号 | TRUE | string | |
riskCount | 险种数量 | TRUE | integer(int32) | |
prem | 险种保费 | TRUE | integer(int32) | 单位(分) |
amount | 险种保额 | TRUE | integer(int32) | 单位(分) |
effectPeriod | 保障期限 | FALSE | integer(int32) | |
effectPeriodUnit | 保障期限单位 | FALSE | string | |
effectTime | 险种起期 | FALSE | string | |
expireTime | 险种止期 | FALSE | string | |
mainRiskFlag | 主险标记 | FALSE | boolean | |
dutyList | 责任列表 | TRUE | array | DutyInfoDTO |
DutyInfoDTO
参数名称 | 参数说明 | 是否必须 | 数据类型 | schema |
dutyName | 责任名称 | true | string | |
dutyCode | 责任编码 | true | string | |
dutyType | 责任类型 | true | string | |
dutyCount | 责任份数 | true | integer(int32) | |
dutyPrem | 责任保费 | true | integer(int32) | 单位(分) |
dutyAmount | 责任保额 | true | integer(int32) | 单位(分) |
subDedu | 次免赔额 | true | integer(int32) | 单位(分) |
yearDedu | 年免赔额 | true | integer(int32) | 单位(分) |
PayReceivedDTO
参数名称 | 参数说明 | 是否必须 | 数据类型 | schema |
paymentId | 支付id | true | string | |
outTradeNo | 商户支付号 | true | string | |
payNo | 商户支付单号 | true | string | |
orderAmount | 订单金额 | true | integer(int32) | 单位(分) |
payAmount | 支付金额 | true | integer(int32) | 单位(分) |
subsidyAmount | 折扣金额 | false | integer(int32) | 单位(分) |
payType | 支付方式 | false | string | |
payMethod | 支付方法 | false | string | |
payState | 支付状态 | true | string | |
payTime | 支付时间 | true | string | yyyy-MM-dd HH:mm:ss |
accountName | 账户名称 | false | string | |
accountNo | 账户号 | false | string | |
accountType | 账户类型 | false | string | |
bankCode | 银行编码 | false | string | |
payDesc | 支付描述 | false | string | |
createDate | 创建时间 | false | string(date-time) | yyyy-MM-dd HH:mm:ss |