问题背景:在做企业微信考勤相关功能的时候,遇到把json转成实体类,通常我会使用com.alibaba.fastjson.parseObject(json,.class)。但是有些属性一直转换不过来。即使我使用了@SerializedName注解,也无法转换。
binarywang提供了一些企业微信的sdk,可以很方便的调用企业微信的接口
<!-- 企业微信sdk -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-cp</artifactId>
</dependency>
但是,最新的sdk版本中,获取审批详情时,并没有打卡补卡的数据,于是我只能自己去调用企业微信的接口。
@Slf4j
@Component
@EnableConfigurationProperties({WxCpProperties.class})
public class WxHttpUtil {
@Resource
private WxCpAppidProperties appidProperties;
@Resource
private WxCpProperties properties;
private String corpId;
private String corpSecret;
private String getTokenUrl = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?";
private String getApprovalDetailUrl = "https://qyapi.weixin.qq.com/cgi-bin/oa/getapprovaldetail?access_token=";
/**
* 获取access_token
*
* @return
*/
public String getWxAccessToken() {
try {
List<WxCpProperties.AppConfig> appConfigs = properties.getAppConfigs();
Integer checkinSp = appidProperties.getCheckinSp();
Optional<WxCpProperties.AppConfig> config = appConfigs.stream().filter(a -> a.getAgentId().equals(checkinSp)).findFirst();
if (config.isPresent()) {
WxCpProperties.AppConfig appConfig = config.get();
corpId = properties.getCorpId();
corpSecret = appConfig.getSecret();
}
} catch (Exception e) {
log.error("微信配置文件不正确");
}
String url = getTokenUrl + "corpid=" + corpId + "&corpsecret=" + corpSecret;
log.info("获取企业微信access_token,url:{}", url);
String result = HttpUtil.get(url);
if (result != null) {
JSONObject resultJson = JSON.parseObject(result);
// 出错返回码,为0表示成功,非0表示调用失败
if (resultJson.getInteger("errcode") == 0) {
return resultJson.getString("access_token");
} else {
log.error("企业微信获取access_token失败,{}", resultJson.get("errmsg"));
return "";
}
}
log.info("获取企业微信access_token失败,result:{}", result);
return "";
}
/**
* 获取审批详情
*
* @param accessToken token
* @param spNo 审批单号
*/
public String getApprovalDetail(String accessToken, String spNo) {
String url = getApprovalDetailUrl + accessToken;
Map<String, Object> body = new HashMap<>();
body.put("sp_no", spNo);
String result = HttpUtil.post(url, JSONObject.toJSONString(body));
if (result != null) {
JSONObject resultJson = JSON.parseObject(result);
// 出错返回码,为0表示成功,非0表示调用失败
if (resultJson.getInteger("errcode") == 0) {
return resultJson.toJSONString();
} else {
log.error("调用企业微信getApprovalDetail接口失败,{}", resultJson.get("errmsg"));
return "";
}
}
log.error("企业微信调用getApprovalDetail接口失败,{}", result);
return "";
}
}
这样,我们就能自己获取到企业微信的审批数据啦,但是在使用审批数据的时候,我们需要把json转成实体类,方便后续使用,这里就遇到了问题:
我不想完全自己定义接收实体类,因为属性实在太多了。于是我就继承sdk里面的实体,然后把打卡补卡属性补全,这样就相当于帮sdk打了个补丁,哈哈
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MesWxCpApprovalDetailContent implements Serializable {
/**
* 控件名称
*/
private String control;
/**
* 控件详情
*/
private WxCpApprovalDetailContentValue value;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class WxCpApprovalDetailContentValue extends ContentValue implements Serializable {
/**
* 补卡信息
*/
@SerializedName("punch_correction")
private punchCorrection punchCorrection;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class punchCorrection implements Serializable {
/**
* 异常状态说明
*/
private String state;
/**
* 补卡时间,Unix时间戳
*/
private long time;
/**
* 未知
*/
private String date;
}
}
}
然后再使用fastjson.parseObject把接口返回的json转成我们定义的补丁实体类,大功告成!!!
NONONO,正当此时,我发现sdk缺失的打卡补卡数据有了,但其他数据好像没了。。。
怎么会这样?原来sdk里面的实体属性和接口返回的属性名称不对应,比如:
但是,他不是定义了@SerializedName("sp_name")这样的别名吗?我自己也使用了@SerializedName注解,通过fastjson.parseObject是能接收过来的呀?一脸懵逼。。。
在接下来的一段时间里,我在疯狂逼问度娘,为什么继承会导致@SerializedName注解失效?
然而并没有得到想要的答案,笑死,然后我做了一个惊为天人的操作,我使用jsonString.replace方法,把接口结果里面转换不了的属性改成一样的属性名称,这也是不得已而为之的方法,哈哈,大功告成!!!
等等。。。
@SerializedName("value")
private List<ContentTitle> values;
replace其他唯一属性的时候,都得到了想要大的结果,转换成功,但,这个sdk怎么连value都能有好几种叫法?接口里面value可太多了,这下可就不好replace了
怎么办?我还想通过replace正则表达式来替换指定位置的value,然而不行,越搞越复杂。而且这样写代码谁能看得懂!
最后,经过学长点拨,原来一开始就错了,Gson和fastjosn是不同的工具类,
@SerializedName是Gson的写法,fastjosn当然不能识别。
Gson有自己转json到实体类的方法:
Type type = new TypeToken<MesWxCpApprovalDetailResult>() {
}.getType();
MesWxCpApprovalDetailResult mesWxCpApprovalDetailResult = new Gson().fromJson(approvalDetail, type);
//JSONObject.parseObject(approvalDetail,MesWxCpApprovalDetailResult.class);
恍然大悟。。。
最后,有个问题,我自己写的实体类的属性用
@SerializedName
,为什么可以通过fastjson转换到实体里面?继承过来的属性为啥就不能识别?