Feature/server java (#374)

* fix: 1. 去除jwt存储password关键信息;token创建逻辑同node,jwt信息实现node和java互通
2. 新增hash256方法,用户注册password加密逻辑同node,实现java端注册的账号登录和node版本互通

* add Workspace,WorkspaceMember,ConvertorConfig

* 删除获取获取jwt信息中的魔法值;处理空指针问题

* add error code

* 常量命名调整

* 1.新增mongodb事件拦截器 MongoEntityInterceptor
2.新增对象转换器 GeneralConvertor
3.新增空间Workspace接口
4.新增空间成员WorkspaceMember接口

* init application-dev.properties

* 删除Status的get set方法

* pom依赖管理
This commit is contained in:
misWCL 2024-08-07 11:42:24 +08:00 committed by GitHub
parent 92f11f81a7
commit a6ff240369
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 1240 additions and 16 deletions

4
lombok.config Normal file
View File

@ -0,0 +1,4 @@
lombok.accessors.chain=true
lombok.equalsAndHashCode.doNotUseGetters=true
lombok.toString.doNotUseGetters=true
lombok.equalsAndHashCode.callSuper=SKIP

View File

@ -34,6 +34,7 @@
<lang3.version>3.14.0</lang3.version>
<fastjson.version>1.2.83</fastjson.version>
<jwt.version>4.4.0</jwt.version>
<dozer.version>5.5.1</dozer.version>
</properties>
<dependencyManagement>
@ -83,6 +84,11 @@
<artifactId>commons-lang3</artifactId>
<version>${lang3.version}</version>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
<version>${dozer.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

View File

@ -0,0 +1,13 @@
package com.xiaojusurvey.engine.common.entity;
import lombok.Data;
/**
* @description: InitBaseEntity
* @author: wangchenglong
* @time: 2024/7/31 17:12
*/
@Data
public class InitBaseEntity extends BaseEntity {
}

View File

@ -12,20 +12,4 @@ public class Status implements Serializable {
private String status;
public Long getDate() {
return date;
}
public void setDate(Long date) {
this.date = date;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@ -0,0 +1,22 @@
package com.xiaojusurvey.engine.common.entity.workspace;
import com.xiaojusurvey.engine.common.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* @description: 空间
* @author: wangchenglong
* @time: 2024/7/24 10:50
*/
@Document("workspace")
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
public class Workspace extends BaseEntity {
private String ownerId;
private String name;
private String description;
}

View File

@ -0,0 +1,24 @@
package com.xiaojusurvey.engine.common.entity.workspace;
import com.xiaojusurvey.engine.common.entity.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* @description: 空间成员
* @author: wangchenglong
* @time: 2024/7/24 10:51
*/
@Document("workspaceMember")
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Data
public class WorkspaceMember extends BaseEntity {
private String userId;
private String workspaceId;
private String role;
}

View File

@ -0,0 +1,38 @@
package com.xiaojusurvey.engine.common.enums;
/**
* @description: 状态类型
* @author: wangchenglong
* @time: 2024/7/30 16:08
*/
public enum RecordStatusEnum {
// 新建
NEW("new"),
// 编辑
EDITING("editing"),
// 暂停
PAUSING("pausing"),
// 发布
PUBLISHED("published"),
// 删除
REMOVED("removed"),
// 从回收站删除
FORCE_REMOVED("forceRemoved");
private final String statusType;
RecordStatusEnum(String statusType) {
this.statusType = statusType;
}
public String getStatusType() {
return this.statusType;
}
}

View File

@ -0,0 +1,31 @@
package com.xiaojusurvey.engine.common.enums;
/**
* @description: 用户角色枚举
* @author: wangchenglong
* @time: 2024/7/24 14:47
*/
public enum RoleEmum {
USER(0, "user"),
ADMIN(1, "admin");
private final Integer state;
private final String value;
RoleEmum(Integer state, String value) {
this.state = state;
this.value = value;
}
public Integer getState() {
return this.state;
}
public String getValue() {
return this.value;
}
}

View File

@ -33,6 +33,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>net.sf.dozer</groupId>
<artifactId>dozer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@ -0,0 +1,18 @@
package com.xiaojusurvey.engine.bean;
import org.dozer.DozerBeanMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description: net.sf.dozer
* @author: wangchenglong
* @time: 2024/7/24 22:25
*/
@Configuration
public class ConvertorConfig {
@Bean
public DozerBeanMapper dozerBeanMapper() {
return new DozerBeanMapper();
}
}

View File

@ -0,0 +1,89 @@
package com.xiaojusurvey.engine.bean;
import org.dozer.Mapper;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
/**
* @description: 对象转换
* @author: wangchenglong
* @time: 2024/7/24 14:23
*/
@Component
public class GeneralConvertor {
@Resource
private Mapper mapper;
/**
* List 实体类 转换器
*
* @param source 原数据
* @param clz 转换类型
* @param <T>
* @param <S>
* @return
*/
public <T, S> List<T> convertor(List<S> source, Class<T> clz) {
if (source == null) {
return null;
}
List<T> map = new ArrayList<>();
for (S s : source) {
map.add(mapper.map(s, clz));
}
return map;
}
/**
* Set 实体类 深度转换器
*
* @param source 原数据
* @param clz 目标对象
* @param <T>
* @param <S>
* @return
*/
public <T, S> Set<T> convertor(Set<S> source, Class<T> clz) {
if (source == null) {
return null;
}
Set<T> set = new TreeSet<>();
for (S s : source) {
set.add(mapper.map(s, clz));
}
return set;
}
/**
* 实体类 深度转换器
*
* @param source
* @param clz
* @param <T>
* @param <S>
* @return
*/
public <T, S> T convertor(S source, Class<T> clz) {
if (source == null) {
return null;
}
return mapper.map(source, clz);
}
public void convertor(Object source, Object object) {
mapper.map(source, object);
}
public <T> void copyConvertor(T source, Object object) {
mapper.map(source, object);
}
}

View File

@ -0,0 +1,29 @@
package com.xiaojusurvey.engine.core.workspace;
import com.xiaojusurvey.engine.common.entity.workspace.WorkspaceMember;
import com.xiaojusurvey.engine.core.workspace.param.CreateWorkspaceMemberParam;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* @description:
* @author: wangchenglong
* @time: 2024/7/24 14:23
*/
public interface WorkspaceMemberService {
List<WorkspaceMember> getWorkspaceMembers(String workspaceId, List<String> userId);
List<WorkspaceMember> getWorkspaceMembers(String userId, Integer pageSize, Integer curPage);
List<WorkspaceMember> getWorkspaceMembers(String workspaceId);
WorkspaceMember getWorkspaceMember(String workspaceId, String userId);
String create(CreateWorkspaceMemberParam createWorkspaceMemberParam);
void delete(CreateWorkspaceMemberParam workspaceMemberParam);
void updateRole(@RequestBody CreateWorkspaceMemberParam createWorkspaceMemberParam);
}

View File

@ -0,0 +1,29 @@
package com.xiaojusurvey.engine.core.workspace;
import com.xiaojusurvey.engine.core.workspace.param.WorkspaceParam;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceListVO;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceMemberVO;
import org.springframework.web.bind.annotation.RequestBody;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* @description:
* @author: wangchenglong
* @time: 2024/7/24 14:23
*/
public interface WorkspaceService {
String createWorkspace(HttpServletRequest request, @RequestBody WorkspaceParam workspaceParam);
WorkspaceListVO findAll(HttpServletRequest request, Integer pageSize, Integer curPage, String name);
WorkspaceMemberVO getWorkspaceInfo(HttpServletRequest request, String workspaceId);
void update(HttpServletRequest request, @RequestBody WorkspaceParam workspaceParam, String workspaceId);
void delete(HttpServletRequest request, String workspaceId);
List<WorkspaceMemberVO> findAllByUserId(HttpServletRequest request);
}

View File

@ -0,0 +1,84 @@
package com.xiaojusurvey.engine.core.workspace.impl;
import com.xiaojusurvey.engine.bean.GeneralConvertor;
import com.xiaojusurvey.engine.common.entity.workspace.WorkspaceMember;
import com.xiaojusurvey.engine.common.enums.RecordStatusEnum;
import com.xiaojusurvey.engine.core.workspace.WorkspaceMemberService;
import com.xiaojusurvey.engine.core.workspace.param.CreateWorkspaceMemberParam;
import com.xiaojusurvey.engine.repository.MongoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* @description: 空间成员
* @author: wangchenglong
* @time: 2024/7/24 14:23
*/
@Service
public class WorkspaceMemberServiceImpl implements WorkspaceMemberService {
@Autowired
private MongoRepository mongoRepository;
@Autowired
private GeneralConvertor convertors;
@Override
public List<WorkspaceMember> getWorkspaceMembers(String workspaceId, List<String> userId) {
return mongoRepository.findList(new Query().addCriteria(Criteria.where("workspaceId").is(workspaceId))
.addCriteria(Criteria.where("userId").in(userId)), WorkspaceMember.class);
}
@Override
public WorkspaceMember getWorkspaceMember(String workspaceId, String userId) {
return mongoRepository.findOne(new Query().addCriteria(Criteria.where("workspaceId").is(workspaceId))
.addCriteria(Criteria.where("userId").is(userId)), WorkspaceMember.class);
}
@Override
public String create(CreateWorkspaceMemberParam createWorkspaceMemberParam) {
WorkspaceMember workspaceMemberDto = convertors.convertor(createWorkspaceMemberParam, WorkspaceMember.class);
WorkspaceMember workspaceMember = mongoRepository.save(workspaceMemberDto);
return workspaceMember.getId();
}
/**
* 查询当前用户参与的空间
* @param userId
* @return
*/
@Override
public List<WorkspaceMember> getWorkspaceMembers(String userId, Integer pageSize, Integer curPage) {
List<WorkspaceMember> workspaceMembers = mongoRepository.page(new Query().addCriteria(Criteria.where("userId").is(userId))
.addCriteria(Criteria.where("curStatus.status").ne(RecordStatusEnum.REMOVED.getStatusType()))
.with(Sort.by(Sort.Direction.ASC, "createDate")),
curPage, pageSize, WorkspaceMember.class);
return workspaceMembers;
}
@Override
public List<WorkspaceMember> getWorkspaceMembers(String workspaceId) {
return mongoRepository.findList(new Query().addCriteria(Criteria.where("workspaceId").is(workspaceId))
.with(Sort.by(Sort.Direction.ASC, "createDate")), WorkspaceMember.class);
}
@Override
public void delete(CreateWorkspaceMemberParam workspaceMemberParam) {
mongoRepository.delete(new Query().addCriteria(Criteria.where("workspaceId").is(workspaceMemberParam.getWorkspaceId()))
.addCriteria(Criteria.where("userId").is(workspaceMemberParam.getUserId())), WorkspaceMember.class);
}
@Override
public void updateRole(@RequestBody CreateWorkspaceMemberParam createWorkspaceMemberParam) {
mongoRepository.updateFirst(new Query().addCriteria(Criteria.where("workspaceId").is(createWorkspaceMemberParam.getWorkspaceId()))
.addCriteria(Criteria.where("_id").is(createWorkspaceMemberParam.getUserId())),
new Update().set("role", createWorkspaceMemberParam.getRole()), WorkspaceMember.class);
}
}

View File

@ -0,0 +1,205 @@
package com.xiaojusurvey.engine.core.workspace.impl;
import com.xiaojusurvey.engine.bean.GeneralConvertor;
import com.xiaojusurvey.engine.common.constants.RespErrorCode;
import com.xiaojusurvey.engine.common.entity.InitBaseEntity;
import com.xiaojusurvey.engine.common.entity.survey.SurveyMeta;
import com.xiaojusurvey.engine.common.entity.user.User;
import com.xiaojusurvey.engine.common.entity.workspace.Workspace;
import com.xiaojusurvey.engine.common.entity.workspace.WorkspaceMember;
import com.xiaojusurvey.engine.common.enums.RecordStatusEnum;
import com.xiaojusurvey.engine.common.enums.RoleEmum;
import com.xiaojusurvey.engine.common.exception.ServiceException;
import com.xiaojusurvey.engine.core.reslut.IdResult;
import com.xiaojusurvey.engine.core.workspace.WorkspaceMemberService;
import com.xiaojusurvey.engine.core.workspace.WorkspaceService;
import com.xiaojusurvey.engine.core.workspace.param.MemberParam;
import com.xiaojusurvey.engine.core.workspace.param.WorkspaceParam;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceInfoVO;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceListVO;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceMemberVO;
import com.xiaojusurvey.engine.repository.MongoRepository;
import com.xiaojusurvey.engine.repository.interceptor.MongoEntityInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @description: 空间
* @author: wangchenglong
* @time: 2024/7/24 14:23
*/
@Slf4j
@Service
public class WorkspaceServiceImpl implements WorkspaceService {
@Autowired
private MongoRepository mongoRepository;
@Autowired
private GeneralConvertor convertors;
@Autowired
private WorkspaceMemberService memberService;
@Autowired
private MongoEntityInterceptor mongoEntityInterceptor;
/**
* 创建空间
* @param request
* @param param
* @return
*/
@Override
public String createWorkspace(HttpServletRequest request, WorkspaceParam param) {
Workspace workspace = this.convertors.convertor(param, Workspace.class);
User user = (User) request.getAttribute("user");
IdResult idResult = new IdResult();
idResult.setId(mongoRepository.save(workspace.setOwnerId(user.getId())).getId());
if (!CollectionUtils.isEmpty(param.getMembers())) {
// 不能重复添加用户
List<String> userIds = param.getMembers().stream().map(MemberParam::getUserId).collect(Collectors.toList());
List<WorkspaceMember> workspaceMembers = memberService.getWorkspaceMembers(idResult.getId(), userIds);
if (!CollectionUtils.isEmpty(workspaceMembers)) {
throw new ServiceException("不能重复添加用户", RespErrorCode.PARAMETER_ERROR.getCode());
}
// 用户不存在
param.getMembers().stream().forEach(member -> {
User memberUser = mongoRepository.findOne(new Query().addCriteria(Criteria.where("_id").is(member.getUserId())), User.class);
if (ObjectUtils.isEmpty(memberUser)) {
throw new ServiceException("用户id:" + member.getUserId() + "不存在", RespErrorCode.USER_NOT_EXISTS.getCode());
}
});
List<WorkspaceMember> members = this.convertors.convertor(param.getMembers(), WorkspaceMember.class);
members = members.stream().map(member -> member.setWorkspaceId(idResult.getId())).collect(Collectors.toList());
members.add(new WorkspaceMember().setUserId(user.getId()).setWorkspaceId(idResult.getId()).setRole(RoleEmum.ADMIN.getValue()));
mongoRepository.batchSave(members, WorkspaceMember.class);
}
return idResult.getId();
}
/**
* 获取空间列表
* @param request
* @param pageSize
* @param curPage
* @param name
* @return
*/
@Override
public WorkspaceListVO findAll(HttpServletRequest request, Integer pageSize, Integer curPage, String name) {
curPage -= 1;
User user = (User) request.getAttribute("user");
// 查询当前用户参与的空间
List<WorkspaceMember> workspaceMembers = memberService.getWorkspaceMembers(user.getId(), pageSize, curPage);
List<WorkspaceInfoVO> workspaceInfos = new ArrayList<>();
workspaceMembers.stream().forEach(workspaceMember -> {
// 成员数量
Long count = mongoRepository.count(new Query().addCriteria(Criteria.where("workspaceId").is(workspaceMember.getWorkspaceId())), WorkspaceMember.class);
Workspace workspace = mongoRepository.findOne(new Query().addCriteria(Criteria.where("_id").is(workspaceMember.getWorkspaceId())).addCriteria(Criteria.where("curStatus.status").ne(RecordStatusEnum.REMOVED.getStatusType())), Workspace.class);
// 问卷数量
Long surveyCount = mongoRepository.count(new Query().addCriteria(Criteria.where("workspaceId").is(workspaceMember.getWorkspaceId())), SurveyMeta.class);
if (!ObjectUtils.isEmpty(workspace)) {
WorkspaceInfoVO convertor = this.convertors.convertor(workspace, WorkspaceInfoVO.class);
workspaceInfos.add(convertor.setCurrentUserId(user.getId())
.setCurrentUserRole(workspaceMembers.stream().filter(member -> member.getWorkspaceId().equals(workspaceMember.getWorkspaceId())).findFirst().get().getRole())
.setMemberTotal(count)
.setSurveyTotal(surveyCount)
.setOwner(workspace.getOwnerId().equals(user.getId()) ? user.getUsername() : mongoRepository.findOne(new Query().addCriteria(Criteria.where("_id").is(workspace.getOwnerId())), User.class).getUsername())
.setOwnerId(workspace.getOwnerId()));
}
});
return new WorkspaceListVO().setData(workspaceInfos).setCount(workspaceMembers.size());
}
@Override
public WorkspaceMemberVO getWorkspaceInfo(HttpServletRequest request, String workspaceId) {
User user = (User) request.getAttribute("user");
Workspace workspace = mongoRepository.findOne(new Query().addCriteria(Criteria.where("_id").is(workspaceId)), Workspace.class);
WorkspaceMemberVO workspaceMember = this.convertors.convertor(workspace, WorkspaceMemberVO.class);
List<WorkspaceMember> workspaceMembers = memberService.getWorkspaceMembers(workspaceId);
List<WorkspaceMemberVO.MembersVO> members = this.convertors.convertor(workspaceMembers, WorkspaceMemberVO.MembersVO.class);
workspaceMember.setCurrentUserId(user.getId()).setMembers(members);
workspaceMember.getMembers().forEach(member -> member.setWorkspaceId(workspaceId).setUsername(member.getUserId().equals(user.getId()) ? user.getUsername() : mongoRepository.findOne(new Query().addCriteria(Criteria.where("_id").is(member.getUserId())), User.class).getUsername()));
return workspaceMember;
}
@Override
public void update(HttpServletRequest request, WorkspaceParam workspaceParam, String workspaceId) {
if (CollectionUtils.isEmpty(workspaceParam.getMembers())) {
throw new ServiceException("成员不能为空", RespErrorCode.PARAMETER_ERROR.getCode());
}
// 更新空间信息
Workspace convertor = convertors.convertor(workspaceParam, Workspace.class);
mongoRepository.updateFirst(new Query().addCriteria(Criteria.where("_id").is(workspaceId)),
new Update().set("name", convertor.getName()).set("description", convertor.getDescription()), Workspace.class);
// 空间不能没有管理员
boolean flag = workspaceParam.getMembers().stream().map(member -> member.getRole()).collect(Collectors.toList()).contains(RoleEmum.ADMIN.getValue());
if (!flag) {
throw new ServiceException("空间不能没有管理员", RespErrorCode.PARAMETER_ERROR.getCode());
}
// 不能有重复的userId
List<String> userIds = workspaceParam.getMembers().stream().map(member -> member.getUserId()).distinct().collect(Collectors.toList());
if (userIds.size() != workspaceParam.getMembers().size()) {
throw new ServiceException("不能重复添加用户", RespErrorCode.PARAMETER_ERROR.getCode());
}
// 删除历史成员
List<String> oldWorkspaceUserId = mongoRepository.findList(new Query().addCriteria(Criteria.where("workspaceId").is(workspaceId)), WorkspaceMember.class).stream().map(WorkspaceMember::getUserId).collect(Collectors.toList());
oldWorkspaceUserId.removeAll(userIds);
mongoRepository.delete(new Query().addCriteria(Criteria.where("workspaceId").is(workspaceId))
.addCriteria(Criteria.where("userId").in(oldWorkspaceUserId)), WorkspaceMember.class);
// 检查所有成员是否真实存在
workspaceParam.getMembers().stream().forEach(member -> {
User memberUser = mongoRepository.findOne(new Query().addCriteria(Criteria.where("_id").is(member.getUserId())), User.class);
if (ObjectUtils.isEmpty(memberUser)) {
throw new ServiceException("用户id:" + member.getUserId() + "不存在", RespErrorCode.USER_NOT_EXISTS.getCode());
}
// 修改成员信息
WorkspaceMember workspaceMember = memberService.getWorkspaceMember(workspaceId, memberUser.getId());
if (ObjectUtils.isEmpty(workspaceMember)) {
mongoRepository.save(new WorkspaceMember().setUserId(memberUser.getId()).setWorkspaceId(workspaceId).setRole(member.getRole()));
} else {
if (workspaceMember.getRole() != member.getRole()) {
mongoRepository.updateFirst(new Query().addCriteria(Criteria.where("_id").is(workspaceMember.getId()))
.addCriteria(Criteria.where("workspaceId").is(workspaceId)), new Update().set("role", member.getRole()), WorkspaceMember.class);
}
}
});
}
@Override
public void delete(HttpServletRequest request, String workspaceId) {
Workspace workspace = mongoRepository.findOne(new Query().addCriteria(Criteria.where("_id").is(workspaceId)), Workspace.class);
// 更新空间状态
InitBaseEntity initBaseEntity = mongoEntityInterceptor.updateDocument(workspace.getStatusList());
mongoRepository.updateMulti(new Query().addCriteria(Criteria.where("_id").is(workspaceId)),
new Update().set("curStatus", initBaseEntity.getCurStatus())
.set("statusList", initBaseEntity.getStatusList()), Workspace.class);
// 更新空间下的问卷状态
mongoRepository.updateMulti(new Query().addCriteria(Criteria.where("workspaceId").is(workspaceId)),
new Update().set("curStatus", initBaseEntity.getCurStatus())
.set("statusList", initBaseEntity.getStatusList()), SurveyMeta.class);
}
@Override
public List<WorkspaceMemberVO> findAllByUserId(HttpServletRequest request) {
List<WorkspaceMemberVO> workspaceMembers = new ArrayList<>();
User user = (User) request.getAttribute("user");
List<Workspace> workspaces = mongoRepository.findList(new Query().addCriteria(Criteria.where("ownerId").is(user.getId())).with(Sort.by(Sort.Direction.DESC, "createDate")), Workspace.class);
workspaces.stream().forEach(workspace -> workspaceMembers.add(this.getWorkspaceInfo(request, workspace.getId())));
return workspaceMembers;
}
}

View File

@ -0,0 +1,18 @@
package com.xiaojusurvey.engine.core.workspace.param;
import lombok.Data;
/**
* @description:
* @author: wangchenglong
* @time: 2024/8/1 11:17
*/
@Data
public class CreateWorkspaceMemberParam {
private String userId;
private String role;
private String workspaceId;
}

View File

@ -0,0 +1,16 @@
package com.xiaojusurvey.engine.core.workspace.param;
import lombok.Data;
/**
* @description:
* @author: wangchenglong
* @time: 2024/7/24 14:44
*/
@Data
public class MemberParam {
private String userId;
private String role;
}

View File

@ -0,0 +1,29 @@
package com.xiaojusurvey.engine.core.workspace.param;
import com.xiaojusurvey.engine.common.entity.BaseEntity;
import lombok.Data;
import java.util.List;
/**
* @description: 空间Dto
* @author: wangchenglong
* @time: 2024/7/24 14:37
*/
@Data
public class WorkspaceParam extends BaseEntity {
/**
* 空间名称
*/
private String name;
/**
* 空间描述
*/
private String description;
/**
* 空间创建者
*/
private List<MemberParam> members;
}

View File

@ -0,0 +1,58 @@
package com.xiaojusurvey.engine.core.workspace.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* @description: 空间信息VO
* @author: wangchenglong
* @time: 2024/7/25 14:23
*/
@Data
public class WorkspaceInfoVO {
/**
* 空间 id
*/
@JsonProperty("_id")
private String id;
/**
* 所有者id
*/
private String ownerId;
/**
* 所有者用户名
*/
private String owner;
/**
* 空间名称
*/
private String name;
/**
* 空间描述
*/
private String description;
/**
* 当前用户的
*/
private String currentUserId;
/**
* 当前用户的角色枚举adminuser
*/
private String currentUserRole;
/**
* 包含的问卷总数
*/
private Long surveyTotal;
/**
* 包含的成员总数
*/
private Long memberTotal;
}

View File

@ -0,0 +1,16 @@
package com.xiaojusurvey.engine.core.workspace.vo;
import lombok.Data;
import java.util.List;
/**
* @description: 空间信息VO
* @author: wangchenglong
* @time: 2024/7/25 14:23
*/
@Data
public class WorkspaceListVO {
private List<WorkspaceInfoVO> data;
private Integer count;
}

View File

@ -0,0 +1,15 @@
package com.xiaojusurvey.engine.core.workspace.vo;
import lombok.Data;
/**
* @description:
* @author: wangchenglong
* @time: 2024/8/1 14:28
*/
@Data
public class WorkspaceMemberIdVO {
private String memberId;
}

View File

@ -0,0 +1,32 @@
package com.xiaojusurvey.engine.core.workspace.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* @description:
* @author: wangchenglong
* @time: 2024/7/25 19:38
*/
@Data
public class WorkspaceMemberVO {
private String name;
private String description;
private String currentUserId;
@JsonProperty("_id")
private String id;
private List<MembersVO> members;
@Data
public static class MembersVO {
@JsonProperty("_id")
private String id;
private String userId;
private String username;
private String role;
private String workspaceId;
}
}

View File

@ -0,0 +1,17 @@
package com.xiaojusurvey.engine.core.workspace.vo;
import lombok.Data;
/**
* @description: 空间VO
* @author: wangchenglong
* @time: 2024/7/24 14:37
*/
@Data
public class WorkspaceVO {
/**
* 新建的空间 id
*/
private String workspaceId;
}

View File

@ -90,4 +90,13 @@ public interface MongoRepository {
* 多条件分页查询
*/
<T extends BaseEntity> List<T> page(Query query, int pageIndex, int pageSize, Class<T> entityClass);
/**
* 多条件查询
* @param query
* @param entityClass
* @param <T>
* @return
*/
<T extends BaseEntity> List<T> findList(Query query, Class<T> entityClass);
}

View File

@ -113,4 +113,9 @@ public class MongoRepositoryImpl implements MongoRepository {
return mongoTemplate.find(query, entityClass);
}
@Override
public <T extends BaseEntity> List<T> findList(Query query, Class<T> entityClass) {
return mongoTemplate.find(query, entityClass);
}
}

View File

@ -0,0 +1,20 @@
package com.xiaojusurvey.engine.repository.interceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
/**
* @description: MongoEntityInterceptor
* @author: wangchenglong
* @time: 2024/7/30 17:36
*/
@Configuration
@EnableMongoAuditing
public class MongoConfig {
@Bean
public MongoEntityInterceptor auditEntityMongoListener() {
return new MongoEntityInterceptor();
}
}

View File

@ -0,0 +1,53 @@
package com.xiaojusurvey.engine.repository.interceptor;
import com.xiaojusurvey.engine.common.entity.BaseEntity;
import com.xiaojusurvey.engine.common.entity.InitBaseEntity;
import com.xiaojusurvey.engine.common.entity.Status;
import com.xiaojusurvey.engine.common.enums.RecordStatusEnum;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.util.Arrays;
import java.util.List;
/**
* @description: mongodb事件拦截器
* @author: wangchenglong
* @time: 2024/7/30 16:37
* @param <T>
*/
@Component
public class MongoEntityInterceptor<T> extends AbstractMongoEventListener<T> {
@Override
public void onBeforeConvert(BeforeConvertEvent<T> event) {
Object entity = event.getSource();
long time = System.currentTimeMillis();
if (entity instanceof BaseEntity) {
String id = ((BaseEntity) entity).getId();
if (ObjectUtils.isEmpty(id)) {
Status status = new Status().setStatus(RecordStatusEnum.NEW.getStatusType()).setDate(time);
((BaseEntity) entity).setCurStatus(status)
.setCreateDate(time).setUpdateDate(time)
.setStatusList(Arrays.asList(status));
}
}
}
/**
* 更新操作维护公共字段
* @param statusList
* @return
*/
public InitBaseEntity updateDocument(List<Status> statusList) {
long time = System.currentTimeMillis();
Status status = new Status().setStatus(RecordStatusEnum.REMOVED.getStatusType()).setDate(time);
statusList.add(status);
return (InitBaseEntity) new InitBaseEntity().setUpdateDate(time)
.setCurStatus(status)
.setStatusList(statusList);
}
}

View File

@ -0,0 +1,99 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.common.util.RpcResultUtil;
import com.xiaojusurvey.engine.core.workspace.WorkspaceService;
import com.xiaojusurvey.engine.core.workspace.param.WorkspaceParam;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceListVO;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceMemberVO;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* @description: 空间
* @author: wangchenglong
* @time: 2024/7/24 14:33
*/
@RequestMapping("/api/workspace")
@RestController
public class WorkspaceController {
@Autowired
private WorkspaceService workspaceService;
/**
* 创建空间
* @param request
* @param workspaceParam
* @return
*/
@PostMapping
public RpcResult<WorkspaceVO> create(HttpServletRequest request, @RequestBody WorkspaceParam workspaceParam) {
return RpcResultUtil.createSuccessResult(new WorkspaceVO().setWorkspaceId(workspaceService.createWorkspace(request, workspaceParam)));
}
/**
* 获取空间列表
* @param request
* @param pageSize
* @param curPage
* @param name
* @return
*/
@GetMapping
public RpcResult<WorkspaceListVO> findAll(HttpServletRequest request, @RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(defaultValue = "1") Integer curPage, String name) {
return RpcResultUtil.createSuccessResult(workspaceService.findAll(request, pageSize, curPage, name));
}
/**
* 获取空间详情
* @param request
* @param workspaceId
* @return
*/
@GetMapping("/{workspaceId}")
public RpcResult<WorkspaceMemberVO> getWorkspaceInfo(HttpServletRequest request, @PathVariable String workspaceId) {
return RpcResultUtil.createSuccessResult(workspaceService.getWorkspaceInfo(request, workspaceId));
}
/**
* 更新空间详情
* @param request
* @param workspaceId
* @param workspaceParam
* @return
*/
@PostMapping("/{workspaceId}")
public RpcResult<?> update(HttpServletRequest request, @PathVariable String workspaceId, @RequestBody WorkspaceParam workspaceParam) {
workspaceService.update(request, workspaceParam, workspaceId);
return RpcResultUtil.createSuccessResult(true);
}
/**
* 删除空间
* @param request
* @param workspaceId
* @return
*/
@DeleteMapping("/{workspaceId}")
public RpcResult<?> delete(HttpServletRequest request, @PathVariable String workspaceId) {
workspaceService.delete(request, workspaceId);
return RpcResultUtil.createSuccessResult(true);
}
/**
* 获取空间成员列表
* @param request
* @return
*/
@GetMapping("/member/list")
public RpcResult<List<WorkspaceMemberVO>> getWorkspaceAndMember(HttpServletRequest request) {
return RpcResultUtil.createSuccessResult(workspaceService.findAllByUserId(request));
}
}

View File

@ -0,0 +1,59 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.common.util.RpcResultUtil;
import com.xiaojusurvey.engine.core.workspace.WorkspaceMemberService;
import com.xiaojusurvey.engine.core.workspace.param.CreateWorkspaceMemberParam;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceMemberIdVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description: 空间空间成员
* @author: wangchenglong
* @time: 2024/8/1 14:33
*/
@RequestMapping("/api/workspaceMember")
@RestController
public class WorkspaceMemberController {
@Autowired
private WorkspaceMemberService workspaceMemberService;
/**
* 添加空间成员
* @param createWorkspaceMemberParam
* @return
*/
@PostMapping
public RpcResult<WorkspaceMemberIdVO> create(@RequestBody CreateWorkspaceMemberParam createWorkspaceMemberParam) {
return RpcResultUtil.createSuccessResult(new WorkspaceMemberIdVO().setMemberId(workspaceMemberService.create(createWorkspaceMemberParam)));
}
/**
* 更新空间成员角色
* @param createWorkspaceMemberParam
* @return
*/
@PostMapping("/updateRole")
public RpcResult<?> updateRole(@RequestBody CreateWorkspaceMemberParam createWorkspaceMemberParam) {
workspaceMemberService.updateRole(createWorkspaceMemberParam);
return RpcResultUtil.createSuccessResult(true);
}
/**
* 删除空间成员
* @param workspaceMemberParam
* @return
*/
@PostMapping("/deleteMember")
public RpcResult<?> delete(@RequestBody CreateWorkspaceMemberParam workspaceMemberParam) {
workspaceMemberService.delete(workspaceMemberParam);
return RpcResultUtil.createSuccessResult(true);
}
}

View File

@ -0,0 +1,127 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.core.workspace.WorkspaceService;
import com.xiaojusurvey.engine.core.workspace.param.WorkspaceParam;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceListVO;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceMemberVO;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceVO;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
/**
* @description: WorkspaceController测试
* @author: wangchenglong
* @time: 2024/8/1 16:52
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class WorkspaceControllerTest {
@InjectMocks
private WorkspaceController workspaceController;
@Mock
private WorkspaceService workspaceService;
private MockHttpServletRequest mockRequest;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockRequest = new MockHttpServletRequest();
}
@Test
public void testCreateWorkspace() {
WorkspaceParam mockWorkspaceParam = new WorkspaceParam();
String workspaceId = "123456";
when(workspaceService.createWorkspace(any(HttpServletRequest.class), any(WorkspaceParam.class)))
.thenReturn(workspaceId);
RpcResult<WorkspaceVO> result = workspaceController.create(mockRequest, mockWorkspaceParam);
assertEquals(true, result.getSuccess());
assertEquals(workspaceId, result.getData().getWorkspaceId());
}
@Test
public void testFindAllWorkspaces() {
int pageSize = 10;
int curPage = 1;
String name = "TestWorkspace";
WorkspaceListVO mockListVO = new WorkspaceListVO();
when(workspaceService.findAll(any(HttpServletRequest.class), eq(pageSize), eq(curPage), eq(name)))
.thenReturn(mockListVO);
RpcResult<WorkspaceListVO> result = workspaceController.findAll(mockRequest, pageSize, curPage, name);
assertEquals(true, result.getSuccess());
assertNotNull(result.getData());
}
@Test
public void testGetWorkspaceInfo() {
String workspaceId = "123456";
WorkspaceMemberVO mockMemberVO = new WorkspaceMemberVO();
when(workspaceService.getWorkspaceInfo(any(HttpServletRequest.class), eq(workspaceId)))
.thenReturn(mockMemberVO);
RpcResult<WorkspaceMemberVO> result = workspaceController.getWorkspaceInfo(mockRequest, workspaceId);
assertEquals(true, result.getSuccess());
assertNotNull(result.getData());
}
@Test
public void testUpdateWorkspace() {
String workspaceId = "123456";
WorkspaceParam mockWorkspaceParam = new WorkspaceParam();
RpcResult<?> result = workspaceController.update(mockRequest, workspaceId, mockWorkspaceParam);
assertEquals(true, result.getSuccess());
verify(workspaceService, times(1)).update(any(HttpServletRequest.class), eq(mockWorkspaceParam), eq(workspaceId));
}
@Test
public void testDeleteWorkspace() {
String workspaceId = "123456";
RpcResult<?> result = workspaceController.delete(mockRequest, workspaceId);
assertEquals(true, result.getSuccess());
verify(workspaceService, times(1)).delete(any(HttpServletRequest.class), eq(workspaceId));
}
@Test
public void testGetWorkspaceAndMemberList() {
List<WorkspaceMemberVO> mockMemberList = new ArrayList<>();
when(workspaceService.findAllByUserId(any(HttpServletRequest.class)))
.thenReturn(mockMemberList);
RpcResult<List<WorkspaceMemberVO>> result = workspaceController.getWorkspaceAndMember(mockRequest);
assertEquals(true, result.getSuccess());
assertEquals(mockMemberList, result.getData());
}
}

View File

@ -0,0 +1,71 @@
package com.xiaojusurvey.engine.controller;
import com.xiaojusurvey.engine.common.rpc.RpcResult;
import com.xiaojusurvey.engine.core.workspace.WorkspaceMemberService;
import com.xiaojusurvey.engine.core.workspace.param.CreateWorkspaceMemberParam;
import com.xiaojusurvey.engine.core.workspace.vo.WorkspaceMemberIdVO;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
/**
* @description: WorkspaceMemberController 测试
* @author: wangchenglong
* @time: 2024/8/1 17:23
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class WorkspaceMemberControllerTest {
@InjectMocks
private WorkspaceMemberController workspaceMemberController;
@Mock
private WorkspaceMemberService workspaceMemberService;
private MockHttpServletRequest mockRequest;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockRequest = new MockHttpServletRequest();
}
@Test
public void testCreateWorkspaceMember() {
CreateWorkspaceMemberParam mockParam = new CreateWorkspaceMemberParam();
String memberId = "123456";
when(workspaceMemberService.create(any(CreateWorkspaceMemberParam.class)))
.thenReturn(memberId);
RpcResult<WorkspaceMemberIdVO> result = workspaceMemberController.create(mockParam);
assertEquals(true, result.getSuccess());
assertEquals(memberId, result.getData().getMemberId());
}
@Test
public void testUpdateWorkspaceMemberRole() {
CreateWorkspaceMemberParam mockParam = new CreateWorkspaceMemberParam();
RpcResult<?> result = workspaceMemberController.updateRole(mockParam);
assertEquals(true, result.getSuccess());
}
@Test
public void testDeleteWorkspaceMember() {
CreateWorkspaceMemberParam mockParam = new CreateWorkspaceMemberParam();
RpcResult<?> result = workspaceMemberController.delete(mockParam);
assertEquals(true, result.getSuccess());
}
}