迁移德州市鲁通码接口;

This commit is contained in:
mengkuiliang 2023-10-26 09:11:30 +08:00
parent 6f499cd4a5
commit 8b548ac3ba
7 changed files with 581 additions and 2 deletions

View File

@ -86,6 +86,14 @@
<artifactId>xinelu-familydoctor</artifactId>
</dependency>
<!-- 德州市居民码SM3Hmac算法 -->
<dependency>
<groupId>com.tzwy</groupId>
<artifactId>hmac</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/resources/lib/hmac-1.0.jar</systemPath>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,352 @@
package com.xinelu.web.controller.fd;
import com.alibaba.fastjson2.JSONObject;
import com.xinelu.common.core.controller.BaseController;
import com.xinelu.common.core.domain.R;
import com.xinelu.common.exception.ServiceException;
import com.xinelu.common.utils.DateUtils;
import com.xinelu.common.utils.http.HttpService;
import com.xinelu.common.utils.http.SslUtils;
import com.xinelu.familydoctor.applet.pojo.body.DzsCodeBody;
import com.xinelu.familydoctor.applet.pojo.query.DzsCodeQuery;
import com.xinelu.web.controller.fd.utils.DzsCodeSign;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Api(tags = "德州市居民码控制器爱山东APP")
@Slf4j
@RestController
@RequestMapping("/applet/fd/dzs/code")
public class DzsCodeController extends BaseController {
@Resource
private HttpService httpService;
@Value("${dzsCode.appid}")
private String appid;
@Value("${dzsCode.appSecret}")
private String appSecret;
@Value("${dzsCode.url}")
private String url;
@Value("${dzsCode.mutualUrl}")
private String mutualUrl;
@Value("${dzsCode.isSecret}")
private String isSecret;
@Value("${dzsCode.isWhole}")
private String isWhole;
@Value("${dzsCode.institutionCode}")
private String institutionCode;
@Value("${dzsCode.useCityCode}")
private String useCityCode;
@Value("${dzsCode.businessStepCode}")
private String businessStepCode;
@ApiOperation(value = "居民码注册接口")
@GetMapping("/register")
public R<?> register(DzsCodeBody body) {
try {
JSONObject bodyParams = registerBody(body);
String message = "";
// 0明文 1加密
if (isSecret.equals("1")) {
message = DzsCodeSign.makeSign(appSecret, bodyParams.toJSONString());
} else {
message = bodyParams.toJSONString();
}
Map<String, Object> headerMap = headerParams(message);
// 0明文 1加密
JSONObject requestBody = new JSONObject();
requestBody.put("message", message);
SslUtils.ignoreSsl();
JSONObject resultObj = httpService.post(url + "/register", headerMap, requestBody);
log.info("居民码注册接口响应:{}", resultObj);
if (!resultObj.containsKey("code") || !resultObj.getString("code").equals("200")) {
if (resultObj.containsKey("msg") && !StringUtils.isBlank(resultObj.getString("msg"))) {
return R.fail(resultObj.getString("msg"));
}
return R.fail("接口异常");
}
if (resultObj.containsKey("data")) {
return R.ok(resultObj.get("data"));
}
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(e.getMessage());
}
return R.ok();
}
@ApiOperation(value = "居民码查询接口")
@GetMapping("/analysis")
public R<?> query(DzsCodeQuery queryBody) {
try {
JSONObject bodyParams;
switch (queryBody.getInterfaceName()) {
// 是否已注册
case "isReg":
bodyParams = isRegBody(queryBody.getCardType(), queryBody.getCardNo());
break;
// 根据UID获取码值
case "getCodeByUid":
bodyParams = getCodeByUidBody(queryBody.getUid());
break;
// 根据证件获取居民码
case "getCodeByCard":
bodyParams = getCodeByCardBody(queryBody.getCardType(), queryBody.getCardNo());
break;
// 解析二维码
case "parsingCode":
bodyParams = parsingCodeBody(queryBody.getQrCode());
break;
// 获取用户信息
case "getUserInfo":
bodyParams = getUserInfoBody(queryBody.getJmmCode());
break;
default:
return R.fail("参数无效");
}
String message = "";
// 0明文 1加密
if (isSecret.equals("1")) {
message = DzsCodeSign.makeSign(appSecret, bodyParams.toJSONString());
} else {
message = bodyParams.toJSONString();
}
Map<String, Object> headerMap = headerParams(message);
// 0明文 1加密
JSONObject requestBody = new JSONObject();
requestBody.put("message", message);
SslUtils.ignoreSsl();
JSONObject resultObj = httpService.post(url + "/" + queryBody.getInterfaceName(), headerMap, requestBody);
log.info("居民码{}接口响应:{}", queryBody.getInterfaceName(), resultObj);
if (!resultObj.containsKey("code") || !resultObj.getString("code").equals("200")) {
if (resultObj.containsKey("msg") && !StringUtils.isBlank(resultObj.getString("msg"))) {
return R.fail(resultObj.getString("msg"));
}
return R.fail("接口异常");
}
if (resultObj.containsKey("data")) {
return R.ok(resultObj.getJSONObject("data"));
}
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(e.getMessage());
}
return R.ok();
}
@ApiOperation(value = "多码互认接口")
@PostMapping("/mutualDiscern")
public R<?> mutualDiscern(@RequestBody DzsCodeBody body) {
// 请求参数示例
// {
// "qrCode":"SDQR0000001A00010001371400011667058654613299203000169828216216982822221410ff8de0b234bdf8a92932e36173578789c4099bf3606c4c1e3e175a91a5ac754434bd767e4155ffdf095dc8a096714d4b86e535231efbb5383e9fd4cd13f2"
// }
if(body == null || StringUtils.isBlank(body.getQrCode())) {
return R.fail("请求参数无效");
}
try {
JSONObject bodyParams = mutualDiscernBody(body.getQrCode());
Map<String, Object> headerMap;
SslUtils.ignoreSsl();
String message = "";
JSONObject resultObj;
// 0明文 1加密
if (isSecret.equals("1")) {
message = DzsCodeSign.makeSign(appSecret, bodyParams.toJSONString());
headerMap = headerParams(message);
resultObj = httpService.post(mutualUrl + "/mutualDiscern", headerMap, message);
} else {
headerMap = headerParams(bodyParams.toJSONString());
resultObj = httpService.post(mutualUrl + "/mutualDiscern", headerMap, bodyParams);
}
log.info("居民码多码互认接口响应:{}", resultObj);
if (!resultObj.containsKey("code") || !resultObj.getString("code").equals("200")) {
if (resultObj.containsKey("msg") && !StringUtils.isBlank(resultObj.getString("msg"))) {
if (resultObj.containsKey("detail") && !StringUtils.isBlank(resultObj.getString("detail"))) {
return R.fail(resultObj.getString("msg") + "->" + resultObj.getString("detail"));
} else {
return R.fail(resultObj.getString("msg"));
}
}
return R.fail("接口异常");
}
if (resultObj.containsKey("data")) {
return R.ok(resultObj.getJSONObject("data"));
}
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(e.getMessage());
}
return R.ok();
}
/**
* 设置请求header参数 参数都是必填的
*/
private Map<String, Object> headerParams(String message) {
Map<String, Object> headMap = new HashMap<>();
// 客户端生成的安全随机码
String nonceStr = DzsCodeSign.getRandomString(10);
// 当前时间yyyyMMddHHmmss
String time = DateUtils.formatDate(new Date(), "yyyyMMddHHmmss");
// 根据appidnonceStrtime和(message)经过HMAC算法计算的值
String str = appid + "&" + time + "&" + nonceStr;
if (isWhole.equals("1")) {
str += message;
}
System.out.println("签名字符串:" + str);
// 应用ID
headMap.put("appid", appid);
headMap.put("nonceStr", nonceStr);
headMap.put("time", time);
headMap.put("sign", DzsCodeSign.makeSign(appSecret, str));
headMap.put("isSecret", isSecret);
headMap.put("isWhole", isWhole);
return headMap;
}
/**
* 设置body参数 - 判断是否已注册居民码
*/
private JSONObject isRegBody(String cardType, String cardNo) {
JSONObject jsonObject = new JSONObject();
// 证件类型
jsonObject.put("cardType", cardType);
// 证件编号
jsonObject.put("cardNo", cardNo);
return jsonObject;
}
/**
* 设置body参数 - 用户注册
*/
private JSONObject registerBody(DzsCodeBody body) {
JSONObject jsonObject = new JSONObject();
return jsonObject;
}
/**
* 设置body参数 - 根据UID获取居民码
*/
private JSONObject getCodeByUidBody(String uid) {
JSONObject jsonObject = new JSONObject();
// 居民码UID
jsonObject.put("uid", uid);
// 经度
jsonObject.put("longitude", "");
// 纬度
jsonObject.put("latitude", "");
// 县区编码
jsonObject.put("county", "");
// 街道
jsonObject.put("subdistrict", "");
// 地点
jsonObject.put("position", "");
return jsonObject;
}
/**
* 设置body参数 - 根据证件获取居民码
*/
private JSONObject getCodeByCardBody(String cardType, String cardNo) {
JSONObject jsonObject = new JSONObject();
// 证件类型
jsonObject.put("cardType", cardType);
// 证件编号
jsonObject.put("cardNo", cardNo);
// 经度
jsonObject.put("longitude", "");
// 纬度
jsonObject.put("latitude", "");
// 县区编码
jsonObject.put("county", "");
// 街道
jsonObject.put("subdistrict", "");
// 地点
jsonObject.put("position", "");
return jsonObject;
}
/**
* 设置body参数 - 解析二维码
*/
private JSONObject parsingCodeBody(String qrCode) {
JSONObject jsonObject = new JSONObject();
//
jsonObject.put("QrCode", qrCode);
// 机构编码
jsonObject.put("institutionCode", institutionCode);
// 终端类型0人工1自助
jsonObject.put("channelCode", "0");
// 业务环节
jsonObject.put("businessStepCode", businessStepCode);
// 用码时间 yyyy-MM-dd HH:mm:ss
jsonObject.put("useTime", DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
// 返回值类型对接时添加后台的 二维码解析返回值类型
jsonObject.put("returnValueType", "01");
// 经度
jsonObject.put("longitude", "");
// 纬度
jsonObject.put("latitude", "");
// 县区编码
jsonObject.put("county", "");
// 街道
jsonObject.put("subdistrict", "");
// 地点
jsonObject.put("position", "");
return jsonObject;
}
/**
* 设置body参数 - 获取用户信息
*/
private JSONObject getUserInfoBody(String jmmCode) {
JSONObject jsonObject = new JSONObject();
// 省居民码授权码
jsonObject.put("jmmCode", jmmCode);
return jsonObject;
}
/**
* 设置body参数 - 多码互认 二维码识读
*/
private JSONObject mutualDiscernBody(String qrCode) {
JSONObject jsonObject = new JSONObject();
//
jsonObject.put("QrCode", qrCode);
// 城市编码
jsonObject.put("useCityCode", useCityCode);
// 机构编码
jsonObject.put("institutionCode", institutionCode);
// 终端类型0人工1自助
jsonObject.put("channelCode", "0");
// 业务环节接口方提供
jsonObject.put("businessStepCode", businessStepCode);
// 用卡时间 yyyy-MM-dd HH:mm:ss
jsonObject.put("useTime", DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
// 返回值类型对接时添加后台的 二维码解析返回值类型
jsonObject.put("returnValueType", "01");
// 经度
jsonObject.put("longitude", "");
// 纬度
jsonObject.put("latitude", "");
// 县区编码 市辖区371401 德城区371402 陵城区371403 宁津县371422 庆云县371423 临邑县371424 齐河县371425 平原县371426 夏津县371427 武城县371428 乐陵市371481 禹城市371482 天衢新区371471
jsonObject.put("county", "");
// 街道
jsonObject.put("subdistrict", "");
// 地点
jsonObject.put("position", "");
return jsonObject;
}
}

View File

@ -0,0 +1,98 @@
package com.xinelu.web.controller.fd.utils;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
import com.tzwy.hmac.sm3.utils.Sm3HmacUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
/**
* @Author mengkuiliang
* @Description 德州市居民码签名工具类
* @Date 2023-06-08 16:45
* @Param
* @return
**/
@Slf4j
@Component
public class DzsCodeSign {
/**
* @return java.lang.String
* @Author mengkuiliang
* @Description 生成签名
* @Date 2023-06-08 16:40
* @Param [appId, appSecret, isWhole]
**/
public static String createSign(String appId, String appSecret, String isWhole, String message) {
SimpleDateFormat formater = new SimpleDateFormat("yyyyMMddHHmmss");
String str;
if(isWhole.equals("0")) {
str = appId + "&" + formater.format(new Date()) + "&" + getRandomString(10);
} else {
// message前边没有 &
str = appId + "&" + formater.format(new Date()) + "&" + getRandomString(10) + message;
}
System.out.println("签名字符串:" + str);
return makeSign(appSecret, str);
}
/**
* @return boolean
* @Author mengkuiliang
* @Description 验证签名
* @Date 2023-06-08 16:43
* @Param [str, appSecret, sign]
**/
public static boolean verifySign(String str, String appSecret, String sign) {
String signS = makeSign(appSecret, str);
return signS.equals(sign);
}
/**
* 生成指定长度的随机字符串
*/
public static String getRandomString(int length) {
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(62);
sb.append(str.charAt(number));
}
return sb.toString();
}
/**
* 生成签名
*/
public static String makeSign(String appSecret, String str) {
try {
byte[] sm3Sign = Sm3HmacUtils.calcMac(HexUtil.decodeHex(appSecret), str.getBytes("UTF-8"));
return Base64.encode(sm3Sign);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) throws UnsupportedEncodingException {
String appSecret = "74cb380c19b5448da4d7a1ef505089c4";
String appid = "lhw8570wl9zojyou6zv6";
// String time = DateUtils.formatDate(new Date(), "yyyyMMddHHmmss");
String time = "20230609165045";
// String nonceStr = DzsCodeSign.getRandomString(10);
String nonceStr = "8EqtkddxC2";
String str = appid + "&" + time + "&" + nonceStr;
String signS = makeSign(appSecret, str);
System.out.println(signS);
// JAlMiqpak3hwtTa+OzlWPcTuE2sSwn+F/I0j5/Cu3Mg=
}
}

View File

@ -249,8 +249,8 @@ xss:
# 家医配置
fd:
dy: http://192.168.124.6:8001/fd/mp
dz: http://192.168.124.6:8001/fd/mp
dz: http://8.131.93.145:54089/fd/mp
dy: http://8.131.93.145:54089/fd/mp
# 签约附近的机构多少公里内 <=0时不限制
distance: 0
@ -316,3 +316,22 @@ logistics-config:
e-business-id: 1781371
api-key: 998b273d-c926-4659-a9d5-ae0613782d70
express-bird-url: https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx
# 德州市鲁通码接口配置
dzsCode:
appid: lhw8570wl9zojyou6zv6
appSecret: 74cb380c19b5448da4d7a1ef505089c4
# 接口服务
url: https://dsjj.dezhou.gov.cn/dzjmm/code
# 多码互认
mutualUrl: https://dsjj.dezhou.gov.cn/dzjmm/mutual
# 传输数据是否要加密(0:否1:是)
isSecret: 0
# 是否校验完整性(0:否1:是) 当为1时sign的生成入参包括message
isWhole: 0
# 机构编码
institutionCode: 1137140000440159XP
# 城市编码 德州市
useCityCode: 371400
# 业务场景
businessStepCode: 302

Binary file not shown.

View File

@ -0,0 +1,66 @@
package com.xinelu.familydoctor.applet.pojo.body;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author mengkuiliang
* @Description 德州市居民码请求对象
* @Date 2023-06-09 9:45
* @Param
* @return
**/
@Data
@ApiModel("德州市居民码请求对象")
public class DzsCodeBody {
@ApiModelProperty(value = "二维码信息")
private String qrCode;
@ApiModelProperty(value = "姓名", required = true)
private String name;
@ApiModelProperty(value = "证件类型", required = true)
private String cardType;
@ApiModelProperty(value = "证件号码", required = true)
private String cardNo;
@ApiModelProperty(value = "电话号码", required = true)
private String phone;
@ApiModelProperty(value = "民族 01汉族 02蒙古族 03回族 04藏族 05维吾尔族 06苗族 07彝族 08壮族 09布依族 10朝鲜族 11满族 12侗族 13瑶族 14白族 15土家族 16哈尼族 17哈萨克族 18傣族 19黎族 20傈僳族 21佤族 22畲族 23高山族 24拉祜族 25水族 26东乡族 27纳西族 28景颇族 29柯尔柯孜族 30土族 31达尔族 32仫佬族 33羌族 34布朗族 35撒拉族 36毛南族 37仡佬族 38锡伯族 39阿昌族 40普米族 41塔吉克族 42怒族 43乌孜别克族 44俄罗斯族 45鄂温克族 46德昂族 47保安族 48裕固族 49京族 50塔塔尔族 51独龙族 52鄂伦春族 53赫哲族 54门巴族 55珞巴族 56基诺族 97其他未识别的民族", required = true)
private String nation;
@ApiModelProperty(value = "性别 1男 2女 9未说明性别 ", required = true)
private String sex;
@ApiModelProperty(value = "注册途径11APP 12微信公众帐号 13支付宝服务号 21自助机 31窗口 41批量处理", required = true)
private String regChannel;
@ApiModelProperty(value = "注册模式1线上、2线下", required = true)
private String regMode;
@ApiModelProperty(value = "个人审核材料上传地址(身份证时可空;非身份证时必填)")
private String path;
@ApiModelProperty(value = "绑卡类型(对接时添加,后台字典的 证件类型--可绑定证)")
private String bindCardType;
@ApiModelProperty(value = "绑卡卡号")
private String bindCardNo;
@ApiModelProperty(value = "出生年月yyyyMM 证件类型是身份证时可空,非身份证时必填)")
private String birthday;
@ApiModelProperty(value = "地区编码")
private String addressAreaCode;
@ApiModelProperty(value = "用户uid调用省居民码接口返回", required = true)
private String uid;
@ApiModelProperty(value = "用户id调用省居民码接口返回", required = true)
private String qcUserId;
}

View File

@ -0,0 +1,36 @@
package com.xinelu.familydoctor.applet.pojo.query;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @Author mengkuiliang
* @Description 德州市居民码查询对象
* @Date 2023-06-09 9:45
* @Param
* @return
**/
@Data
@ApiModel("德州市居民码查询对象")
public class DzsCodeQuery {
@ApiModelProperty(value = "接口名称判断是否已注册居民码isReg 居民码用户注册register 根据UID获取居民码getCodeByUid 解析居民码二维码parsingCode 根据证件获取居民码getCodeByCard 获取用户信息getUserInfo", required = true)
String interfaceName;
@ApiModelProperty("省居民码授权码")
String jmmCode;
@ApiModelProperty("用户标识")
String uid;
@ApiModelProperty("证件类型01居民身份证 03: 外国护照; 06: 港澳居民来往内地通行证; 07: 台湾居民来往内地通行证;)")
String cardType;
@ApiModelProperty("证件号")
String cardNo;
@ApiModelProperty("二维码")
String qrCode;
}