Procházet zdrojové kódy

refactor: 优化项目控制器和服务实现代码结构

weipengtao před 7 měsíci
rodič
revize
8ca019495d

+ 31 - 58
web/src/main/java/cn/seecoder/web/controller/project/ProjectController.java

@@ -1,112 +1,85 @@
 package cn.seecoder.web.controller.project;
 
-import cn.seecoder.web.model.vo.project.ProjectCreateVO;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
-import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.ResponseEntity;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
 import cn.seecoder.common.exceptions.ServiceException;
 import cn.seecoder.web.model.vo.Response;
+import cn.seecoder.web.model.vo.project.ProjectCreateVO;
 import cn.seecoder.web.model.vo.project.ProjectVO;
 import cn.seecoder.web.model.vo.user.UserVO;
 import cn.seecoder.web.service.project.ProjectService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
 
-/**
- * @author Chenyz
- * @date 2021/3/10
- * @description: 项目接口
- */
 @Api(tags = "项目相关 API")
 @RestController
 @RequestMapping("/project")
+@RequiredArgsConstructor
 public class ProjectController {
 
     private final ProjectService projectService;
 
-    @Autowired
-    public ProjectController(ProjectService projectService) {
-        this.projectService = projectService;
-    }
-
-
-    @ApiOperation(value = "根据user获取Project列表", httpMethod = "GET")
+    @ApiOperation("根据用户获取项目列表")
     @GetMapping("/listByUser")
     public Response<List<ProjectVO>> listProjectsByUserId() throws ServiceException {
         return Response.buildSuccess(projectService.listProjectsByUserId());
     }
 
-    @ApiOperation(value = "根据projectId获取Project", httpMethod = "GET")
+    @ApiOperation("根据项目ID获取项目")
     @GetMapping("/{projectId}")
-    @ApiImplicitParam(name = "projectId",dataType ="int", paramType = "path")
-    public Response<ProjectVO> getProjectById(@PathVariable("projectId")int projectId){
+    public Response<ProjectVO> getProjectById(@PathVariable Integer projectId) {
         return Response.buildSuccess(projectService.getProjectById(projectId));
     }
 
-    @ApiOperation(value = "创建项目,传入的参数中不必带有效的projectId字段,返回一个创建后的结果,注入id", httpMethod = "POST")
+    @ApiOperation("创建项目")
     @PostMapping("/create")
-    @ApiImplicitParam(name = "projectCreateVO",dataType = "object", paramType = "body")
-    public Response<ProjectVO> createProject(@RequestBody @Validated ProjectCreateVO projectCreateVO) throws ServiceException {
+    public Response<ProjectVO> createProject(@RequestBody @Validated ProjectCreateVO projectCreateVO)
+            throws ServiceException {
         return Response.buildSuccess(projectService.createProject(projectCreateVO));
     }
 
-    @ApiOperation(value = "获取一个项目所有成员信息", httpMethod = "GET")
+    @ApiOperation("获取项目所有成员")
     @GetMapping("/members")
-    @ApiImplicitParam(name = "projectId", dataType = "int", paramType = "query")
-    public Response<List<UserVO>> getProjectMember(@RequestParam("projectId") Integer projectId) throws ServiceException {
+    public Response<List<UserVO>> getProjectMember(@RequestParam Integer projectId)
+            throws ServiceException {
         return Response.buildSuccess(projectService.getProjectMembers(projectId));
     }
 
-    @ApiOperation(value = "给项目添加成员", httpMethod = "POST")
+    @ApiOperation("通过手机号添加成员")
     @PostMapping("/members")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "projectId", dataType = "int", paramType = "query"),
-            @ApiImplicitParam(name = "phone", dataType = "string", paramType = "query")
-    })
-    public Response addMember(@RequestParam("projectId") Integer projectId,@RequestParam("phone") String phone) throws ServiceException {
+    public Response<?> addMemberByPhone(@RequestParam Integer projectId,
+                                        @RequestParam String phone) throws ServiceException {
         projectService.addMember(projectId, phone);
         return Response.buildSuccess();
     }
 
-    @ApiOperation(value = "给项目添加成员", httpMethod = "POST")
+    @ApiOperation("通过用户ID添加成员")
     @PostMapping("/members/add")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "projectId", dataType = "int", paramType = "query"),
-            @ApiImplicitParam(name = "userId", dataType = "int", paramType = "query")
-    })
-    public Response addMember(@RequestParam("projectId") Integer projectId,@RequestParam("userId") Integer userId) throws ServiceException {
+    public Response<?> addMemberByUserId(@RequestParam Integer projectId,
+                                         @RequestParam Integer userId) throws ServiceException {
         projectService.addMember(projectId, userId);
         return Response.buildSuccess();
     }
 
-    @ApiOperation(value = "生成项目关联邀请码", httpMethod = "POST")
+    @ApiOperation("生成项目关联邀请码")
     @PostMapping("/relate/code")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "projectId", dataType = "int", paramType = "query")
-    })
-    public Response generaterelateCode(@RequestParam("projectId") Integer projectId) {
-        return Response.buildSuccess(projectService.generaterelateCode(projectId));
+    public Response<String> generateRelateCode(@RequestParam Integer projectId) {
+        return Response.buildSuccess(projectService.generateRelateCode(projectId));
     }
 
-    @ApiOperation(value = "通过邀请码关联两个项目", httpMethod = "POST")
+    @ApiOperation("通过邀请码关联项目")
     @PostMapping("/relate")
-    @ApiImplicitParams({
-            @ApiImplicitParam(name = "projectId", dataType = "int", paramType = "query"),
-            @ApiImplicitParam(name = "relateCode", dataType = "String", paramType = "query")
-    })
-    public Response generaterelateCode(@RequestParam("projectId") Integer projectId,@RequestParam("relateCode") String relateCode) {
-        return Response.buildSuccess(projectService.relateProjects(projectId,relateCode));
+    public Response<String> relateProjects(@RequestParam Integer projectId,
+                                           @RequestParam String relateCode) {
+        return Response.buildSuccess(projectService.relateProjects(projectId, relateCode));
     }
 
-    @ApiOperation(value = "查看一个项目关联的所有项目", httpMethod = "GET")
+    @ApiOperation("查看项目关联的所有项目")
     @GetMapping("/relate/{projectId}")
-    @ApiImplicitParam(name = "projectId", dataType = "int", paramType = "query")
-    public Response<List<ProjectVO>> getRelatedProject(@PathVariable("projectId") Integer projectId) {
+    public Response<List<ProjectVO>> getRelatedProject(@PathVariable Integer projectId) {
         return Response.buildSuccess(projectService.getRelatedProjects(projectId));
     }
 }

+ 111 - 90
web/src/main/java/cn/seecoder/web/service/impl/project/ProjectServiceImpl.java

@@ -20,43 +20,28 @@ import com.nju.edu.gitlab.SeecoderGitlabApi;
 import com.nju.edu.gitlab.SeecoderGitlabException;
 import com.nju.edu.gitlab.dto.member.AccessLevelForm;
 import com.nju.edu.gitlab.dto.project.VisibilityForm;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.http.HttpStatus;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
+@Slf4j
 @Service
+@RequiredArgsConstructor
 public class ProjectServiceImpl implements ProjectService {
 
     private final UserService userService;
-
     private final ProjectMapper projectMapper;
-
     private final ProjectRelatedMapper projectRelatedMapper;
-
     private final UserMapper userMapper;
-
     private final SeecoderGitlabApi seecoderGitlabApi;
-
     private final ApplicationProperties properties;
 
-    private final static Logger log = LoggerFactory.getLogger(ProjectServiceImpl.class);
-
-    @Autowired
-    public ProjectServiceImpl(UserService userService, ProjectMapper projectMapper, ProjectRelatedMapper projectRelatedMapper, UserMapper userMapper, SeecoderGitlabApi seecoderGitlabApi, ApplicationProperties properties) {
-        this.userService = userService;
-        this.projectMapper = projectMapper;
-        this.projectRelatedMapper = projectRelatedMapper;
-        this.userMapper = userMapper;
-        this.seecoderGitlabApi = seecoderGitlabApi;
-        this.properties = properties;
-    }
 
     @Override
     public List<ProjectVO> listProjectsByUserId() throws ServiceException {
@@ -65,12 +50,16 @@ public class ProjectServiceImpl implements ProjectService {
         try {
             projects = seecoderGitlabApi.getAllProjectsByUserId(userId);
 
-            //同步数据,有可能gitlab那边有的项目我们这边没有
-            List<ProjectPO> pos = projects.stream().filter(x -> projectMapper.getProjectById(x.getProjectId()) == null).map(ProjectPO::new).collect(Collectors.toList());
-            if (pos.size() != 0) {
+            // 同步数据,有可能 gitlab 那边有的项目我们这边没有
+            List<ProjectPO> pos = projects.stream()
+                    .filter(x -> projectMapper.getProjectById(x.getProjectId()) == null)
+                    .map(ProjectPO::new)
+                    .collect(Collectors.toList());
+
+            if (!pos.isEmpty()) {
                 for (ProjectPO po : pos) {
                     seecoderGitlabApi.addWebHook(po.getId(), properties.getGitlab().getWebhookProxy(), true, false, false);
-                    log.info("项目Id是{},名称是{}",po.getId(),po.getName());
+                    log.info("项目 ID: {}, 名称: {}", po.getId(), po.getName());
                     projectMapper.insertProject(po);
                     log.info("同步成功");
                 }
@@ -78,9 +67,15 @@ public class ProjectServiceImpl implements ProjectService {
         } catch (SeecoderGitlabException e) {
             throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "获取项目列表失败", e);
         }
-        List<Integer> projectIds = projects.stream().map(com.nju.edu.gitlab.vo.ProjectVO::getProjectId).collect(Collectors.toList());
 
-        return projectIds.size() == 0 ? new ArrayList<>() : projectMapper.selectByIds(projectIds).stream().map(ProjectVO::new).collect(Collectors.toList());
+        List<Integer> projectIds = projects.stream()
+                .map(com.nju.edu.gitlab.vo.ProjectVO::getProjectId)
+                .collect(Collectors.toList());
+
+        return projectIds.isEmpty() ? new ArrayList<>() :
+                projectMapper.selectByIds(projectIds).stream()
+                        .map(ProjectVO::new)
+                        .collect(Collectors.toList());
     }
 
     @Override
@@ -93,82 +88,92 @@ public class ProjectServiceImpl implements ProjectService {
     public ProjectVO createProject(ProjectCreateVO vo) throws ServiceException {
         ProjectPO po = new ProjectPO();
         BeanUtils.copyProperties(vo, po);
+
         try {
-            if(vo.getVisibility()==null) vo.setVisibility("private");
-            com.nju.edu.gitlab.vo.ProjectVO project = seecoderGitlabApi.createPrivateProject(po.getName(), vo.getVisibility().equals("public")?VisibilityForm.PUBLIC:VisibilityForm.PRIVATE, UserService.loginUser().getId());
-            log.info("项目可见性为:{}", vo.getVisibility());
+            if (vo.getVisibility() == null) {
+                vo.setVisibility("private");
+            }
+
+            VisibilityForm visibility = "public".equals(vo.getVisibility()) ?
+                    VisibilityForm.PUBLIC : VisibilityForm.PRIVATE;
+
+            com.nju.edu.gitlab.vo.ProjectVO project = seecoderGitlabApi.createPrivateProject(
+                    po.getName(), visibility, UserService.loginUser().getId());
+
+            log.info("项目可见性: {}", vo.getVisibility());
             po.setId(project.getProjectId());
             po.setGitRemoteUrl(project.getWebUrl());
         } catch (SeecoderGitlabException e) {
-            e.printStackTrace();
+            log.error("创建项目时发生异常: project id={}, error={}", po.getId(), e.getMessage(), e);
             throw new ServiceException("创建项目时发生异常[project id:" + po.getId() + ", " + e.getMessage() + "]", e);
         }
+
         projectMapper.insertProject(po);
+
         try {
             seecoderGitlabApi.addWebHook(po.getId(), properties.getGitlab().getWebhookProxy(), true, false, false);
         } catch (SeecoderGitlabException e) {
-            throw new ServiceException("给项目添加webhook发生异常[project id:" + po.getId() + ", " + e.getMessage() + "]", e);
+            throw new ServiceException("给项目添加 webhook 发生异常[project id:" + po.getId() + ", " + e.getMessage() + "]", e);
         }
 
-        //ANA 日志需要打出创建项目的基础信息
-        try{
-            JSONObject object = new JSONObject();
-            object.put("user_id",userService.getLoginUser().getId());
-            object.put("project_id",po.getId());
-            object.put("project_name",po.getName());
-            object.put("description",po.getDescription());
-
-            String data = JSONObject.toJSONString(object);
-            LogTrackingUtil.log(data,OpType.CREATE_PROJECT);
-        }catch (Exception e){}
+        // ANA 日志需要打出创建项目的基础信息
+        logCreateProject(po);
 
         return new ProjectVO(po);
+    }
+
+    private void logCreateProject(ProjectPO po) {
+        try {
+            JSONObject object = new JSONObject();
+            object.put("user_id", userService.getLoginUser().getId());
+            object.put("project_id", po.getId());
+            object.put("project_name", po.getName());
+            object.put("description", po.getDescription());
 
+            LogTrackingUtil.log(object.toJSONString(), OpType.CREATE_PROJECT);
+        } catch (Exception e) {
+            log.warn("记录创建项目日志失败", e);
+        }
     }
 
     @Override
     public void addMember(Integer projectId, String phone) throws ServiceException {
         Integer userId = userMapper.selectIdByPhone(phone);
-        if(userId == null){
+        if (userId == null) {
             throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "该手机号不存在对应用户");
         }
-        try {
-            seecoderGitlabApi.addAuthorization(projectId, userId, AccessLevelForm.MASTER);
-        } catch (Exception e) {
-            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "添加项目权限失败", e);
-        }
-        //ANA 日志需要打出加入的成员信息
-        try{
-            JSONObject object = new JSONObject();
-
-            object.put("project_id",projectId);
-            object.put("user_id",userId);
-
-            String data = JSONObject.toJSONString(object);
-            LogTrackingUtil.log(data, OpType.ADD_MEMBER);
-        }catch (Exception e){}
+        addMemberToProject(projectId, userId);
     }
 
     @Override
     public void addMember(Integer projectId, Integer userId) throws ServiceException {
-//        Integer userId = userMapper.selectIdByPhone(phone);
-        if(userId == null){
-            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "该手机号不存在对应用户");
+        if (userId == null) {
+            throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "用户 ID 不能为空");
         }
+        addMemberToProject(projectId, userId);
+    }
+
+    private void addMemberToProject(Integer projectId, Integer userId) throws ServiceException {
         try {
             seecoderGitlabApi.addAuthorization(projectId, userId, AccessLevelForm.MASTER);
         } catch (Exception e) {
             throw new ServiceException(HttpStatus.SC_INTERNAL_SERVER_ERROR, "添加项目权限失败", e);
         }
-        //ANA 日志需要打出加入的成员信息
-        try{
+
+        // ANA 日志需要打出加入的成员信息
+        logAddMember(projectId, userId);
+    }
+
+    private void logAddMember(Integer projectId, Integer userId) {
+        try {
             JSONObject object = new JSONObject();
-            object.put("project_id",projectId);
-            object.put("user_id",userId);
+            object.put("project_id", projectId);
+            object.put("user_id", userId);
 
-            String data = JSONObject.toJSONString(object);
-            LogTrackingUtil.log(data, OpType.ADD_MEMBER);
-        }catch (Exception e){}
+            LogTrackingUtil.log(object.toJSONString(), OpType.ADD_MEMBER);
+        } catch (Exception e) {
+            log.warn("记录添加成员日志失败", e);
+        }
     }
 
     @Override
@@ -185,50 +190,66 @@ public class ProjectServiceImpl implements ProjectService {
     }
 
     @Override
-    public String generaterelateCode(Integer projectId) {
+    public String generateRelateCode(Integer projectId) {
         return ShareCodeUtil.idToCode(projectId.longValue());
     }
 
     @Override
     public String relateProjects(Integer projectId, String relateCode) {
         Long[] result = ShareCodeUtil.codeToId(relateCode);
-        if (System.currentTimeMillis() - result[1] > 1000 * 60 * 5) {
+        long timestamp = result[1];
+        int targetProjectId = result[0].intValue();
+
+        // 验证码有效期 5 分钟
+        long expireTime = 5 * 60 * 1000;
+        if (System.currentTimeMillis() - timestamp > expireTime) {
             return "验证码有效时间为五分钟,已过期";
         }
-        if (projectId == result[0].intValue()) {
+
+        if (projectId.equals(targetProjectId)) {
             return "不可将本项目与自身关联!";
         }
-        List<ProjectRelatedPO> projectRelatedPOS = projectRelatedMapper.isExistRelated(projectId, result[0].intValue());
-        if (projectRelatedPOS.size() != 0) {
+
+        List<ProjectRelatedPO> projectRelatedPOS = projectRelatedMapper.isExistRelated(projectId, targetProjectId);
+        if (!projectRelatedPOS.isEmpty()) {
             return "该项目已与目标项目关联过,无须重复关联";
         }
+
         projectRelatedMapper.insert(ProjectRelatedPO.builder()
                 .projectIdA(projectId)
-                .projectIdB(result[0].intValue()).build(), "id");
-
-        //ANA 日志需要打出关联项目的id
-        try{
-            JSONObject object = new JSONObject();
-            object.put("user_id",userService.getLoginUser().getId());
-            object.put("projectA_id",projectId);
-            object.put("projectB_id",result[0].intValue());
+                .projectIdB(targetProjectId)
+                .build(), "id");
 
-            String data = JSONObject.toJSONString(object);
-            LogTrackingUtil.log(data, OpType.RELATE_PROJECT);
-        }catch (Exception e){}
+        // ANA 日志需要打出关联项目的 ID
+        logRelateProject(projectId, targetProjectId);
 
         return "关联项目成功";
     }
 
+    private void logRelateProject(Integer projectIdA, Integer projectIdB) {
+        try {
+            JSONObject object = new JSONObject();
+            object.put("user_id", userService.getLoginUser().getId());
+            object.put("projectA_id", projectIdA);
+            object.put("projectB_id", projectIdB);
+
+            LogTrackingUtil.log(object.toJSONString(), OpType.RELATE_PROJECT);
+        } catch (Exception e) {
+            log.warn("记录关联项目日志失败", e);
+        }
+    }
+
     @Override
     public List<ProjectVO> getRelatedProjects(Integer projectId) {
         List<ProjectRelatedPO> projectRelatedPOS = projectRelatedMapper.selectByProjectId(projectId);
-        List<Integer> projectIds = new ArrayList<>();
-        for (ProjectRelatedPO projectRelatedPO : projectRelatedPOS) {
-            int projectIdA = projectRelatedPO.getProjectIdA();
-            int projectIdB = projectRelatedPO.getProjectIdB();
-            projectIds.add(projectIdA == projectId ? projectIdB : projectIdA);
-        }
-        return projectIds.size() == 0 ? new ArrayList<>() : projectMapper.selectByIds(projectIds).stream().map(ProjectVO::new).collect(Collectors.toList());
+
+        List<Integer> projectIds = projectRelatedPOS.stream()
+                .map(po -> po.getProjectIdA().equals(projectId) ? po.getProjectIdB() : po.getProjectIdA())
+                .collect(Collectors.toList());
+
+        return projectIds.isEmpty() ? new ArrayList<>() :
+                projectMapper.selectByIds(projectIds).stream()
+                        .map(ProjectVO::new)
+                        .collect(Collectors.toList());
     }
 }

+ 47 - 14
web/src/main/java/cn/seecoder/web/service/project/ProjectService.java

@@ -1,7 +1,7 @@
 package cn.seecoder.web.service.project;
 
-import cn.seecoder.web.model.vo.project.ProjectCreateVO;
 import cn.seecoder.common.exceptions.ServiceException;
+import cn.seecoder.web.model.vo.project.ProjectCreateVO;
 import cn.seecoder.web.model.vo.project.ProjectVO;
 import cn.seecoder.web.model.vo.user.UserVO;
 
@@ -10,46 +10,79 @@ import java.util.List;
 public interface ProjectService {
 
     /**
-     * 根据user找Project
-     * @return
+     * 根据当前用户获取项目列表
+     *
+     * @return 项目列表
+     * @throws ServiceException 服务异常
      */
     List<ProjectVO> listProjectsByUserId() throws ServiceException;
 
     /**
-     * 获取project
-     * @param projectId
-     * @return
+     * 根据项目ID获取项目信息
+     *
+     * @param projectId 项目ID
+     * @return 项目信息
      */
     ProjectVO getProjectById(int projectId);
 
     /**
      * 创建项目
-     * @return 注入id后返回
+     *
+     * @param vo 项目创建信息
+     * @return 创建后的项目信息(包含生成的ID)
+     * @throws ServiceException 服务异常
      */
     ProjectVO createProject(ProjectCreateVO vo) throws ServiceException;
 
+    /**
+     * 通过手机号添加项目成员
+     *
+     * @param projectId 项目ID
+     * @param phone     用户手机号
+     * @throws ServiceException 服务异常
+     */
     void addMember(Integer projectId, String phone) throws ServiceException;
 
+    /**
+     * 通过用户ID添加项目成员
+     *
+     * @param projectId 项目ID
+     * @param userId    用户ID
+     * @throws ServiceException 服务异常
+     */
     void addMember(Integer projectId, Integer userId) throws ServiceException;
 
+    /**
+     * 获取项目所有成员信息
+     *
+     * @param projectId 项目ID
+     * @return 成员列表
+     * @throws ServiceException 服务异常
+     */
     List<UserVO> getProjectMembers(Integer projectId) throws ServiceException;
 
     /**
      * 生成项目关联邀请码
-     * @param projectId
+     *
+     * @param projectId 项目ID
+     * @return 邀请码
      */
-    String generaterelateCode(Integer projectId);
+    String generateRelateCode(Integer projectId);
 
     /**
-     * 关联项目
-     * @param relateCode
+     * 通过邀请码关联项目
+     *
+     * @param projectId  项目ID
+     * @param relateCode 邀请码
+     * @return 关联结果信息
      */
     String relateProjects(Integer projectId, String relateCode);
 
     /**
-     * 获取一个项目关联的所有项目信息
-     * @param projectId
-     * @return
+     * 获取项目关联的所有项目信息
+     *
+     * @param projectId 项目ID
+     * @return 关联的项目列表
      */
     List<ProjectVO> getRelatedProjects(Integer projectId);