fix(backend): Restore service flow and admin management integration
This commit is contained in:
+16
-1
@@ -2,8 +2,11 @@ package com.nuaa.video.comment.config;
|
||||
|
||||
import com.nuaa.video.comment.filter.JwtAuthenticationFilter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authorization.AuthorizationDecision;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
@@ -15,11 +18,15 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity
|
||||
@RequiredArgsConstructor
|
||||
public class SecurityConfig {
|
||||
|
||||
private final JwtAuthenticationFilter jwtAuthenticationFilter;
|
||||
|
||||
@Value("${service.auth.token}")
|
||||
private String internalServiceToken;
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
@@ -29,13 +36,21 @@ public class SecurityConfig {
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers(
|
||||
"/comment/public/**",
|
||||
"/comment/reply/public/**",
|
||||
"/actuator/**",
|
||||
"/error"
|
||||
).permitAll()
|
||||
.requestMatchers("/comment/admin/**")
|
||||
.access((authentication, context) ->
|
||||
new AuthorizationDecision(isInternalRequest(context.getRequest().getHeader("X-Internal-Token"))))
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInternalRequest(String internalToken) {
|
||||
return internalServiceToken.equals(internalToken);
|
||||
}
|
||||
}
|
||||
|
||||
+27
-5
@@ -6,8 +6,10 @@ import com.nuaa.video.comment.service.CommentService;
|
||||
import com.nuaa.video.comment.vo.CommentStatVO;
|
||||
import com.nuaa.video.comment.vo.CommentVO;
|
||||
import com.nuaa.video.common.model.vo.Result;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
@@ -19,6 +21,9 @@ import org.springframework.web.bind.annotation.*;
|
||||
@RequiredArgsConstructor
|
||||
public class AdminCommentController {
|
||||
|
||||
@Value("${service.auth.token}")
|
||||
private String internalServiceToken;
|
||||
|
||||
private final CommentService commentService;
|
||||
|
||||
/**
|
||||
@@ -30,7 +35,11 @@ public class AdminCommentController {
|
||||
@RequestParam(value = "size", defaultValue = "10") Integer size,
|
||||
@RequestParam(value = "videoId", required = false) Long videoId,
|
||||
@RequestParam(value = "userId", required = false) Long userId,
|
||||
@RequestParam(value = "keyword", required = false) String keyword) {
|
||||
@RequestParam(value = "keyword", required = false) String keyword,
|
||||
HttpServletRequest request) {
|
||||
if (!isInternalRequest(request)) {
|
||||
return Result.error("非法的内部调用");
|
||||
}
|
||||
|
||||
return commentService.getAdminCommentList(page, size, videoId, userId, keyword);
|
||||
}
|
||||
@@ -39,7 +48,10 @@ public class AdminCommentController {
|
||||
* 获取评论详情 - 管理接口
|
||||
*/
|
||||
@GetMapping("/{commentId}")
|
||||
public Result<CommentVO> getCommentDetail(@PathVariable Long commentId) {
|
||||
public Result<CommentVO> getCommentDetail(@PathVariable Long commentId, HttpServletRequest request) {
|
||||
if (!isInternalRequest(request)) {
|
||||
return Result.error("非法的内部调用");
|
||||
}
|
||||
return commentService.getAdminCommentDetail(commentId);
|
||||
}
|
||||
|
||||
@@ -47,7 +59,10 @@ public class AdminCommentController {
|
||||
* 删除评论 - 管理接口
|
||||
*/
|
||||
@DeleteMapping("/{commentId}")
|
||||
public Result<Void> deleteComment(@PathVariable Long commentId) {
|
||||
public Result<Void> deleteComment(@PathVariable Long commentId, HttpServletRequest request) {
|
||||
if (!isInternalRequest(request)) {
|
||||
return Result.error("非法的内部调用");
|
||||
}
|
||||
return commentService.adminDeleteComment(commentId);
|
||||
}
|
||||
|
||||
@@ -55,7 +70,14 @@ public class AdminCommentController {
|
||||
* 获取评论统计信息 - 管理接口
|
||||
*/
|
||||
@GetMapping("/stats")
|
||||
public Result<CommentStatVO> getCommentStats() {
|
||||
public Result<CommentStatVO> getCommentStats(HttpServletRequest request) {
|
||||
if (!isInternalRequest(request)) {
|
||||
return Result.error("非法的内部调用");
|
||||
}
|
||||
return commentService.getCommentStats();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInternalRequest(HttpServletRequest request) {
|
||||
return internalServiceToken.equals(request.getHeader("X-Internal-Token"));
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -19,7 +19,7 @@ public interface ContentFeignClient {
|
||||
* @param id 视频ID
|
||||
* @return 视频信息
|
||||
*/
|
||||
@GetMapping("/content/video/{id}")
|
||||
@GetMapping("/content/video/public/{id}")
|
||||
Result<Object> getVideoInfo(@PathVariable("id") Long id);
|
||||
|
||||
/**
|
||||
@@ -33,5 +33,5 @@ public interface ContentFeignClient {
|
||||
@PostMapping("/content/video/count/comment/{videoId}/{count}")
|
||||
Result<Void> increaseCommentCount(@PathVariable("videoId") Long videoId,
|
||||
@PathVariable("count") Integer count,
|
||||
@RequestHeader("Authorization") String token);
|
||||
}
|
||||
@RequestHeader("X-Internal-Token") String internalToken);
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,10 +23,10 @@ public class ContentFeignClientFallbackFactory implements FallbackFactory<Conten
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Void> increaseCommentCount(Long videoId, Integer count, String token) {
|
||||
public Result<Void> increaseCommentCount(Long videoId, Integer count, String internalToken) {
|
||||
log.error("增加视频评论数量失败,视频ID:{}, 数量:{}", videoId, count);
|
||||
return Result.error("更新视频评论数量失败");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -35,5 +35,5 @@ public interface UserFeignClient {
|
||||
@PostMapping("/user/notification/send/{userId}/{type}")
|
||||
Result<Void> sendNotification(@PathVariable("userId") Long userId,
|
||||
@PathVariable("type") Integer type,
|
||||
@RequestHeader("Authorization") String token);
|
||||
}
|
||||
@RequestHeader("X-Internal-Token") String internalToken);
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,10 +23,10 @@ public class UserFeignClientFallbackFactory implements FallbackFactory<UserFeign
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Void> sendNotification(Long userId, Integer type, String token) {
|
||||
public Result<Void> sendNotification(Long userId, Integer type, String internalToken) {
|
||||
log.error("发送用户通知失败,用户ID:{}, 类型:{}", userId, type);
|
||||
return Result.error("发送用户通知失败");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-3
@@ -21,6 +21,7 @@ import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* JWT认证过滤器
|
||||
@@ -29,7 +30,7 @@ import java.util.List;
|
||||
@Component
|
||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
@Value("${jwt.secret:video-platform-secret-key-2024-nuaa}")
|
||||
@Value("${jwt.secret}")
|
||||
private String secret;
|
||||
|
||||
private static final String TOKEN_PREFIX = "Bearer ";
|
||||
@@ -55,7 +56,13 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
String username = claims.get("username", String.class);
|
||||
|
||||
// 设置用户权限
|
||||
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
|
||||
List<String> authorityClaims = claims.get("authorities", List.class);
|
||||
List<SimpleGrantedAuthority> authorities = authorityClaims == null
|
||||
? new ArrayList<>()
|
||||
: authorityClaims.stream()
|
||||
.filter(StringUtils::hasText)
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
// 创建认证对象
|
||||
UsernamePasswordAuthenticationToken authentication =
|
||||
@@ -70,6 +77,9 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
// 在请求属性中存储用户ID
|
||||
request.setAttribute("userId", userId);
|
||||
request.setAttribute("username", username);
|
||||
if (!authorities.isEmpty()) {
|
||||
request.setAttribute("adminId", userId);
|
||||
}
|
||||
|
||||
log.debug("认证成功: 用户ID={}, 用户名={}", userId, username);
|
||||
} catch (Exception e) {
|
||||
@@ -99,4 +109,4 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||
byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
|
||||
return Keys.hmacShaKeyFor(keyBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-15
@@ -26,6 +26,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* 评论回复服务实现类
|
||||
@@ -35,6 +36,9 @@ import java.util.Map;
|
||||
@RequiredArgsConstructor
|
||||
public class CommentReplyServiceImpl extends ServiceImpl<CommentReplyMapper, CommentReply> implements CommentReplyService {
|
||||
|
||||
@Value("${service.auth.token}")
|
||||
private String internalServiceToken;
|
||||
|
||||
private final CommentReplyMapper commentReplyMapper;
|
||||
private final CommentMapper commentMapper;
|
||||
private final CommentLikeMapper commentLikeMapper;
|
||||
@@ -80,20 +84,7 @@ public class CommentReplyServiceImpl extends ServiceImpl<CommentReplyMapper, Com
|
||||
// 更新评论回复数
|
||||
commentMapper.increaseReplyCount(replyDTO.getCommentId(), 1);
|
||||
|
||||
// 发送回复通知给评论作者
|
||||
try {
|
||||
// 如果回复者不是评论作者,发送通知
|
||||
if (!userId.equals(comment.getUserId())) {
|
||||
userFeignClient.sendNotification(comment.getUserId(), 2, "Bearer ");
|
||||
}
|
||||
|
||||
// 如果存在回复目标用户,且回复者不是回复目标用户,发送通知
|
||||
if (replyDTO.getReplyToId() != null && !userId.equals(replyDTO.getReplyToId())) {
|
||||
userFeignClient.sendNotification(replyDTO.getReplyToId(), 2, "Bearer ");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("发送回复通知失败", e);
|
||||
}
|
||||
sendReplyNotificationAsync(comment, replyDTO, userId);
|
||||
|
||||
return Result.success(reply.getId());
|
||||
}
|
||||
@@ -161,6 +152,9 @@ public class CommentReplyServiceImpl extends ServiceImpl<CommentReplyMapper, Com
|
||||
if (reply == null) {
|
||||
return Result.error("回复不存在");
|
||||
}
|
||||
if (reply.getStatus() == 0) {
|
||||
return Result.error("回复已删除");
|
||||
}
|
||||
|
||||
// 校验操作权限
|
||||
if (!reply.getUserId().equals(userId)) {
|
||||
@@ -278,4 +272,19 @@ public class CommentReplyServiceImpl extends ServiceImpl<CommentReplyMapper, Com
|
||||
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendReplyNotificationAsync(Comment comment, ReplyAddDTO replyDTO, Long userId) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
if (!userId.equals(comment.getUserId())) {
|
||||
userFeignClient.sendNotification(comment.getUserId(), 2, internalServiceToken);
|
||||
}
|
||||
if (replyDTO.getReplyToId() != null && !userId.equals(replyDTO.getReplyToId())) {
|
||||
userFeignClient.sendNotification(replyDTO.getReplyToId(), 2, internalServiceToken);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("发送回复通知失败", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+55
-22
@@ -32,6 +32,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* 评论服务实现类
|
||||
@@ -41,6 +42,9 @@ import java.util.Map;
|
||||
@RequiredArgsConstructor
|
||||
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {
|
||||
|
||||
@Value("${service.auth.token}")
|
||||
private String internalServiceToken;
|
||||
|
||||
private final CommentMapper commentMapper;
|
||||
private final CommentReplyMapper commentReplyMapper;
|
||||
private final CommentLikeMapper commentLikeMapper;
|
||||
@@ -88,22 +92,9 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
// 保存评论
|
||||
save(comment);
|
||||
|
||||
// 更新视频评论数
|
||||
contentFeignClient.increaseCommentCount(commentDTO.getVideoId(), 1, "Bearer ");
|
||||
updateVideoCommentCountAsync(commentDTO.getVideoId(), 1);
|
||||
|
||||
// 发送评论通知给视频作者
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> videoData = (Map<String, Object>) videoResult.getData();
|
||||
Long videoAuthorId = Long.valueOf(videoData.get("userId").toString());
|
||||
|
||||
// 如果评论者不是视频作者,发送通知
|
||||
if (!userId.equals(videoAuthorId)) {
|
||||
userFeignClient.sendNotification(videoAuthorId, 2, "Bearer ");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("发送评论通知失败", e);
|
||||
}
|
||||
sendCommentNotificationAsync(videoResult.getData(), userId);
|
||||
|
||||
return Result.success(comment.getId());
|
||||
}
|
||||
@@ -176,6 +167,9 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
if (comment == null) {
|
||||
return Result.error("评论不存在");
|
||||
}
|
||||
if (comment.getStatus() == 0) {
|
||||
return Result.error("评论已删除");
|
||||
}
|
||||
|
||||
// 校验操作权限
|
||||
if (!comment.getUserId().equals(userId)) {
|
||||
@@ -188,8 +182,7 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
comment.setUpdateTime(LocalDateTime.now());
|
||||
updateById(comment);
|
||||
|
||||
// 更新视频评论数
|
||||
contentFeignClient.increaseCommentCount(comment.getVideoId(), -1, "Bearer ");
|
||||
updateVideoCommentCountAsync(comment.getVideoId(), -1);
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
@@ -258,6 +251,9 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
if (comment == null || comment.getStatus() == 0) {
|
||||
return Result.error("评论不存在");
|
||||
}
|
||||
if (!videoId.equals(comment.getVideoId())) {
|
||||
return Result.error("评论不属于该视频");
|
||||
}
|
||||
|
||||
// 验证视频所有权(只有视频作者才能置顶评论)
|
||||
Result<Object> videoResult = contentFeignClient.getVideoInfo(videoId);
|
||||
@@ -308,6 +304,9 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
if (comment == null || comment.getStatus() == 0) {
|
||||
return Result.error("评论不存在");
|
||||
}
|
||||
if (!videoId.equals(comment.getVideoId())) {
|
||||
return Result.error("评论不属于该视频");
|
||||
}
|
||||
|
||||
// 验证视频所有权(只有视频作者才能取消置顶评论)
|
||||
Result<Object> videoResult = contentFeignClient.getVideoInfo(videoId);
|
||||
@@ -422,6 +421,9 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
if (comment == null) {
|
||||
return Result.error("评论不存在");
|
||||
}
|
||||
if (comment.getStatus() == 0) {
|
||||
return Result.error("评论已删除");
|
||||
}
|
||||
|
||||
// 转换为VO
|
||||
CommentVO vo = convertToCommentVO(comment, null);
|
||||
@@ -452,8 +454,7 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
comment.setUpdateTime(LocalDateTime.now());
|
||||
updateById(comment);
|
||||
|
||||
// 更新视频评论数
|
||||
contentFeignClient.increaseCommentCount(comment.getVideoId(), -1, "Bearer ");
|
||||
updateVideoCommentCountAsync(comment.getVideoId(), -1);
|
||||
|
||||
return Result.success();
|
||||
}
|
||||
@@ -464,16 +465,20 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
|
||||
// 获取各种统计数据
|
||||
// 1. 总评论数
|
||||
long totalComments = count();
|
||||
long totalComments = count(new LambdaQueryWrapper<Comment>().eq(Comment::getStatus, 1));
|
||||
statVO.setCommentCount((int)totalComments);
|
||||
|
||||
// 2. 今日新增评论数
|
||||
LocalDate today = LocalDate.now();
|
||||
long todayComments = count(new LambdaQueryWrapper<Comment>()
|
||||
.eq(Comment::getStatus, 1)
|
||||
.ge(Comment::getCreateTime, today.atStartOfDay()));
|
||||
|
||||
// 3. 回复总数
|
||||
long totalReplies = commentReplyMapper.selectCount(null);
|
||||
long totalReplies = commentReplyMapper.selectCount(
|
||||
new LambdaQueryWrapper<com.nuaa.video.comment.entity.CommentReply>()
|
||||
.eq(com.nuaa.video.comment.entity.CommentReply::getStatus, 1)
|
||||
);
|
||||
statVO.setReplyCount((int)totalReplies);
|
||||
|
||||
// 4. 总点赞数
|
||||
@@ -514,4 +519,32 @@ public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> impl
|
||||
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendCommentNotificationAsync(Object videoPayload, Long userId) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> videoData = (Map<String, Object>) videoPayload;
|
||||
Long videoAuthorId = Long.valueOf(videoData.get("userId").toString());
|
||||
if (!userId.equals(videoAuthorId)) {
|
||||
userFeignClient.sendNotification(videoAuthorId, 2, internalServiceToken);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("发送评论通知失败", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateVideoCommentCountAsync(Long videoId, int delta) {
|
||||
CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
Result<Void> countResult = contentFeignClient.increaseCommentCount(videoId, delta, internalServiceToken);
|
||||
if (countResult == null || countResult.getCode() != 200) {
|
||||
log.warn("异步更新视频评论数失败,videoId={}, delta={}, result={}", videoId, delta, countResult);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("异步更新视频评论数异常,videoId={}, delta={}", videoId, delta, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
server:
|
||||
port: 9005
|
||||
port: 9004
|
||||
|
||||
spring:
|
||||
application:
|
||||
@@ -18,14 +18,14 @@ spring:
|
||||
datasource:
|
||||
url: jdbc:mysql://${MYSQL_HOST:mysql}:${MYSQL_PORT:3306}/video_comment?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: root
|
||||
password: ${MYSQL_ROOT_PASSWORD}
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
data:
|
||||
redis:
|
||||
host: ${REDIS_HOST:redis}
|
||||
port: ${REDIS_PORT:6379}
|
||||
password: redis_EsJ8FX
|
||||
database: 4
|
||||
password: ${REDIS_PASSWORD}
|
||||
database: 3
|
||||
timeout: 10000
|
||||
lettuce:
|
||||
pool:
|
||||
@@ -40,10 +40,19 @@ mybatis-plus:
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
cache-enabled: false
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
global-config:
|
||||
db-config:
|
||||
id-type: auto
|
||||
logic-delete-field: is_deleted
|
||||
logic-delete-value: 1
|
||||
logic-not-delete-value: 0
|
||||
logic-not-delete-value: 0
|
||||
|
||||
service:
|
||||
auth:
|
||||
token: ${SERVICE_AUTH_TOKEN}
|
||||
|
||||
jwt:
|
||||
secret: ${USER_JWT_SECRET}
|
||||
expiration: ${JWT_EXPIRATION}
|
||||
token-header: Authorization
|
||||
token-prefix: Bearer
|
||||
|
||||
+3
@@ -17,7 +17,9 @@ import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
@@ -31,6 +33,7 @@ import static org.mockito.Mockito.*;
|
||||
* CommentService 单元测试
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.LENIENT)
|
||||
@DisplayName("评论服务测试")
|
||||
class CommentServiceTest {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user