Commit 9da261cead9b3bb5fca92cea827537127125249b

Authored by 芯火源
1 parent 0916e846

fix: 事务逻辑手动回滚

1、事务问题引起设备无法上线问题。
2、新建设备TK异常时,删除TB设备
3、新建产品TK异常时,删除TB设备配置
... ... @@ -11,7 +11,6 @@ import lombok.extern.slf4j.Slf4j;
11 11 import org.apache.commons.lang3.StringUtils;
12 12 import org.springframework.http.ResponseEntity;
13 13 import org.springframework.security.access.prepost.PreAuthorize;
14   -import org.springframework.transaction.annotation.Transactional;
15 14 import org.springframework.validation.annotation.Validated;
16 15 import org.springframework.web.bind.annotation.*;
17 16 import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;
... ... @@ -64,7 +63,6 @@ public class TkDeviceController extends BaseController {
64 63 private final GatewayNotificationsService gatewayNotificationsService;
65 64
66 65 @PostMapping
67   - @Transactional
68 66 @ApiOperation("创建|编辑")
69 67 @PreAuthorize(
70 68 "@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:device:post','api:yt:device:update'})")
... ... @@ -78,51 +76,68 @@ public class TkDeviceController extends BaseController {
78 76 String gatewayId = deviceDTO.getGatewayId();
79 77 DeviceDTO gateWay = null;
80 78 if (StringUtils.isNotEmpty(gatewayId)) {
81   - gateWay =
82   - tkdeviceService.checkDeviceByTenantIdAndDeviceId(currentTenantId, gatewayId);
  79 + gateWay = tkdeviceService.checkDeviceByTenantIdAndDeviceId(currentTenantId, gatewayId);
83 80 if (null == gateWay) {
84 81 throw new TkDataValidationException(
85 82 ErrorMessage.DEVICE_NOT_EXISTENCE_IN_TENANT.getMessage());
86 83 }
87 84 }
88   - /**
89   - * 子设备编辑业务逻辑: 设备地址码必须同时设置到附加信息字段内。 1、新增或编辑网关和直连设备 2、新增网关子设备 3、编辑网关子设备时,关联关系已存在(未切换网关)
90   - * 4、编辑网关子设备时,关联关系不存在(切换网关) 5、编辑网关子设备时,修改其它设备信息,例如:设备名称等。
91   - */
92   - Device tbDevice = buildTbDeviceFromDeviceDTO(getCurrentUser().getTenantId(), deviceDTO);
93   - DeviceId selfTbId = updateTbDevice(tbDevice, deviceDTO.getDeviceToken());
94   - String selfTbIdStr = selfTbId.getId().toString();
95   - deviceDTO.setTbDeviceId(selfTbIdStr);
96   -
97   - if (selfTbIdStr != null
98   - && deviceDTO.getDeviceType().equals(DeviceTypeEnum.SENSOR)
99   - && StringUtils.isNotEmpty(gatewayId)) {
100   - boolean relationNotMatched = true;
101   -
102   - EntityId slaveId = EntityIdFactory.getByTypeAndId("DEVICE", selfTbIdStr);
103   - List<EntityRelationInfo> relations =
104   - relationService.findInfoByTo(getTenantId(), slaveId, RelationTypeGroup.COMMON).get();
105   -
106   - for (EntityRelationInfo relationInfo : relations) {
107   - if (!FastIotConstants.Relation.relationType.equals(relationInfo.getType())) {
108   - continue;
  85 + DeviceDTO newDeviceDTO = null;
  86 + boolean created = StringUtils.isBlank(deviceDTO.getId());
  87 + Device savedDevice = null;
  88 + String selfTbIdStr = null;
  89 + try {
  90 + /**
  91 + * 子设备编辑业务逻辑: 设备地址码必须同时设置到附加信息字段内。 1、新增或编辑网关和直连设备 2、新增网关子设备 3、编辑网关子设备时,关联关系已存在(未切换网关)
  92 + * 4、编辑网关子设备时,关联关系不存在(切换网关) 5、编辑网关子设备时,修改其它设备信息,例如:设备名称等。
  93 + */
  94 + Device tbDevice = buildTbDeviceFromDeviceDTO(getCurrentUser().getTenantId(), deviceDTO);
  95 + savedDevice = updateTbDevice(tbDevice, deviceDTO.getDeviceToken(), created);
  96 + selfTbIdStr = savedDevice.getId().getId().toString();
  97 + deviceDTO.setTbDeviceId(selfTbIdStr);
  98 +
  99 + if (selfTbIdStr != null
  100 + && deviceDTO.getDeviceType().equals(DeviceTypeEnum.SENSOR)
  101 + && StringUtils.isNotEmpty(gatewayId)) {
  102 + boolean relationNotMatched = true;
  103 +
  104 + EntityId slaveId = EntityIdFactory.getByTypeAndId("DEVICE", selfTbIdStr);
  105 + List<EntityRelationInfo> relations =
  106 + relationService.findInfoByTo(getTenantId(), slaveId, RelationTypeGroup.COMMON).get();
  107 +
  108 + for (EntityRelationInfo relationInfo : relations) {
  109 + if (!FastIotConstants.Relation.relationType.equals(relationInfo.getType())) {
  110 + continue;
  111 + }
  112 + if (relationInfo.getFrom().getId().toString().equals(gateWay.getTbDeviceId())) {
  113 + relationNotMatched = false;
  114 + } else {
  115 + relationService.deleteRelation(getTenantId(), relationInfo);
  116 + sendRelationNotificationMsg(
  117 + getTenantId(), relationInfo, EdgeEventActionType.RELATION_DELETED);
  118 + }
109 119 }
110   - if (relationInfo.getFrom().getId().toString().equals(gateWay.getTbDeviceId())) {
111   - relationNotMatched = false;
112   - } else {
113   - relationService.deleteRelation(getTenantId(), relationInfo);
114   - sendRelationNotificationMsg(
115   - getTenantId(), relationInfo, EdgeEventActionType.RELATION_DELETED);
  120 +
  121 + if (relationNotMatched) {
  122 + addRelation(getTenantId(), gateWay.getTbDeviceId(), selfTbIdStr);
116 123 }
117 124 }
118 125
119   - if (relationNotMatched) {
120   - addRelation(getTenantId(), gateWay.getTbDeviceId(), selfTbIdStr);
  126 + newDeviceDTO =
  127 + tkdeviceService.insertOrUpdate(getCurrentUser().getCurrentTenantId(), deviceDTO);
  128 + } catch (Exception e) {
  129 + if (created) {
  130 + logEntityAction(
  131 + getCurrentUser(),
  132 + savedDevice.getId(),
  133 + savedDevice,
  134 + savedDevice.getCustomerId(),
  135 + created ? ActionType.ADDED : ActionType.UPDATED,
  136 + e);
  137 + deleteTbDevice(selfTbIdStr);
  138 + throw handleException(e);
121 139 }
122 140 }
123   -
124   - DeviceDTO newDeviceDTO =
125   - tkdeviceService.insertOrUpdate(getCurrentUser().getCurrentTenantId(), deviceDTO);
126 141 return ResponseEntity.ok(newDeviceDTO);
127 142 }
128 143
... ... @@ -133,10 +148,10 @@ public class TkDeviceController extends BaseController {
133 148 return ResponseEntity.ok(result);
134 149 }
135 150
136   - private DeviceId updateTbDevice(Device tbDevice, TkCredentialsDto formCredentials)
  151 + private Device updateTbDevice(
  152 + Device tbDevice, TkCredentialsDto formCredentials, boolean created)
137 153 throws ThingsboardException {
138 154 Device oldDevice = null;
139   - boolean created = tbDevice.getId() == null;
140 155 if (!created) {
141 156 oldDevice = checkDeviceId(tbDevice.getId(), Operation.WRITE);
142 157 } else {
... ... @@ -147,6 +162,7 @@ public class TkDeviceController extends BaseController {
147 162 tbClusterService.onDeviceUpdated(savedDevice, oldDevice);
148 163 DeviceId tbDeviceId = savedDevice.getId();
149 164 DeviceCredentials deviceCredentials = null;
  165 + try {
150 166 logEntityAction(
151 167 getCurrentUser(),
152 168 savedDevice.getId(),
... ... @@ -184,7 +200,18 @@ public class TkDeviceController extends BaseController {
184 200 null,
185 201 deviceCredentials);
186 202 }
187   - return tbDeviceId;
  203 + } catch (Exception e) {
  204 + logEntityAction(
  205 + emptyId(EntityType.DEVICE),
  206 + null,
  207 + null,
  208 + ActionType.CREDENTIALS_UPDATED,
  209 + e,
  210 + deviceCredentials);
  211 + deleteTbDevice(tbDeviceId.getId().toString());
  212 + throw handleException(e);
  213 + }
  214 + return savedDevice;
188 215 }
189 216
190 217 @GetMapping("{id}")
... ... @@ -482,6 +509,7 @@ public class TkDeviceController extends BaseController {
482 509 result.setMessage(str);
483 510 return result;
484 511 }
  512 +
485 513 @GetMapping({"/attributes/{deviceProfileId}"})
486 514 @ApiOperation("获取设备的属性")
487 515 public ResponseEntity<JsonNode> getDeviceAttributes(
... ...
... ... @@ -7,13 +7,9 @@ import lombok.RequiredArgsConstructor;
7 7 import org.apache.commons.lang3.StringUtils;
8 8 import org.springframework.http.ResponseEntity;
9 9 import org.springframework.security.access.prepost.PreAuthorize;
10   -import org.springframework.transaction.annotation.Transactional;
11 10 import org.springframework.validation.annotation.Validated;
12 11 import org.springframework.web.bind.annotation.*;
13   -import org.thingsboard.server.common.data.DeviceProfile;
14   -import org.thingsboard.server.common.data.DeviceProfileProvisionType;
15   -import org.thingsboard.server.common.data.DeviceProfileType;
16   -import org.thingsboard.server.common.data.DeviceTransportType;
  12 +import org.thingsboard.server.common.data.*;
17 13 import org.thingsboard.server.common.data.audit.ActionType;
18 14 import org.thingsboard.server.common.data.device.profile.*;
19 15 import org.thingsboard.server.common.data.edge.EdgeEventActionType;
... ... @@ -51,12 +47,11 @@ public class TkDeviceProfileController extends BaseController {
51 47 private final TkDeviceProfileService tkDeviceProfileService;
52 48
53 49 @PostMapping()
54   - @Transactional
55 50 @PreAuthorize(
56   - "@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:deviceProfile:post','api:yt:deviceProfile:update'})")
  51 + "@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:deviceProfile:post','api:yt:deviceProfile:update'})")
57 52 @ApiOperation("创建 | 编辑")
58 53 public ResponseEntity<DeviceProfileDTO> saveDeviceProfile(
59   - @RequestBody DeviceProfileDTO deviceProfileDTO) throws ThingsboardException {
  54 + @RequestBody DeviceProfileDTO deviceProfileDTO) throws ThingsboardException {
60 55
61 56 boolean created = deviceProfileDTO.getId() == null;
62 57
... ... @@ -64,10 +59,22 @@ public class TkDeviceProfileController extends BaseController {
64 59 String tenantId = getCurrentUser().getCurrentTenantId();
65 60 deviceProfileDTO.setTenantId(tenantId);
66 61 DeviceProfile tbDeviceProfile = buildTbDeviceProfileFromDeviceProfileDTO(deviceProfileDTO);
  62 + DeviceProfile saveDeviceProfile = null;
  63 + try{
  64 + saveDeviceProfile = updateTbDeviceProfile(tbDeviceProfile);
  65 + deviceProfileDTO.setTbProfileId(saveDeviceProfile.getId().toString());
  66 + tkDeviceProfileService.insertOrUpdate(deviceProfileDTO);
  67 + }catch (Exception e){
  68 + if (created) {
  69 + logEntityAction(emptyId(EntityType.DEVICE_PROFILE), saveDeviceProfile,
  70 + null, created ? ActionType.ADDED : ActionType.UPDATED, e);
  71 + deviceProfileService.deleteDeviceProfile(getTenantId(), saveDeviceProfile.getId());
  72 + tbClusterService.onDeviceProfileDelete(saveDeviceProfile, null);
  73 + tbClusterService.broadcastEntityStateChangeEvent(saveDeviceProfile.getTenantId(), saveDeviceProfile.getId(), ComponentLifecycleEvent.DELETED);
  74 + throw handleException(e);
  75 + }
  76 + }
67 77
68   - DeviceProfile saveDeviceProfile = updateTbDeviceProfile(tbDeviceProfile);
69   - deviceProfileDTO.setTbProfileId(saveDeviceProfile.getId().toString());
70   - tkDeviceProfileService.insertOrUpdate(deviceProfileDTO);
71 78
72 79 return ResponseEntity.ok(deviceProfileDTO);
73 80 }
... ... @@ -75,24 +82,24 @@ public class TkDeviceProfileController extends BaseController {
75 82 @GetMapping("{id}")
76 83 @ApiOperation("详情")
77 84 @PreAuthorize(
78   - "@check.checkPermissions({'TENANT_ADMIN','CUSTOMER_USER'},{'api:yt:deviceProfile:get'})")
  85 + "@check.checkPermissions({'TENANT_ADMIN','CUSTOMER_USER'},{'api:yt:deviceProfile:get'})")
79 86 public ResponseEntity<DeviceProfileDTO> getDevice(@PathVariable("id") String id)
80   - throws ThingsboardException {
  87 + throws ThingsboardException {
81 88 return ResponseEntity.ok(
82   - tkDeviceProfileService.getDeviceProfile(getCurrentUser().getCurrentTenantId(), id));
  89 + tkDeviceProfileService.getDeviceProfile(getCurrentUser().getCurrentTenantId(), id));
83 90 }
84 91
85 92 @GetMapping(params = {PAGE_SIZE, PAGE})
86 93 @ApiOperation("查询")
87 94 @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN','CUSTOMER_USER'},{})")
88 95 public TkPageData<DeviceProfileDTO> pageDeviceProfile(
89   - @RequestParam(PAGE_SIZE) int pageSize,
90   - @RequestParam(PAGE) int page,
91   - @RequestParam(value = "name", required = false) String name,
92   - @RequestParam(value = "transportType", required = false) String transportType,
93   - @RequestParam(value = ORDER_FILED, required = false) String orderBy,
94   - @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType)
95   - throws ThingsboardException {
  96 + @RequestParam(PAGE_SIZE) int pageSize,
  97 + @RequestParam(PAGE) int page,
  98 + @RequestParam(value = "name", required = false) String name,
  99 + @RequestParam(value = "transportType", required = false) String transportType,
  100 + @RequestParam(value = ORDER_FILED, required = false) String orderBy,
  101 + @RequestParam(value = ORDER_TYPE, required = false) OrderTypeEnum orderType)
  102 + throws ThingsboardException {
96 103 Map<String, Object> queryMap = new HashMap<>();
97 104 queryMap.put(PAGE, page);
98 105 queryMap.put(PAGE_SIZE, pageSize);
... ... @@ -109,17 +116,17 @@ public class TkDeviceProfileController extends BaseController {
109 116 @ApiOperation("选项列表")
110 117 @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN','CUSTOMER_USER'},{})")
111 118 public ResponseEntity listDeviceProfile(
112   - @ApiParam(value = "设备类型") @RequestParam(value = "deviceType", required = false)
  119 + @ApiParam(value = "设备类型") @RequestParam(value = "deviceType", required = false)
113 120 DeviceTypeEnum deviceType)
114   - throws ThingsboardException {
  121 + throws ThingsboardException {
115 122 List<DeviceProfileDTO> results;
116 123 String tenantId = getCurrentUser().getCurrentTenantId();
117 124 if (getCurrentUser().isTenantAdmin()) {
118 125 results = tkDeviceProfileService.findDeviceProfile(tenantId, null,deviceType);
119 126 } else {
120 127 results =
121   - tkDeviceProfileService.findCustomerDeviceProfiles(
122   - tenantId, getCurrentUser().getCustomerId(),deviceType);
  128 + tkDeviceProfileService.findCustomerDeviceProfiles(
  129 + tenantId, getCurrentUser().getCustomerId(),deviceType);
123 130 }
124 131
125 132 return ResponseEntity.ok(results);
... ... @@ -129,7 +136,7 @@ public class TkDeviceProfileController extends BaseController {
129 136 @ApiOperation("删除")
130 137 @PreAuthorize("@check.checkPermissions({'TENANT_ADMIN'},{'api:yt:deviceProfile:delete'})")
131 138 public void deleteDeviceProfiles(@Validated({DeleteGroup.class}) @RequestBody DeleteDTO deleteDTO)
132   - throws ThingsboardException {
  139 + throws ThingsboardException {
133 140 String tenantId = getCurrentUser().getCurrentTenantId();
134 141 tkDeviceProfileService.checkDeviceProfiles(tenantId, deleteDTO.getIds());
135 142
... ... @@ -142,8 +149,8 @@ public class TkDeviceProfileController extends BaseController {
142 149
143 150 private void deleteTbDeviceProfile(String profileId) throws ThingsboardException {
144 151 DeviceProfileDTO dto =
145   - tkDeviceProfileService.findDeviceProfileById(
146   - getCurrentUser().getCurrentTenantId(), profileId);
  152 + tkDeviceProfileService.findDeviceProfileById(
  153 + getCurrentUser().getCurrentTenantId(), profileId);
147 154 if (null != dto) {
148 155 DeviceProfileId deviceProfileId = new DeviceProfileId(toUUID(dto.getTbProfileId()));
149 156 DeviceProfile deviceProfile = checkDeviceProfileId(deviceProfileId, Operation.DELETE);
... ... @@ -151,10 +158,10 @@ public class TkDeviceProfileController extends BaseController {
151 158
152 159 tbClusterService.onDeviceProfileDelete(deviceProfile, null);
153 160 tbClusterService.broadcastEntityStateChangeEvent(
154   - deviceProfile.getTenantId(), deviceProfile.getId(), ComponentLifecycleEvent.DELETED);
  161 + deviceProfile.getTenantId(), deviceProfile.getId(), ComponentLifecycleEvent.DELETED);
155 162
156 163 logEntityAction(
157   - deviceProfileId, deviceProfile, null, ActionType.DELETED, null, deviceProfileId);
  164 + deviceProfileId, deviceProfile, null, ActionType.DELETED, null, deviceProfileId);
158 165
159 166 sendEntityNotificationMsg(getTenantId(), deviceProfile.getId(), EdgeEventActionType.DELETED);
160 167 }
... ... @@ -163,9 +170,9 @@ public class TkDeviceProfileController extends BaseController {
163 170 @GetMapping("/me/default")
164 171 @ApiOperation("默认设备配置")
165 172 public ResponseEntity<DeviceProfile> findCurrentTenantDeviceProfiles()
166   - throws ThingsboardException {
  173 + throws ThingsboardException {
167 174 DeviceProfile result =
168   - deviceProfileService.findDefaultDeviceProfile(getCurrentUser().getTenantId());
  175 + deviceProfileService.findDefaultDeviceProfile(getCurrentUser().getTenantId());
169 176 return ResponseEntity.ok(result);
170 177 }
171 178
... ... @@ -192,21 +199,21 @@ public class TkDeviceProfileController extends BaseController {
192 199 * @return 封装好的TBDeviceProfile
193 200 */
194 201 private DeviceProfile buildTbDeviceProfileFromDeviceProfileDTO(DeviceProfileDTO deviceProfileDTO)
195   - throws ThingsboardException {
  202 + throws ThingsboardException {
196 203 DeviceProfile tbDeviceProfile = new DeviceProfile();
197 204 if (StringUtils.isNotBlank(deviceProfileDTO.getId())) {
198 205 DeviceProfileDTO findDeviceProfile =
199   - tkDeviceProfileService.findDeviceProfileById(
200   - getCurrentUser().getCurrentTenantId(), deviceProfileDTO.getId());
  206 + tkDeviceProfileService.findDeviceProfileById(
  207 + getCurrentUser().getCurrentTenantId(), deviceProfileDTO.getId());
201 208 if (StringUtils.isNotEmpty(findDeviceProfile.getTbProfileId())) {
202 209 UUID profileId = UUID.fromString(findDeviceProfile.getTbProfileId());
203 210 tbDeviceProfile.setId(new DeviceProfileId(profileId));
204 211 tbDeviceProfile.setCreatedTime(
205   - deviceProfileDTO.getCreateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());
  212 + deviceProfileDTO.getCreateTime().toInstant(ZoneOffset.of("+8")).toEpochMilli());
206 213 }
207 214 } else {
208 215 tbDeviceProfile.setCreatedTime(
209   - LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
  216 + LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
210 217 }
211 218 tbDeviceProfile.setName(deviceProfileDTO.getName());
212 219 tbDeviceProfile.setImage(deviceProfileDTO.getImage());
... ... @@ -221,9 +228,9 @@ public class TkDeviceProfileController extends BaseController {
221 228 if (StringUtils.isNotBlank(chainStr)) {
222 229 UUID chainId = UUID.fromString(chainStr);
223 230 RuleChain chain =
224   - ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, new RuleChainId(chainId));
  231 + ruleChainService.findRuleChainById(TenantId.SYS_TENANT_ID, new RuleChainId(chainId));
225 232 if (chain == null
226   - || !deviceProfileDTO.getTenantId().equals(chain.getTenantId().getId().toString())) {
  233 + || !deviceProfileDTO.getTenantId().equals(chain.getTenantId().getId().toString())) {
227 234 throw new TkDataValidationException(ErrorMessage.RULE_CHAIN_NOT_ENABLE.getMessage());
228 235 }
229 236 tbDeviceProfile.setDefaultRuleChainId(new RuleChainId(chainId));
... ... @@ -242,7 +249,7 @@ public class TkDeviceProfileController extends BaseController {
242 249 }
243 250
244 251 tbDeviceProfile.setProfileData(
245   - buildDeviceProfileData(transportType, deviceProfileDTO.getProfileData()));
  252 + buildDeviceProfileData(transportType, deviceProfileDTO.getProfileData()));
246 253 return tbDeviceProfile;
247 254 }
248 255 }
... ...