以前简单下发权限,现在简单取消权限

This commit is contained in:
guoshengxiong 2024-07-15 19:59:33 +08:00
parent a3bc633163
commit f6bbbfaf10
3 changed files with 116 additions and 151 deletions

View File

@ -1,5 +1,6 @@
package com.zhgd.xmgl.async;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
@ -33,7 +34,6 @@ import com.zhgd.xmgl.modules.xz.service.impl.XzHikvisionCompareDataServiceImpl;
import com.zhgd.xmgl.security.entity.UserInfo;
import com.zhgd.xmgl.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
@ -563,106 +563,6 @@ public class AsyncHikvision {
}
}
/**
* 异步添加人员权限
*
* @param workerInfo
* @param devSns
*/
@Async("hikvisionExecutor")
public void addPersonAuthAsync(WorkerInfo workerInfo, String devSns) {
try {
StringBuilder sucSb = new StringBuilder();
StringBuilder failSb = new StringBuilder();
String[] devSnArr = StringUtils.split(devSns, ",");
try {
for (String ds : devSnArr) {
hikvisionCall.updatePersonAuth(workerInfo, ds, sucSb, failSb, 0);
}
} catch (Exception e) {
log.error("e", e);
if (HttpUtils.isTimeOut(e)) {
noticeService.addUserNotice(ThreadLocalUtil.getByKey(Cts.TL_AUTH_USER, UserInfo.class).getUserId(), "失败原因平台连接isc网络异常", "人员下发设备提醒", "1");
} else {
noticeService.addUserNotice(ThreadLocalUtil.getByKey(Cts.TL_AUTH_USER, UserInfo.class).getUserId(), e.getMessage(), "人员下发设备提醒", "1");
}
hikvisionCall.updateAllFailStatusIfNullForAuth(workerInfo.getProjectSn(), workerInfo.getId(), 1, 1);
return;
}
String title = "人员下发设备提醒";
String type = "1";
String msg = "";
String sucSbStr = sucSb.toString();
if (StringUtils.isNotBlank(sucSbStr)) {
sucSbStr = "下发权限成功:" + sucSbStr;
msg += sucSbStr;
}
String failSbStr = failSb.toString();
if (StringUtils.isNotBlank(failSbStr)) {
failSbStr = "下发权限失败:" + failSbStr;
msg += failSbStr;
}
if (ThreadLocalUtil.getByKey(Cts.TL_AUTH_USER, UserInfo.class) != null) {
noticeService.addUserNotice(ThreadLocalUtil.getByKey(Cts.TL_AUTH_USER, UserInfo.class).getUserId(), StringUtils.substring(msg, 0, msg.length() - 1), title, type);
}
hikvisionCall.updateAllFailStatusIfNullForAuth(workerInfo.getProjectSn(), workerInfo.getId(), 1, 1);
} catch (Exception e) {
log.error("海康:", e);
}
}
/**
* 异步删除人员权限
*
* @param workerInfo
* @param devSns
*/
@Async("hikvisionExecutor")
public void deletePersonAuthAsync(WorkerInfo workerInfo, String devSns) {
try {
if (StringUtils.isBlank(devSns)) {
return;
}
StringBuilder sucSb = new StringBuilder();
StringBuilder failSb = new StringBuilder();
String[] devSnArr = StringUtils.split(devSns, ",");
try {
for (String ds : devSnArr) {
hikvisionCall.updatePersonAuth(workerInfo, ds, sucSb, failSb, 2);
}
} catch (Exception e) {
if (HttpUtils.isTimeOut(e)) {
noticeService.addUserNotice(ThreadLocalUtil.getByKey(Cts.TL_AUTH_USER, UserInfo.class).getUserId(), "网络异常", "人员下发设备提醒", "1");
} else {
noticeService.addUserNotice(ThreadLocalUtil.getByKey(Cts.TL_AUTH_USER, UserInfo.class).getUserId(), e.getMessage(), "人员下发设备提醒", "1");
}
hikvisionCall.updateAllFailStatusIfNullForAuth(workerInfo.getProjectSn(), workerInfo.getId(), 1, 3);
return;
}
String title = "人员下发设备提醒";
String type = "1";
String msg = "";
String sucSbStr = sucSb.toString();
if (StringUtils.isNotBlank(sucSbStr)) {
sucSbStr = "移除权限成功:" + sucSbStr;
msg += sucSbStr;
}
String failSbStr = failSb.toString();
if (StringUtils.isNotBlank(failSbStr)) {
failSbStr = "移除权限失败:" + failSbStr;
msg += failSbStr;
}
if (ThreadLocalUtil.getByKey(Cts.TL_AUTH_USER, UserInfo.class) != null) {
noticeService.addUserNotice(ThreadLocalUtil.getByKey(Cts.TL_AUTH_USER, UserInfo.class).getUserId(), StringUtils.substring(msg, 0, msg.length() - 1), title, type);
}
hikvisionCall.updateAllFailStatusIfNullForAuth(workerInfo.getProjectSn(), workerInfo.getId(), 1, 3);
} catch (Exception e) {
log.error("海康:", e);
}
}
/**
* 异步获取车辆通行数据
*
@ -715,14 +615,16 @@ public class AsyncHikvision {
}
}
Map<String, UfaceDev> devSnMap = allDevList.stream().collect(Collectors.toMap(UfaceDev::getDevSn, Function.identity()));
Map<String, List<JSONObject>> devSnToJoMap = workerAndDevSnList.stream().collect(Collectors.groupingBy(jsonObject -> jsonObject.getString("devSn")));
JSONObject gdvJo = HikvisionUtil.getDoorsV2(project, HikvisionUtil.addPageParamIfAbsent(new JSONObject()));
JSONObject gdvDataJo = HikvisionUtil.getJsonObjectData(gdvJo);
//门禁设备编号parentIndexCode门禁点编号indexCode门禁设备资源通道号channelNo
Map<String, JSONObject> devSnToIscDevSnMap = gdvDataJo.getJSONArray("list").stream().collect(Collectors.toMap(o -> ((JSONObject) o).getString("indexCode"), o -> (JSONObject) o));
workerAndDevSnList = this.addNeedSimpleAuthProp(workerAndDevSnList, devSnToIscDevSnMap, project);
Map<String, List<JSONObject>> devSnToJoMap = workerAndDevSnList.stream().collect(Collectors.groupingBy(jsonObject -> jsonObject.getString("devSn")));
futures = new ArrayList<>();
for (Map.Entry<String, List<JSONObject>> entry : devSnToJoMap.entrySet()) {
Future future = asyncHikvision.sendBatchWorkersForOneDevAsync(workerIdMap, devSnMap, project, devSnToIscDevSnMap, entry, projectSn, sendNotice, workerList, flowStartUser);
JSONObject iscDevSnObj = devSnToIscDevSnMap.get(entry.getKey());
Future future = asyncHikvision.sendBatchWorkersForOneDevAsync(devSnMap.get(entry.getKey()), entry, workerIdMap, workerList, project, projectSn, sendNotice, flowStartUser, iscDevSnObj);
futures.add(future);
}
for (Future future : futures) {
@ -753,6 +655,59 @@ public class AsyncHikvision {
}
}
/**
* 添加需要简单权限删除的标志
*
* @param workerAndDevSnList
* @param devSnToIscDevSnMap
* @param project
* @return
*/
private List<JSONObject> addNeedSimpleAuthProp(List<JSONObject> workerAndDevSnList, Map<String, JSONObject> devSnToIscDevSnMap, Project project) throws Exception {
JSONArray rtJa = new JSONArray();
List<String> workerIds = workerAndDevSnList.stream().filter(o -> !o.getBoolean(Cts.IS_ADD_AUTH)).map(o -> o.getString("workerId")).distinct().collect(Collectors.toList());
Map<String, JSONObject> iscDevMap = new HashMap<>();
if (CollUtil.isNotEmpty(workerIds)) {
Set<Map.Entry<String, JSONObject>> iscDevEntries = devSnToIscDevSnMap.entrySet();
for (List<String> splitList : CollUtil.splitList(workerIds, MAX_PAGE_SIZE)) {
JSONObject qaiJo = getQueryAuthItemParam(splitList, iscDevEntries.stream().map(e -> {
return new JoBuilder()
.put("resourceIndexCode", e.getValue().getString("parentIndexCode"))
.put("resourceType", "acsDevice")
.put("channelNos", Collections.singletonList(e.getValue().getString("channelNo")))
.build();
}).collect(Collectors.toList()));
JSONObject qaiRtJo = HikvisionUtil.getJsonObjectData(HikvisionUtil.queryAuthItem(project, qaiJo));
JSONArray qaiList = qaiRtJo.getJSONArray("list");
if (CollUtil.isNotEmpty(qaiList)) {
rtJa.addAll(qaiList);
}
}
List<JSONObject> simpleDeleteAuths = rtJa.stream().filter(o -> {
JSONArray ja = ((JSONObject) o).getJSONArray("templateConfigInfos");
if (CollUtil.isNotEmpty(ja)) {
JSONObject jo = ja.getJSONObject(0);
if (jo != null) {
return Objects.equals(jo.getInteger("dimension"), 1);
}
}
return false;
}).map(o -> ((JSONObject) o)).collect(Collectors.toList());
iscDevMap = simpleDeleteAuths.stream().collect(Collectors.toMap(o -> o.getString("resourceIndexCode") + Cts.COMMA + o.getString("channelNo"), Function.identity()));
}
for (JSONObject jo : workerAndDevSnList) {
String devSn = jo.getString("devSn");
JSONObject iscDevJo = devSnToIscDevSnMap.get(devSn);
JSONObject have = iscDevMap.get(iscDevJo.get("parentIndexCode") + Cts.COMMA + iscDevJo.get("channelNo"));
if (have != null) {
jo.put(Cts.IS_SIMPLE_DELETE_AUTH, true);
} else {
jo.put(Cts.IS_SIMPLE_DELETE_AUTH, false);
}
}
return workerAndDevSnList;
}
/**
* 发送异常通知
*
@ -843,35 +798,42 @@ public class AsyncHikvision {
/**
* 一个设备批量下发人员
*
* @param workerIdMap
* @param devSnMap
* @param project
* @param devSnToIscDevSnMap
* @param dev
* @param devSnToJoEntry
* @param sendNotice
* @param workerIdMap
* @param workerList
* @param project
* @param sendNotice
* @param flowStartUser
* @param iscDevSnObj
*/
@Async("workerBeWaitHkExecutor")
public Future sendBatchWorkersForOneDevAsync(Map<String, WorkerInfo> workerIdMap, Map<String, UfaceDev> devSnMap, ProjectInfoExtVo project, Map<String, JSONObject> devSnToIscDevSnMap, Map.Entry<String, List<JSONObject>> devSnToJoEntry, String projectSn, boolean sendNotice, List<WorkerInfo> workerList, Long flowStartUser) {
public Future sendBatchWorkersForOneDevAsync(UfaceDev dev, Map.Entry<String, List<JSONObject>> devSnToJoEntry, Map<String, WorkerInfo> workerIdMap, List<WorkerInfo> workerList, ProjectInfoExtVo project, String projectSn, boolean sendNotice, Long flowStartUser, JSONObject iscDevSnObj) {
String devSn = devSnToJoEntry.getKey();
UfaceDev dev = devSnMap.get(devSn);
List<String> addAuthWorkerIds = devSnToJoEntry.getValue().stream().filter(jo -> jo.getBoolean(Cts.IS_ADD_AUTH)).map(jsonObject -> jsonObject.getString("workerId")).collect(Collectors.toList());
List<String> deleteAuthWorkerIds = devSnToJoEntry.getValue().stream().filter(jo -> !jo.getBoolean(Cts.IS_ADD_AUTH)).map(jsonObject -> jsonObject.getString("workerId")).collect(Collectors.toList());
List<String> deleteAuthWorkerIds = devSnToJoEntry.getValue().stream().filter(jo -> !jo.getBoolean(Cts.IS_ADD_AUTH) && !jo.getBoolean(Cts.IS_SIMPLE_DELETE_AUTH)).map(jsonObject -> jsonObject.getString("workerId")).collect(Collectors.toList());
List<String> deleteSimpleAuthWorkerIds = devSnToJoEntry.getValue().stream().filter(jo -> !jo.getBoolean(Cts.IS_ADD_AUTH) && jo.getBoolean(Cts.IS_SIMPLE_DELETE_AUTH)).map(jsonObject -> jsonObject.getString("workerId")).collect(Collectors.toList());
try {
if (CollUtil.isNotEmpty(deleteSimpleAuthWorkerIds)) {
//需要简单删除权限方法
for (String workerId : deleteSimpleAuthWorkerIds) {
Future future = asyncHikvision.simpleDeletePersonAuthAsync(workerId, dev, project, flowStartUser, workerIdMap, iscDevSnObj);
future.get();
}
}
//添加权限配置人员列表设备列表这个接口只要没报错你就直接去下一步就行了
if (CollUtil.isEmpty(addAuthWorkerIds) && CollUtil.isEmpty(deleteAuthWorkerIds)) {
log.error("无权限添加或删除,跳过");
return null;
}
if (CollUtil.isNotEmpty(addAuthWorkerIds)) {
addAuthByWorkerList(project, devSnToIscDevSnMap, devSnToJoEntry, addAuthWorkerIds);
addAuthByWorkerList(project, addAuthWorkerIds, iscDevSnObj);
}
if (CollUtil.isNotEmpty(deleteAuthWorkerIds)) {
deleteAuthByWorkerList(project, devSnToIscDevSnMap, devSnToJoEntry, deleteAuthWorkerIds);
deleteAuthByWorkerList(project, deleteAuthWorkerIds, iscDevSnObj);
}
//然后调用根据出入权限配置快捷下载设备列表添加权限配置+快捷下发这是一个流程你添加了几个权限下发成功之后就清零了
JSONObject daJo = HikvisionUtil.downloadAuth(project, getQueryDownloadProgressParam(devSnToJoEntry, devSnToIscDevSnMap));
JSONObject daJo = HikvisionUtil.downloadAuth(project, getQueryDownloadProgressParam(iscDevSnObj));
JSONObject daRtJo = HikvisionUtil.getJsonObjectData(daJo);
//然后调用查询下载任务进度上面那个的任务
int totalPercent = 0;
@ -884,7 +846,7 @@ public class AsyncHikvision {
} while (totalPercent != 100);
//权限下发后进度100后查询权限条目列表人员列表设备列表接口去查返回参数有权限状态返回已下载的就是有权限
List<String> workerIds = devSnToJoEntry.getValue().stream().map(jsonObject -> jsonObject.getString("workerId")).collect(Collectors.toList());
JSONArray qaiList = queryAuthItemByWorkerList(project, workerIds, devSnToJoEntry, devSnToIscDevSnMap);
JSONArray qaiList = queryAuthItemByWorkerList(project, workerIds, getDevRqParam(iscDevSnObj));
Set<String> rtWorkerIdSet;
if (CollUtil.isNotEmpty(qaiList)) {
for (int i = 0; i < qaiList.size(); i++) {
@ -911,7 +873,7 @@ public class AsyncHikvision {
noticeService.addUserNotice(noticeUserId,
"人员下发设备提醒", StrUtil.format("[{}]取消下发到[{}]{}",
workerIdMap.get(workerId).getWorkerName(),
devSnMap.get(devSn).getDevName(),
dev.getDevName(),
"成功"),
"1");
}
@ -921,25 +883,34 @@ public class AsyncHikvision {
log.error("批量下发权限失败:", e);
hikvisionCall.updateAllFailStatusIfNullForAuth(projectSn, new ArrayList<>(workerIdMap.values()), 1, 1);
hikvisionCall.updateAllFailStatusIfNullForAuth(projectSn, new ArrayList<>(workerIdMap.values()), 1, 3);
sendExcNotice(e, workerList, dev, projectSn, flowStartUser, deleteAuthWorkerIds);
List<String> dawis = BeanUtil.copyToList(deleteAuthWorkerIds, String.class);
if (CollUtil.isNotEmpty(deleteSimpleAuthWorkerIds)) {
dawis.addAll(deleteSimpleAuthWorkerIds);
}
sendExcNotice(e, workerList, dev, projectSn, flowStartUser, dawis);
}
return null;
}
@Async("hkSimpleAuthExecutor")
public Future simpleDeletePersonAuthAsync(String workerId, UfaceDev dev, ProjectInfoExtVo project, Long flowStartUser, Map<String, WorkerInfo> workerIdMap, JSONObject iscDevSnObj) throws Exception {
hikvisionCall.simpleDeletePersonAuth(workerId, dev, project, flowStartUser, workerIdMap, iscDevSnObj);
return null;
}
/**
* 为人员列表查询权限列表
*
* @param project
* @param workerIds
* @param devSnToJoEntry
* @param devSnToIscDevSnMap
* @param devRqParam
* @return
* @throws Exception
*/
private JSONArray queryAuthItemByWorkerList(ProjectInfoExtVo project, List<String> workerIds, Map.Entry<String, List<JSONObject>> devSnToJoEntry, Map<String, JSONObject> devSnToIscDevSnMap) throws Exception {
private JSONArray queryAuthItemByWorkerList(ProjectInfoExtVo project, List<String> workerIds, @NotNull List<JSONObject> devRqParam) throws Exception {
JSONArray rtJa = new JSONArray();
for (List<String> splitList : CollUtil.splitList(workerIds, MAX_PAGE_SIZE)) {
JSONObject qaiJo = HikvisionUtil.queryAuthItem(project, getQueryAuthItemParam(devSnToJoEntry, devSnToIscDevSnMap, splitList));
JSONObject qaiJo = HikvisionUtil.queryAuthItem(project, getQueryAuthItemParam(splitList, devRqParam));
JSONObject qaiRtJo = HikvisionUtil.getJsonObjectData(qaiJo);
JSONArray qaiList = qaiRtJo.getJSONArray("list");
if (CollUtil.isNotEmpty(qaiList)) {
@ -953,14 +924,13 @@ public class AsyncHikvision {
* 为人员列表删除权限
*
* @param project
* @param devSnToIscDevSnMap
* @param devSnToJoEntry
* @param deleteAuthWorkerIds
* @param jsonObject
* @throws Exception
*/
private void deleteAuthByWorkerList(ProjectInfoExtVo project, Map<String, JSONObject> devSnToIscDevSnMap, Map.Entry<String, List<JSONObject>> devSnToJoEntry, List<String> deleteAuthWorkerIds) throws Exception {
private void deleteAuthByWorkerList(ProjectInfoExtVo project, List<String> deleteAuthWorkerIds, JSONObject jsonObject) throws Exception {
for (List<String> splitWorkerIds : CollUtil.splitList(deleteAuthWorkerIds, MAX_PAGE_SIZE)) {
JSONObject jo = HikvisionUtil.deleteAuth(project, getAddOrDeleteAuthParam(devSnToJoEntry, splitWorkerIds, devSnToIscDevSnMap));
JSONObject jo = HikvisionUtil.deleteAuth(project, getAddOrDeleteAuthParam(splitWorkerIds, jsonObject));
HikvisionUtil.getJsonObjectData(jo);
}
}
@ -969,14 +939,13 @@ public class AsyncHikvision {
* 为人员列表添加权限
*
* @param project
* @param devSnToIscDevSnMap
* @param devSnToJoEntry
* @param addAuthWorkerIds
* @param jsonObject
* @throws Exception
*/
private void addAuthByWorkerList(ProjectInfoExtVo project, Map<String, JSONObject> devSnToIscDevSnMap, Map.Entry<String, List<JSONObject>> devSnToJoEntry, List<String> addAuthWorkerIds) throws Exception {
private void addAuthByWorkerList(ProjectInfoExtVo project, List<String> addAuthWorkerIds, JSONObject jsonObject) throws Exception {
for (List<String> splitWorkerIds : CollUtil.splitList(addAuthWorkerIds, MAX_PAGE_SIZE)) {
JSONObject jo = HikvisionUtil.addAuth(project, getAddOrDeleteAuthParam(devSnToJoEntry, splitWorkerIds, devSnToIscDevSnMap));
JSONObject jo = HikvisionUtil.addAuth(project, getAddOrDeleteAuthParam(splitWorkerIds, jsonObject));
HikvisionUtil.getJsonObjectData(jo);
}
}
@ -1049,68 +1018,60 @@ public class AsyncHikvision {
/**
* 获取添加或删除权限的参数
*
* @param entry
* @param workerIds
* @param devSnToIscDevSnMap
* @param jsonObject
* @return
*/
@NotNull
private JSONObject getAddOrDeleteAuthParam(Map.Entry<String, List<JSONObject>> entry, List<String> workerIds, Map<String, JSONObject> devSnToIscDevSnMap) {
private JSONObject getAddOrDeleteAuthParam(List<String> workerIds, JSONObject jsonObject) {
JSONObject aaJo = new JSONObject();
aaJo.put("personDatas", Collections.singletonList(new MapBuilder<String, Object>()
.put("indexCodes", workerIds)
.put("personDataType", "person")
.build()));
aaJo.put("resourceInfos", getDevRqParam(entry, devSnToIscDevSnMap));
aaJo.put("resourceInfos", getDevRqParam(jsonObject));
return aaJo;
}
/**
* 获取删除权限配置接口的设备请求的参数
*
* @param entry
* @param devSnToIscDevSnMap
* @param jsonObject
* @return
*/
@NotNull
private List<JSONObject> getDevRqParam(Map.Entry<String, List<JSONObject>> entry, Map<String, JSONObject> devSnToIscDevSnMap) {
private List<JSONObject> getDevRqParam(JSONObject jsonObject) {
return Collections.singletonList(new JoBuilder()
.put("resourceIndexCode", devSnToIscDevSnMap.get(entry.getKey()).getString("parentIndexCode"))
.put("resourceIndexCode", jsonObject.getString("parentIndexCode"))
.put("resourceType", "acsDevice")
.put("channelNos", Collections.singletonList(devSnToIscDevSnMap.get(entry.getKey()).getString("channelNo")))
.put("channelNos", Collections.singletonList(jsonObject.getString("channelNo")))
.build());
}
/**
* 获取根据出入权限配置快捷下载接口的请求的参数
*
* @param entry
* @param devSnToIscDevSnMap
* @param jsonObject
* @return
*/
private JSONObject getQueryDownloadProgressParam(Map.Entry<String, List<JSONObject>> entry, Map<String, JSONObject> devSnToIscDevSnMap) {
private JSONObject getQueryDownloadProgressParam(JSONObject jsonObject) {
JSONObject aaJo = new JSONObject();
aaJo.put("taskType", 4);
aaJo.put("resourceInfos", getDevRqParam(entry, devSnToIscDevSnMap));
aaJo.put("resourceInfos", getDevRqParam(jsonObject));
return aaJo;
}
/**
* 获取查询权限条目列表的请求参数
*
* @param entry
* @param devSnToIscDevSnMap
* @param workerIds
* @param devRqParam
* @return
*/
private JSONObject getQueryAuthItemParam(Map.Entry<String, List<JSONObject>> entry, Map<String, JSONObject> devSnToIscDevSnMap, List<String> workerIds) {
private JSONObject getQueryAuthItemParam(List<String> workerIds, @NotNull List<JSONObject> devRqParam) {
JSONObject aaJo = new JSONObject();
aaJo.put("personIds", workerIds);
aaJo.put("resourceInfos", Collections.singletonList(new JoBuilder()
.put("resourceIndexCode", devSnToIscDevSnMap.get(entry.getKey()).getString("parentIndexCode"))
.put("resourceType", "acsDevice")
.put("channelNos", Collections.singletonList(devSnToIscDevSnMap.get(entry.getKey()).getString("channelNo")))
.build()));
aaJo.put("resourceInfos", devRqParam);
aaJo.put("queryType", "acsDevice");
aaJo.put("pageNo", 1);
aaJo.put("pageSize", MAX_PAGE_SIZE);

View File

@ -339,7 +339,7 @@ public class AsyncConfig {
*
* @return
*/
@Bean("hikvisionExecutor")
@Bean("hkSimpleAuthExecutor")
public ThreadPoolTaskExecutor hikvisionExecutor() {
MdcThreadPoolTaskExecutor executor = new MdcThreadPoolTaskExecutor();
/** 核心线程数(默认线程数) */

View File

@ -54,6 +54,10 @@ public interface Cts {
* 1添加权限2删除权限
*/
String IS_ADD_AUTH = "isAddAuth";
/**
* 是否需要简单删除权限
*/
String IS_SIMPLE_DELETE_AUTH = "isSimpleDeleteAuth";
/**
* 1成功
*/