瀏覽代碼

增加第三方接口-新增修改用户积分接口

sunxbiao 1 年之前
父節點
當前提交
e03783ec27

+ 46 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/advice/GlobalExceptionHandler.java

@@ -0,0 +1,46 @@
1
+package com.bjtdba.userCenter.advice;
2
+
3
+
4
+import com.bjtdba.userCenter.dto.response.common.ApiResponse;
5
+import com.bjtdba.userCenter.exception.BusinessException;
6
+import org.springframework.http.HttpStatus;
7
+import org.springframework.validation.BindException;
8
+import org.springframework.web.bind.annotation.ExceptionHandler;
9
+import org.springframework.web.bind.annotation.ResponseStatus;
10
+import org.springframework.web.bind.annotation.RestControllerAdvice;
11
+
12
+@RestControllerAdvice
13
+public class GlobalExceptionHandler {
14
+
15
+    /**
16
+     * 处理业务异常
17
+     */
18
+    @ExceptionHandler(BusinessException.class)
19
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
20
+    public ApiResponse<Void> handleBusinessException(BusinessException e) {
21
+        return ApiResponse.error(e.getCode(), e.getMessage());
22
+    }
23
+
24
+    /**
25
+     * 处理参数校验异常
26
+     */
27
+    @ExceptionHandler(BindException.class)
28
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
29
+    public ApiResponse<Void> handleValidationException(BindException e) {
30
+        String errorMsg = e.getBindingResult().getFieldErrors().stream()
31
+                .map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage())
32
+                .findFirst()
33
+                .orElse("参数校验失败");
34
+        return ApiResponse.error(400, errorMsg);
35
+    }
36
+
37
+    /**
38
+     * 处理其他未捕获异常
39
+     */
40
+    @ExceptionHandler(Exception.class)
41
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
42
+    public ApiResponse<Void> handleException(Exception e) {
43
+        // 生产环境应记录日志而不是返回详细错误信息
44
+        return ApiResponse.error(500, "系统繁忙,请稍后再试");
45
+    }
46
+}

+ 12 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/controller/UserController.java

@@ -6,6 +6,9 @@ import com.bjtdba.entity.userCenter.UserAddress;
6 6
 import com.bjtdba.entity.userCenter.UserBill;
7 7
 import com.bjtdba.entity.userCenter.UserCertification;
8 8
 import com.bjtdba.userCenter.dto.request.GetUserListRequest;
9
+import com.bjtdba.userCenter.dto.request.UserScoreModifyRequest;
10
+import com.bjtdba.userCenter.dto.response.UserScoreModifyResponse;
11
+import com.bjtdba.userCenter.dto.response.common.ApiResponse;
9 12
 import com.bjtdba.userCenter.dto.response.common.PageResult;
10 13
 import com.bjtdba.userCenter.dto.response.UserDTO;
11 14
 import com.bjtdba.userCenter.service.UserAddressService;
@@ -17,6 +20,7 @@ import com.bjtdba.userCenter.vo.UserInfoVo;
17 20
 import com.bjtdba.utils.ResponseUtil;
18 21
 import org.springframework.beans.factory.annotation.Autowired;
19 22
 import org.springframework.http.ResponseEntity;
23
+import org.springframework.validation.annotation.Validated;
20 24
 import org.springframework.web.bind.annotation.*;
21 25
 
22 26
 import javax.validation.Valid;
@@ -603,4 +607,12 @@ public class UserController {
603 607
     public ResponseEntity<PageResult<UserDTO>> getUserList(@Valid GetUserListRequest request) {
604 608
         return ResponseEntity.ok(userService.getUserList(request));
605 609
     }
610
+
611
+    @PostMapping("/{uid}/score")
612
+    public ApiResponse<UserScoreModifyResponse> modifyUserScore(
613
+            @PathVariable Integer uid,
614
+            @Validated @RequestBody UserScoreModifyRequest request) {
615
+        request.setUid(uid); // 确保路径参数和body一致
616
+        return ApiResponse.success(userService.modifyUserScore(request));
617
+    }
606 618
 }

+ 5 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/dao/UserDao.java

@@ -54,4 +54,9 @@ public interface UserDao {
54 54
             @Param("uid") Long uid,
55 55
             @Param("status") Integer status
56 56
     );
57
+
58
+    UserEntity getUserScoreByUidForUpdate(@Param("uid") Integer uid);
59
+
60
+    int updateUserScore(@Param("uid") Integer uid,
61
+                        @Param("newScore") BigDecimal newScore);
57 62
 }

+ 3 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/dao/UserSignScoreDao.java

@@ -1,6 +1,7 @@
1 1
 package com.bjtdba.userCenter.dao;
2 2
 
3 3
 import com.bjtdba.entity.userCenter.UserSignScore;
4
+import com.bjtdba.userCenter.entity.UserSignScoreEntity;
4 5
 import org.apache.ibatis.annotations.Mapper;
5 6
 import org.apache.ibatis.annotations.Param;
6 7
 import org.springframework.stereotype.Repository;
@@ -90,5 +91,7 @@ public interface UserSignScoreDao {
90 91
      */
91 92
     int deleteById(Integer id);
92 93
 
94
+    int insertByEntity(UserSignScoreEntity record);
95
+
93 96
 }
94 97
 

+ 26 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/dto/request/UserScoreModifyRequest.java

@@ -0,0 +1,26 @@
1
+package com.bjtdba.userCenter.dto.request;
2
+
3
+import lombok.Data;
4
+import javax.validation.constraints.*;
5
+import java.math.BigDecimal;
6
+
7
+@Data
8
+public class UserScoreModifyRequest {
9
+    private Integer uid;
10
+
11
+    @NotNull(message = "积分类型不能为空")
12
+    @Min(value = 1, message = "积分类型取值错误")
13
+    @Max(value = 2, message = "积分类型取值错误")
14
+    private Integer pm; // 1-收入 2-支出
15
+
16
+    @NotNull(message = "积分值不能为空")
17
+    @DecimalMin(value = "0.01", message = "积分值必须大于0")
18
+    private BigDecimal rewardScore;
19
+
20
+    @NotBlank(message = "订单ID不能为空")
21
+    @Size(max = 255, message = "订单ID长度超限")
22
+    private String orderId;
23
+
24
+    @NotBlank(message = "订单类型不能为空")
25
+    private String orderType;
26
+}

+ 14 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/dto/response/UserScoreModifyResponse.java

@@ -0,0 +1,14 @@
1
+package com.bjtdba.userCenter.dto.response;
2
+
3
+import lombok.Builder;
4
+import lombok.Data;
5
+
6
+import java.math.BigDecimal;
7
+
8
+@Builder
9
+@Data
10
+public class UserScoreModifyResponse {
11
+    private Integer uid;
12
+    private BigDecimal currentScore;
13
+    private String transactionId;
14
+}

+ 25 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/dto/response/common/ApiResponse.java

@@ -0,0 +1,25 @@
1
+package com.bjtdba.userCenter.dto.response.common;
2
+
3
+import lombok.Data;
4
+
5
+@Data
6
+public class ApiResponse<T> {
7
+    private int code;
8
+    private String message;
9
+    private T data;
10
+
11
+    public static <T> ApiResponse<T> success(T data) {
12
+        ApiResponse<T> response = new ApiResponse<>();
13
+        response.setCode(200);
14
+        response.setMessage("操作成功");
15
+        response.setData(data);
16
+        return response;
17
+    }
18
+
19
+    public static ApiResponse<Void> error(int code, String message) {
20
+        ApiResponse<Void> response = new ApiResponse<>();
21
+        response.setCode(code);
22
+        response.setMessage(message);
23
+        return response;
24
+    }
25
+}

+ 23 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/entity/UserSignScoreEntity.java

@@ -0,0 +1,23 @@
1
+package com.bjtdba.userCenter.entity;
2
+import lombok.Data;
3
+import java.math.BigDecimal;
4
+import java.time.LocalDateTime;
5
+
6
+@Data
7
+public class UserSignScoreEntity {
8
+    private Integer id;
9
+    private Integer uid;
10
+    private Integer continuityDay;
11
+    private BigDecimal rewardScore;
12
+    private LocalDateTime signinTime;
13
+    private Integer sourceUid = 0;
14
+    private Integer status = 0;
15
+    private String mark;
16
+    private String orderId;
17
+    private Integer pm = 1;
18
+    private BigDecimal surplus;
19
+    private String orderType;
20
+    private Long addtime;
21
+    private Integer sourceType = 1;
22
+    private LocalDateTime settlementTime;
23
+}

+ 41 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/exception/BusinessException.java

@@ -0,0 +1,41 @@
1
+package com.bjtdba.userCenter.exception;
2
+
3
+import lombok.Getter;
4
+
5
+public class BusinessException extends RuntimeException {
6
+    @Getter
7
+    private final int code;
8
+    private final String message;
9
+
10
+    public BusinessException(int code, String message) {
11
+        super(message);
12
+        this.code = code;
13
+        this.message = message;
14
+    }
15
+
16
+    public BusinessException(String message) {
17
+        this(400, message); // 默认400错误码
18
+    }
19
+
20
+    // 常用的预定义异常
21
+    public static BusinessException of(String message) {
22
+        return new BusinessException(message);
23
+    }
24
+
25
+    public static BusinessException userNotFound() {
26
+        return new BusinessException(404, "用户不存在");
27
+    }
28
+
29
+    public static BusinessException insufficientScore() {
30
+        return new BusinessException(403, "用户积分不足");
31
+    }
32
+
33
+    public static BusinessException updateFailed() {
34
+        return new BusinessException(500, "积分更新失败,请重试");
35
+    }
36
+
37
+    @Override
38
+    public String getMessage() {
39
+        return message;
40
+    }
41
+}

+ 4 - 0
userCenter_service/src/main/java/com/bjtdba/userCenter/service/UserService.java

@@ -3,6 +3,8 @@ package com.bjtdba.userCenter.service;
3 3
 import com.bjtdba.entity.order.User;
4 4
 import com.bjtdba.entity.userCenter.UserBill;
5 5
 import com.bjtdba.userCenter.dto.request.GetUserListRequest;
6
+import com.bjtdba.userCenter.dto.request.UserScoreModifyRequest;
7
+import com.bjtdba.userCenter.dto.response.UserScoreModifyResponse;
6 8
 import com.bjtdba.userCenter.dto.response.common.PageResult;
7 9
 import com.bjtdba.userCenter.dto.response.UserDTO;
8 10
 
@@ -40,4 +42,6 @@ public interface UserService {
40 42
     public BigDecimal getUserCommission(Integer uid);
41 43
 
42 44
     PageResult<UserDTO> getUserList(GetUserListRequest request);
45
+
46
+    UserScoreModifyResponse modifyUserScore(UserScoreModifyRequest request);
43 47
 }

+ 72 - 4
userCenter_service/src/main/java/com/bjtdba/userCenter/service/impl/UserServiceImpl.java

@@ -2,25 +2,31 @@ package com.bjtdba.userCenter.service.impl;
2 2
 
3 3
 import com.bjtdba.entity.order.User;
4 4
 import com.bjtdba.entity.userCenter.UserBill;
5
-import com.bjtdba.userCenter.dao.MerchantDao;
6
-import com.bjtdba.userCenter.dao.UserBillDao;
7
-import com.bjtdba.userCenter.dao.UserDao;
8
-import com.bjtdba.userCenter.dao.UserInfoDao;
5
+import com.bjtdba.userCenter.dao.*;
9 6
 import com.bjtdba.userCenter.dto.request.GetUserListRequest;
7
+import com.bjtdba.userCenter.dto.request.UserScoreModifyRequest;
8
+import com.bjtdba.userCenter.dto.response.UserScoreModifyResponse;
10 9
 import com.bjtdba.userCenter.dto.response.common.PageResult;
11 10
 import com.bjtdba.userCenter.dto.response.UserDTO;
12 11
 import com.bjtdba.userCenter.entity.UserEntity;
12
+import com.bjtdba.userCenter.entity.UserSignScoreEntity;
13
+import com.bjtdba.userCenter.exception.BusinessException;
13 14
 import com.bjtdba.userCenter.service.UserService;
15
+import lombok.RequiredArgsConstructor;
14 16
 import org.springframework.beans.factory.annotation.Autowired;
15 17
 import org.springframework.stereotype.Service;
18
+import org.springframework.transaction.annotation.Transactional;
16 19
 import org.springframework.util.CollectionUtils;
17 20
 
18 21
 import java.math.BigDecimal;
22
+import java.time.LocalDateTime;
23
+import java.time.ZoneOffset;
19 24
 import java.util.Collections;
20 25
 import java.util.List;
21 26
 import java.util.stream.Collectors;
22 27
 
23 28
 @Service("userService")
29
+@RequiredArgsConstructor
24 30
 public class UserServiceImpl  implements UserService {
25 31
     @Autowired
26 32
     private UserInfoDao userInfoDao;
@@ -30,6 +36,8 @@ public class UserServiceImpl  implements UserService {
30 36
     private UserBillDao userBillDao;
31 37
     @Autowired
32 38
     private UserDao userDao;
39
+    @Autowired
40
+    private UserSignScoreDao userSignScoreDao;
33 41
 
34 42
 
35 43
     public User queryByid(Integer uid){
@@ -127,4 +135,64 @@ public class UserServiceImpl  implements UserService {
127 135
         dto.setPv(userEntity.getPv());
128 136
         return dto;
129 137
     }
138
+
139
+    @Override
140
+    @Transactional(rollbackFor = Exception.class)
141
+    public UserScoreModifyResponse modifyUserScore(UserScoreModifyRequest request) {
142
+        // 1. 获取用户并加锁
143
+        UserEntity userEntity = userDao.getUserScoreByUidForUpdate(request.getUid());
144
+        if (userEntity == null) {
145
+            throw BusinessException.userNotFound();
146
+        }
147
+
148
+        // 2. 积分操作处理
149
+        BigDecimal newScore;
150
+        if (request.getPm() == 1) {  // 收入
151
+            newScore = userEntity.getScore().add(request.getRewardScore());
152
+        } else {  // 支出
153
+            if (userEntity.getScore().compareTo(request.getRewardScore()) < 0) {
154
+                throw BusinessException.insufficientScore();
155
+            }
156
+            newScore = userEntity.getScore().subtract(request.getRewardScore());
157
+        }
158
+
159
+        // 3. 更新用户积分(带乐观锁)
160
+        int updateCount = userDao.updateUserScore(
161
+                request.getUid(),
162
+                newScore
163
+        );
164
+        if (updateCount == 0) {
165
+            throw BusinessException.updateFailed();
166
+        }
167
+
168
+        // 4. 创建积分记录
169
+        UserSignScoreEntity record = buildScoreRecord(request, newScore);
170
+        userSignScoreDao.insertByEntity(record);
171
+
172
+        // 5. 构建响应
173
+        return UserScoreModifyResponse.builder()
174
+                .uid(request.getUid())
175
+                .currentScore(newScore)
176
+                .transactionId(record.getId().toString())
177
+                .build();
178
+    }
179
+
180
+    private UserSignScoreEntity buildScoreRecord(UserScoreModifyRequest request, BigDecimal currentScore) {
181
+        UserSignScoreEntity record = new UserSignScoreEntity();
182
+        record.setUid(request.getUid());
183
+        record.setRewardScore(request.getRewardScore());
184
+        record.setPm(request.getPm());
185
+        record.setOrderId(request.getOrderId());
186
+        record.setOrderType(request.getOrderType());
187
+        record.setSurplus(currentScore);
188
+        record.setAddtime(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC));
189
+        record.setMark(buildRecordMark(request));
190
+        return record;
191
+    }
192
+
193
+    private String buildRecordMark(UserScoreModifyRequest request) {
194
+        return String.format("%s积分,订单号:%s",
195
+                request.getPm() == 1 ? "收入" : "支出",
196
+                request.getOrderId());
197
+    }
130 198
 }

+ 12 - 0
userCenter_service/src/main/resources/mapper/UserExternalMapper.xml

@@ -54,4 +54,16 @@
54 54
         FROM rrx_user
55 55
         <include refid="queryCondition"/>
56 56
     </select>
57
+
58
+    <select id="getUserScoreByUidForUpdate" resultMap="userResultMap">
59
+        SELECT uid, score
60
+        FROM rrx_user
61
+        WHERE uid = #{uid} FOR UPDATE
62
+    </select>
63
+
64
+    <update id="updateUserScore">
65
+        UPDATE rrx_user SET
66
+                        score = #{newScore}
67
+        WHERE uid = #{uid}
68
+    </update>
57 69
 </mapper>

+ 10 - 0
userCenter_service/src/main/resources/mapper/UserSignScoreMapper.xml

@@ -203,5 +203,15 @@
203 203
         delete from rrx_user_sign_score where id = #{id}
204 204
     </delete>
205 205
 
206
+
207
+    <insert id="insertByEntity" useGeneratedKeys="true" keyProperty="id">
208
+        INSERT INTO rrx_user_sign_score (
209
+            uid, reward_socre, pm, order_id, order_type,
210
+            surplus, mark, status, addtime
211
+        ) VALUES (
212
+                     #{uid}, #{rewardScore}, #{pm}, #{orderId}, #{orderType},
213
+                     #{surplus}, #{mark}, 1, #{addtime}
214
+                 )
215
+    </insert>
206 216
 </mapper>
207 217