feat(系统设置): 创建用户功能开发

This commit is contained in:
song-tianyang 2023-06-09 11:02:42 +08:00 committed by 建国
parent 2ed0923b2d
commit e8fa426f91
20 changed files with 769 additions and 581 deletions

View File

@ -1,15 +1,20 @@
package io.metersphere.system.domain;
import io.metersphere.validation.groups.*;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
@Data
public class User implements Serializable {
@Schema(title = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{user.id.not_blank}", groups = {Created.class, Updated.class})
@NotBlank(message = "{user.id.not_blank}", groups = {Updated.class})
@Size(min = 1, max = 50, message = "{user.id.length_range}", groups = {Created.class, Updated.class})
private String id;
@ -19,15 +24,16 @@ public class User implements Serializable {
private String name;
@Schema(title = "用户邮箱", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{user.email.not_blank}", groups = {Created.class})
@NotBlank(message = "{user.email.not_blank}", groups = {Created.class, Updated.class})
@Size(min = 1, max = 64, message = "{user.email.length_range}", groups = {Created.class, Updated.class})
@Email(message = "{user.email.invalid}", groups = {Created.class, Updated.class})
private String email;
@Schema(title = "用户密码")
private String password;
@Schema(title = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "{user.enable.not_blank}", groups = {Created.class})
@NotNull(message = "{user.enable.not_blank}", groups = {Updated.class})
private Boolean enable;
@Schema(title = "创建时间")

View File

@ -48,9 +48,7 @@ public class LoginController {
}
return ResultHolder.success(sessionUser);
}
MSException.throwException(rsaKey.getPublicKey());
//
return null;
throw new MSException(rsaKey.getPublicKey());
}
@PostMapping(value = "/login")
@ -58,7 +56,7 @@ public class LoginController {
SessionUser sessionUser = SessionUtils.getUser();
if (sessionUser != null) {
if (!StringUtils.equals(sessionUser.getId(), request.getUsername())) {
MSException.throwException(Translator.get("please_logout_current_user"));
throw new MSException(Translator.get("please_logout_current_user"));
}
}
SecurityUtils.getSubject().getSession().setAttribute("authenticate", UserSource.LOCAL.name());

View File

@ -11,36 +11,26 @@ public class MSException extends RuntimeException {
super(message);
}
public MSException(IResultCode errorCode) {
super(StringUtils.EMPTY);
this.errorCode = errorCode;
}
public MSException(IResultCode errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public static void throwException(IResultCode errorCode, String message) {
throw new MSException(errorCode, message);
}
public MSException(IResultCode errorCode, Throwable t) {
super(t);
this.errorCode = errorCode;
}
public static void throwException(String message) {
throw new MSException(message);
}
public static void throwException(Throwable t) {
throw new MSException(null, t);
}
public static void throwException(IResultCode errorCode) {
throw new MSException(errorCode, StringUtils.EMPTY);
}
public static void throwException(IResultCode errorCode, String message) {
throw new MSException(errorCode, message);
}
public static void throwException(IResultCode errorCode, Throwable t) {
throw new MSException(errorCode, t);
}
public IResultCode getErrorCode() {
return errorCode;
}

View File

@ -7,6 +7,8 @@ import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface BaseUserMapper {
UserDTO selectByEmail(String email);
UserDTO selectById(String id);
List<User> findAll();
@ -14,4 +16,8 @@ public interface BaseUserMapper {
void batchSave(@Param("users") List<User> users);
boolean isSuperUser(String userId);
String selectEmailInDB(@Param("email") String email, @Param("id") String id);
List<User> selectUserIdByEmailList(@Param("emailList") List<String> emailList);
}

View File

@ -8,6 +8,13 @@
WHERE user.id = #{id}
</select>
<select id="selectByEmail" resultType="io.metersphere.sdk.dto.UserDTO">
SELECT *
FROM user
LEFT JOIN user_extend ON user.id = user_extend.id
WHERE user.email = #{email}
</select>
<select id="findAll" resultType="io.metersphere.system.domain.User">
SELECT *
FROM user
@ -31,4 +38,18 @@
WHERE user_id = #{userId}
AND role_id = 'super'
</select>
<select id="selectEmailInDB" resultType="java.lang.String">
SELECT u.email FROM user u
WHERE u.email = #{email}
<if test="id != null">
AND u.id != #{id}
</if>
</select>
<select id="selectUserIdByEmailList" resultType="io.metersphere.system.domain.User">
SELECT u.id,u.email FROM user u
WHERE u.email IN
<foreach collection="emailList" item="email" open="(" separator="," close=")">
#{email}
</foreach>
</select>
</mapper>

View File

@ -30,9 +30,8 @@ public class PluginManager {
/**
* 加载对应目录下的 jar
*
*/
public PluginManager loadJar(String pluginId, String jarfileDir, StorageStrategy storageStrategy) throws IOException {
public PluginManager loadJar(String pluginId, String jarfileDir, StorageStrategy storageStrategy) throws IOException {
PluginClassLoader pluginClassLoader = new PluginClassLoader(storageStrategy);
classLoaderMap.put(pluginId, pluginClassLoader);
pluginClassLoader.loadJar(jarfileDir);
@ -91,12 +90,11 @@ public class PluginManager {
return clazz.getConstructor().newInstance();
} catch (InvocationTargetException e) {
LogUtils.error(e);
MSException.throwException(CommonResultCode.PLUGIN_GET_INSTANCE, e.getTargetException().getMessage());
throw new MSException(CommonResultCode.PLUGIN_GET_INSTANCE, e.getTargetException().getMessage());
} catch (Exception e) {
LogUtils.error(e);
MSException.throwException(CommonResultCode.PLUGIN_GET_INSTANCE, e.getMessage());
throw new MSException(CommonResultCode.PLUGIN_GET_INSTANCE, e.getMessage());
}
return null;
}
public <T> T getImplInstance(String pluginId, Class<T> superClazz, Object param) {
@ -105,12 +103,11 @@ public class PluginManager {
return clazz.getConstructor(param.getClass()).newInstance(param);
} catch (InvocationTargetException e) {
LogUtils.error(e.getTargetException());
MSException.throwException(CommonResultCode.PLUGIN_GET_INSTANCE, e.getTargetException().getMessage());
throw new MSException(CommonResultCode.PLUGIN_GET_INSTANCE, e.getTargetException().getMessage());
} catch (Exception e) {
LogUtils.error(e);
MSException.throwException(CommonResultCode.PLUGIN_GET_INSTANCE, e.getMessage());
throw new MSException(CommonResultCode.PLUGIN_GET_INSTANCE, e.getMessage());
}
return null;
}

View File

@ -291,7 +291,7 @@ public class BaseUserService {
criteria.andEmailEqualTo(user.getEmail());
criteria.andIdNotEqualTo(user.getId());
if (userMapper.countByExample(example) > 0) {
MSException.throwException(Translator.get("user_email_already_exists"));
throw new MSException(Translator.get("user_email_already_exists"));
}
}
user.setPassword(null);
@ -358,10 +358,10 @@ public class BaseUserService {
public boolean checkUserPassword(String userId, String password) {
if (StringUtils.isBlank(userId)) {
MSException.throwException(Translator.get("user_name_is_null"));
throw new MSException(Translator.get("user_name_is_null"));
}
if (StringUtils.isBlank(password)) {
MSException.throwException(Translator.get("password_is_null"));
throw new MSException(Translator.get("password_is_null"));
}
UserExample example = new UserExample();
example.createCriteria().andIdEqualTo(userId).andPasswordEqualTo(CodingUtil.md5(password));

View File

@ -34,14 +34,14 @@ public class UserKeyService {
public UserKey generateUserKey(String userId) {
if (baseUserService.getUserDTO(userId) == null) {
MSException.throwException(Translator.get("user_not_exist") + userId);
throw new MSException(Translator.get("user_not_exist") + userId);
}
UserKeyExample userKeysExample = new UserKeyExample();
userKeysExample.createCriteria().andCreateUserEqualTo(userId);
List<UserKey> userKeysList = userKeyMapper.selectByExample(userKeysExample);
if (!CollectionUtils.isEmpty(userKeysList) && userKeysList.size() >= 5) {
MSException.throwException(Translator.get("user_apikey_limit"));
throw new MSException(Translator.get("user_apikey_limit"));
}
UserKey userKeys = new UserKey();

View File

@ -1,3 +1,4 @@
user.not.login=User not login
auth_source.id.not_blank=Auth source id must not be blank
auth_source.status.length_range=Auth source status must be between {min} and {max} characters long
auth_source.status.not_blank=Auth source status must not be blank
@ -95,6 +96,8 @@ user.name.not_blank=User name must not be blank
user.name.length_range=User name must be between {min} and {max} characters long
user.email.not_blank=User email must not be blank
user.email.length_range=User email must be between {min} and {max} characters long
user.email.repeat=User email already exists
user.email.invalid=User email is invalid
user.status.not_blank=User status must not be blank
user.status.length_range=User status must be between {min} and {max} characters long
user.source.not_blank=User source must not be blank
@ -109,6 +112,9 @@ user_key.access_key.not_blank=User key access key must not be blank
user_key.access_key.length_range=User key access key must be between {min} and {max} characters long
user_key.secret_key.not_blank=User key secret key must not be blank
user_key.secret_key.length_range=User key secret key must be between {min} and {max} characters long
user.info.not_empty=User info must not be blank
user.organizationId.not_blank=User organization must not be blank
user.projectId.not_blank=User project must not be blank
user_role.id.not_blank=User role id must not be blank
user_role.name.not_blank=User role name must not be blank
user_role.name.length_range=User role name must be between {min} and {max} characters long

View File

@ -1,143 +1,149 @@
auth_source.id.not_blank=认证源ID不能为空
auth_source.status.length_range=认证源状态长度必须在{min}和{max}之间
auth_source.status.not_blank=认证源状态不能为空
license.id.not_blank=License ID不能为空
message_task.id.not_blank=消息通知任务ID不能为空
message_task.type.not_blank=消息通知任务类型不能为空
message_task.type.length_range=消息通知任务类型长度必须在{min}和{max}之间
message_task.event.not_blank=消息通知任务事件不能为空
message_task.event.length_range=消息通知任务事件长度必须在{min}和{max}之间
message_task.receiver.not_blank=消息通知任务接收者不能为空
message_task.receiver.length_range=消息通知任务接收者长度必须在{min}和{max}之间
message_task.task_type.not_blank=消息通知任务任务类型不能为空
message_task.task_type.length_range=消息通知任务任务类型长度必须在{min}和{max}之间
message_task.test_id.not_blank=消息通知任务测试ID不能为空
message_task.test_id.length_range=消息通知任务测试ID长度必须在{min}和{max}之间
message_task.project_id.not_blank=消息通知任务项目ID不能为空
message_task.project_id.length_range=消息通知任务项目ID长度必须在{min}和{max}之间
message_task_blob.id.not_blank=消息通知任务ID不能为空
notification.id.not_blank=消息通知ID不能为空
notification.type.not_blank=消息通知类型不能为空
notification.type.length_range=消息通知类型长度必须在{min}和{max}之间
notification.receiver.not_blank=消息通知接收者不能为空
notification.receiver.length_range=消息通知接收者长度必须在{min}和{max}之间
notification.title.not_blank=消息通知标题不能为空
notification.title.length_range=消息通知标题长度必须在{min}和{max}之间
notification.status.not_blank=消息通知状态不能为空
notification.status.length_range=消息通知状态长度必须在{min}和{max}之间
notification.operator.not_blank=消息通知操作者不能为空
notification.operator.length_range=消息通知操作者长度必须在{min}和{max}之间
notification.operation.not_blank=消息通知操作不能为空
notification.operation.length_range=消息通知操作长度必须在{min}和{max}之间
notification.resource_id.not_blank=消息通知资源ID不能为空
notification.resource_id.length_range=消息通知资源ID长度必须在{min}和{max}之间
notification.resource_type.not_blank=消息通知资源类型不能为空
notification.resource_type.length_range=消息通知资源类型长度必须在{min}和{max}之间
notification.resource_name.not_blank=消息通知资源名称不能为空
notification.resource_name.length_range=消息通知资源名称长度必须在{min}和{max}之间
novice_statistics.id.not_blank=新手村ID不能为空
novice_statistics.guide_step.not_blank=新手村步骤不能为空
novice_statistics.guide_step.length_range=新手村步骤长度必须在{min}和{max}之间
operating_log.id.not_blank=操作日志ID不能为空
operating_log.project_id.not_blank=操作日志项目ID不能为空
operating_log.project_id.length_range=操作日志项目ID长度必须在{min}和{max}之间
operating_log_resource.id.not_blank=操作日志资源ID不能为空
operating_log_resource.operating_log_id.not_blank=操作日志资源操作日志ID不能为空
operating_log_resource.operating_log_id.length_range=操作日志资源操作日志ID长度必须在{min}和{max}之间
operating_log_resource.source_id.not_blank=操作日志资源来源ID不能为空
operating_log_resource.source_id.length_range=操作日志资源来源ID长度必须在{min}和{max}之间
plugin.id.not_blank=插件主键不能为空
plugin.plugin_id.not_blank=插件ID不能为空
plugin.plugin_id.length_range=插件ID长度必须在{min}和{max}之间
plugin.script_id.not_blank=插件脚本ID不能为空
plugin.script_id.length_range=插件脚本ID长度必须在{min}和{max}之间
plugin.clazz_name.not_blank=插件类名不能为空
plugin.clazz_name.length_range=插件类名长度必须在{min}和{max}之间
plugin.jmeter_clazz.not_blank=插件jmeter类名不能为空
plugin.jmeter_clazz.length_range=插件jmeter类名长度必须在{min}和{max}之间
plugin.source_path.not_blank=插件源路径不能为空
plugin.source_path.length_range=插件源路径长度必须在{min}和{max}之间
plugin.source_name.not_blank=插件源名称不能为空
plugin.source_name.length_range=插件源名称长度必须在{min}和{max}之间
plugin.scenario.not_blank=插件场景不能为空
plugin.scenario.length_range=插件场景长度必须在{min}和{max}之间
plugin_blob.id.not_blank=插件ID不能为空
quota.id.not_blank=配额ID不能为空
schedule.id.not_blank=定时任务ID不能为空
schedule.type.not_blank=定时任务类型不能为空
schedule.type.length_range=定时任务类型长度必须在{min}和{max}之间
schedule.value.not_blank=定时任务值不能为空
schedule.value.length_range=定时任务值长度必须在{min}和{max}之间
schedule.job.not_blank=定时任务不能为空
schedule.job.length_range=定时任务长度必须在{min}和{max}之间
schedule.create_user.not_blank=定时任务创建人不能为空
schedule.create_user.length_range=定时任务创建人长度必须在{min}和{max}之间
service_integration.id.not_blank=服务集成ID不能为空
service_integration.platform.not_blank=服务集成平台不能为空
service_integration.platform.length_range=服务集成平台长度必须在{min}和{max}之间
system_parameter.param_key.not_blank=系统参数Key不能为空
system_parameter.type.not_blank=系统参数类型不能为空
system_parameter.type.length_range=系统参数类型长度必须在{min}和{max}之间
test_resource.id.not_blank=资源池节点ID不能为空
test_resource.test_resource_pool_id.not_blank=资源池ID不能为空
test_resource.test_resource_pool_id.length_range=资源池ID长度必须在{min}和{max}之间
test_resource.status.not_blank=资源池节点状态不能为空
test_resource.status.length_range=资源池节点状态长度必须在{min}和{max}之间
test_resource_pool.id.not_blank=资源池ID不能为空
test_resource_pool.name.not_blank=资源池名称不能为空
test_resource_pool.name.length_range=资源池名称长度必须在{min}和{max}之间
test_resource_pool.type.not_blank=资源池类型不能为空
test_resource_pool.type.length_range=资源池类型长度必须在{min}和{max}之间
test_resource_pool.status.not_blank=资源池状态不能为空
test_resource_pool.status.length_range=资源池状态长度必须在{min}和{max}之间
user.id.not_blank=用户ID不能为空
user.name.not_blank=用户名称不能为空
user.name.length_range=用户名称长度必须在{min}和{max}之间
user.email.not_blank=用户email不能为空
user.email.length_range=用户email长度必须在{min}和{max}之间
user.status.not_blank=用户状态不能为空
user.status.length_range=用户状态长度必须在{min}和{max}之间
user.source.not_blank=用户来源不能为空
user.source.length_range=用户来源长度必须在{min}和{max}之间
user.create_user.not_blank=用户创建人不能为空
user.create_user.length_range=用户创建人长度必须在{min}和{max}之间
user_extend.id.not_blank=用户ID不能为空
user_key.id.not_blank=用户ApiKey ID不能为空
user_key.create_user.not_blank=用户ApiKey创建人不能为空
user_key.create_user.length_range=用户ApiKey创建人长度必须在{min}和{max}之间
user_key.access_key.not_blank=用户ApiKey access key不能为空
user_key.access_key.length_range=用户ApiKey access key长度必须在{min}和{max}之间
user_key.secret_key.not_blank=用户ApiKey secret key不能为空
user_key.secret_key.length_range=用户ApiKey secret key长度必须在{min}和{max}之间
user_role.id.not_blank=用户组ID不能为空
user_role.name.not_blank=用户组名称不能为空
user_role.name.length_range=用户组名称长度必须在{min}和{max}之间
user_role.system.not_blank=是否是系统用户组不能为空
user_role.system.length_range=是否是系统用户组长度必须在{min}和{max}之间
user_role.type.not_blank=用户组类型不能为空
user_role.type.length_range=用户组类型长度必须在{min}和{max}之间
user_role.create_user.not_blank=用户组创建人不能为空
user_role.create_user.length_range=用户组创建人长度必须在{min}和{max}之间
user_role.scope_id.not_blank=用户组应用范围不能为空
user_role.scope_id.length_range=用户组应用范围长度必须在{min}和{max}之间
user_role_permission.id.not_blank=用户组权限ID不能为空
user_role_permission.role_id.not_blank=用户组权限用户组ID不能为空
user_role_permission.role_id.length_range=用户组权限用户组ID长度必须在{min}和{max}之间
user_role_permission.permission_id.not_blank=用户组权限权限ID不能为空
user_role_permission.permission_id.length_range=用户组权限权限ID长度必须在{min}和{max}之间
user_role_permission.module_id.not_blank=用户组权限模块ID不能为空
user_role_permission.module_id.length_range=用户组权限模块ID长度必须在{min}和{max}之间
user_role_relation.id.not_blank=用户组关系ID不能为空
user_role_relation.user_id.not_blank=用户组关系用户ID不能为空
user_role_relation.user_id.length_range=用户组关系用户ID长度必须在{min}和{max}之间
user_role_relation.role_id.not_blank=用户组关系用户组ID不能为空
user_role_relation.role_id.length_range=用户组关系用户组ID长度必须在{min}和{max}之间
user_role_relation.source_id.not_blank=用户组关系来源ID不能为空
user_role_relation.source_id.length_range=用户组关系来源ID长度必须在{min}和{max}之间
organization.id.not_blank=工作空间ID不能为空
organization.name.not_blank=工作空间名称不能为空
organization.name.length_range=工作空间名称长度必须在{min}和{max}之间
organization.create_user.not_blank=工作空间创建人不能为空
organization.create_user.length_range=工作空间创建人长度必须在{min}和{max}之间
user.not.login=\u672A\u83B7\u53D6\u5230\u767B\u5F55\u7528\u6237
auth_source.id.not_blank=\u8BA4\u8BC1\u6E90ID\u4E0D\u80FD\u4E3A\u7A7A
auth_source.status.length_range=\u8BA4\u8BC1\u6E90\u72B6\u6001\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
auth_source.status.not_blank=\u8BA4\u8BC1\u6E90\u72B6\u6001\u4E0D\u80FD\u4E3A\u7A7A
license.id.not_blank=License ID\u4E0D\u80FD\u4E3A\u7A7A
message_task.id.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1ID\u4E0D\u80FD\u4E3A\u7A7A
message_task.type.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
message_task.type.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
message_task.event.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u4E8B\u4EF6\u4E0D\u80FD\u4E3A\u7A7A
message_task.event.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u4E8B\u4EF6\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
message_task.receiver.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u63A5\u6536\u8005\u4E0D\u80FD\u4E3A\u7A7A
message_task.receiver.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u63A5\u6536\u8005\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
message_task.task_type.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u4EFB\u52A1\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
message_task.task_type.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u4EFB\u52A1\u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
message_task.test_id.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u6D4B\u8BD5ID\u4E0D\u80FD\u4E3A\u7A7A
message_task.test_id.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u6D4B\u8BD5ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
message_task.project_id.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A
message_task.project_id.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1\u9879\u76EEID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
message_task_blob.id.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52A1ID\u4E0D\u80FD\u4E3A\u7A7A
notification.id.not_blank=\u6D88\u606F\u901A\u77E5ID\u4E0D\u80FD\u4E3A\u7A7A
notification.type.not_blank=\u6D88\u606F\u901A\u77E5\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
notification.type.length_range=\u6D88\u606F\u901A\u77E5\u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
notification.receiver.not_blank=\u6D88\u606F\u901A\u77E5\u63A5\u6536\u8005\u4E0D\u80FD\u4E3A\u7A7A
notification.receiver.length_range=\u6D88\u606F\u901A\u77E5\u63A5\u6536\u8005\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
notification.title.not_blank=\u6D88\u606F\u901A\u77E5\u6807\u9898\u4E0D\u80FD\u4E3A\u7A7A
notification.title.length_range=\u6D88\u606F\u901A\u77E5\u6807\u9898\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
notification.status.not_blank=\u6D88\u606F\u901A\u77E5\u72B6\u6001\u4E0D\u80FD\u4E3A\u7A7A
notification.status.length_range=\u6D88\u606F\u901A\u77E5\u72B6\u6001\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
notification.operator.not_blank=\u6D88\u606F\u901A\u77E5\u64CD\u4F5C\u8005\u4E0D\u80FD\u4E3A\u7A7A
notification.operator.length_range=\u6D88\u606F\u901A\u77E5\u64CD\u4F5C\u8005\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
notification.operation.not_blank=\u6D88\u606F\u901A\u77E5\u64CD\u4F5C\u4E0D\u80FD\u4E3A\u7A7A
notification.operation.length_range=\u6D88\u606F\u901A\u77E5\u64CD\u4F5C\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
notification.resource_id.not_blank=\u6D88\u606F\u901A\u77E5\u8D44\u6E90ID\u4E0D\u80FD\u4E3A\u7A7A
notification.resource_id.length_range=\u6D88\u606F\u901A\u77E5\u8D44\u6E90ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
notification.resource_type.not_blank=\u6D88\u606F\u901A\u77E5\u8D44\u6E90\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
notification.resource_type.length_range=\u6D88\u606F\u901A\u77E5\u8D44\u6E90\u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
notification.resource_name.not_blank=\u6D88\u606F\u901A\u77E5\u8D44\u6E90\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
notification.resource_name.length_range=\u6D88\u606F\u901A\u77E5\u8D44\u6E90\u540D\u79F0\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
novice_statistics.id.not_blank=\u65B0\u624B\u6751ID\u4E0D\u80FD\u4E3A\u7A7A
novice_statistics.guide_step.not_blank=\u65B0\u624B\u6751\u6B65\u9AA4\u4E0D\u80FD\u4E3A\u7A7A
novice_statistics.guide_step.length_range=\u65B0\u624B\u6751\u6B65\u9AA4\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
operating_log.id.not_blank=\u64CD\u4F5C\u65E5\u5FD7ID\u4E0D\u80FD\u4E3A\u7A7A
operating_log.project_id.not_blank=\u64CD\u4F5C\u65E5\u5FD7\u9879\u76EEID\u4E0D\u80FD\u4E3A\u7A7A
operating_log.project_id.length_range=\u64CD\u4F5C\u65E5\u5FD7\u9879\u76EEID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
operating_log_resource.id.not_blank=\u64CD\u4F5C\u65E5\u5FD7\u8D44\u6E90ID\u4E0D\u80FD\u4E3A\u7A7A
operating_log_resource.operating_log_id.not_blank=\u64CD\u4F5C\u65E5\u5FD7\u8D44\u6E90\u64CD\u4F5C\u65E5\u5FD7ID\u4E0D\u80FD\u4E3A\u7A7A
operating_log_resource.operating_log_id.length_range=\u64CD\u4F5C\u65E5\u5FD7\u8D44\u6E90\u64CD\u4F5C\u65E5\u5FD7ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
operating_log_resource.source_id.not_blank=\u64CD\u4F5C\u65E5\u5FD7\u8D44\u6E90\u6765\u6E90ID\u4E0D\u80FD\u4E3A\u7A7A
operating_log_resource.source_id.length_range=\u64CD\u4F5C\u65E5\u5FD7\u8D44\u6E90\u6765\u6E90ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
plugin.id.not_blank=\u63D2\u4EF6\u4E3B\u952E\u4E0D\u80FD\u4E3A\u7A7A
plugin.plugin_id.not_blank=\u63D2\u4EF6ID\u4E0D\u80FD\u4E3A\u7A7A
plugin.plugin_id.length_range=\u63D2\u4EF6ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
plugin.script_id.not_blank=\u63D2\u4EF6\u811A\u672CID\u4E0D\u80FD\u4E3A\u7A7A
plugin.script_id.length_range=\u63D2\u4EF6\u811A\u672CID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
plugin.clazz_name.not_blank=\u63D2\u4EF6\u7C7B\u540D\u4E0D\u80FD\u4E3A\u7A7A
plugin.clazz_name.length_range=\u63D2\u4EF6\u7C7B\u540D\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
plugin.jmeter_clazz.not_blank=\u63D2\u4EF6jmeter\u7C7B\u540D\u4E0D\u80FD\u4E3A\u7A7A
plugin.jmeter_clazz.length_range=\u63D2\u4EF6jmeter\u7C7B\u540D\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
plugin.source_path.not_blank=\u63D2\u4EF6\u6E90\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A
plugin.source_path.length_range=\u63D2\u4EF6\u6E90\u8DEF\u5F84\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
plugin.source_name.not_blank=\u63D2\u4EF6\u6E90\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
plugin.source_name.length_range=\u63D2\u4EF6\u6E90\u540D\u79F0\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
plugin.scenario.not_blank=\u63D2\u4EF6\u573A\u666F\u4E0D\u80FD\u4E3A\u7A7A
plugin.scenario.length_range=\u63D2\u4EF6\u573A\u666F\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
plugin_blob.id.not_blank=\u63D2\u4EF6ID\u4E0D\u80FD\u4E3A\u7A7A
quota.id.not_blank=\u914D\u989DID\u4E0D\u80FD\u4E3A\u7A7A
schedule.id.not_blank=\u5B9A\u65F6\u4EFB\u52A1ID\u4E0D\u80FD\u4E3A\u7A7A
schedule.type.not_blank=\u5B9A\u65F6\u4EFB\u52A1\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
schedule.type.length_range=\u5B9A\u65F6\u4EFB\u52A1\u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
schedule.value.not_blank=\u5B9A\u65F6\u4EFB\u52A1\u503C\u4E0D\u80FD\u4E3A\u7A7A
schedule.value.length_range=\u5B9A\u65F6\u4EFB\u52A1\u503C\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
schedule.job.not_blank=\u5B9A\u65F6\u4EFB\u52A1\u4E0D\u80FD\u4E3A\u7A7A
schedule.job.length_range=\u5B9A\u65F6\u4EFB\u52A1\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
schedule.create_user.not_blank=\u5B9A\u65F6\u4EFB\u52A1\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
schedule.create_user.length_range=\u5B9A\u65F6\u4EFB\u52A1\u521B\u5EFA\u4EBA\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
service_integration.id.not_blank=\u670D\u52A1\u96C6\u6210ID\u4E0D\u80FD\u4E3A\u7A7A
service_integration.platform.not_blank=\u670D\u52A1\u96C6\u6210\u5E73\u53F0\u4E0D\u80FD\u4E3A\u7A7A
service_integration.platform.length_range=\u670D\u52A1\u96C6\u6210\u5E73\u53F0\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
system_parameter.param_key.not_blank=\u7CFB\u7EDF\u53C2\u6570Key\u4E0D\u80FD\u4E3A\u7A7A
system_parameter.type.not_blank=\u7CFB\u7EDF\u53C2\u6570\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
system_parameter.type.length_range=\u7CFB\u7EDF\u53C2\u6570\u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
test_resource.id.not_blank=\u8D44\u6E90\u6C60\u8282\u70B9ID\u4E0D\u80FD\u4E3A\u7A7A
test_resource.test_resource_pool_id.not_blank=\u8D44\u6E90\u6C60ID\u4E0D\u80FD\u4E3A\u7A7A
test_resource.test_resource_pool_id.length_range=\u8D44\u6E90\u6C60ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
test_resource.status.not_blank=\u8D44\u6E90\u6C60\u8282\u70B9\u72B6\u6001\u4E0D\u80FD\u4E3A\u7A7A
test_resource.status.length_range=\u8D44\u6E90\u6C60\u8282\u70B9\u72B6\u6001\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
test_resource_pool.id.not_blank=\u8D44\u6E90\u6C60ID\u4E0D\u80FD\u4E3A\u7A7A
test_resource_pool.name.not_blank=\u8D44\u6E90\u6C60\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
test_resource_pool.name.length_range=\u8D44\u6E90\u6C60\u540D\u79F0\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
test_resource_pool.type.not_blank=\u8D44\u6E90\u6C60\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
test_resource_pool.type.length_range=\u8D44\u6E90\u6C60\u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
test_resource_pool.status.not_blank=\u8D44\u6E90\u6C60\u72B6\u6001\u4E0D\u80FD\u4E3A\u7A7A
test_resource_pool.status.length_range=\u8D44\u6E90\u6C60\u72B6\u6001\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user.id.not_blank=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
user.name.not_blank=\u7528\u6237\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
user.name.length_range=\u7528\u6237\u540D\u79F0\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user.email.not_blank=\u7528\u6237email\u4E0D\u80FD\u4E3A\u7A7A
user.email.length_range=\u7528\u6237email\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user.email.repeat=\u7528\u6237email\u5DF2\u5B58\u5728
user.email.invalid=\u7528\u6237email\u683C\u5F0F\u4E0D\u6B63\u786E
user.status.not_blank=\u7528\u6237\u72B6\u6001\u4E0D\u80FD\u4E3A\u7A7A
user.status.length_range=\u7528\u6237\u72B6\u6001\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user.source.not_blank=\u7528\u6237\u6765\u6E90\u4E0D\u80FD\u4E3A\u7A7A
user.source.length_range=\u7528\u6237\u6765\u6E90\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user.create_user.not_blank=\u7528\u6237\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
user.create_user.length_range=\u7528\u6237\u521B\u5EFA\u4EBA\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_extend.id.not_blank=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
user_key.id.not_blank=\u7528\u6237ApiKey ID\u4E0D\u80FD\u4E3A\u7A7A
user_key.create_user.not_blank=\u7528\u6237ApiKey\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
user_key.create_user.length_range=\u7528\u6237ApiKey\u521B\u5EFA\u4EBA\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_key.access_key.not_blank=\u7528\u6237ApiKey access key\u4E0D\u80FD\u4E3A\u7A7A
user_key.access_key.length_range=\u7528\u6237ApiKey access key\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_key.secret_key.not_blank=\u7528\u6237ApiKey secret key\u4E0D\u80FD\u4E3A\u7A7A
user_key.secret_key.length_range=\u7528\u6237ApiKey secret key\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user.info.not_empty=\u7528\u6237\u4FE1\u606F\u4E0D\u80FD\u4E3A\u7A7A
user.organizationId.not_blank=\u7528\u6237\u7EC4\u7EC7\u4E0D\u80FD\u4E3A\u7A7A
user.projectId.not_blank=\u7528\u6237\u9879\u76EE\u4E0D\u80FD\u4E3A\u7A7A
user_role.id.not_blank=\u7528\u6237\u7EC4ID\u4E0D\u80FD\u4E3A\u7A7A
user_role.name.not_blank=\u7528\u6237\u7EC4\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
user_role.name.length_range=\u7528\u6237\u7EC4\u540D\u79F0\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role.system.not_blank=\u662F\u5426\u662F\u7CFB\u7EDF\u7528\u6237\u7EC4\u4E0D\u80FD\u4E3A\u7A7A
user_role.system.length_range=\u662F\u5426\u662F\u7CFB\u7EDF\u7528\u6237\u7EC4\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role.type.not_blank=\u7528\u6237\u7EC4\u7C7B\u578B\u4E0D\u80FD\u4E3A\u7A7A
user_role.type.length_range=\u7528\u6237\u7EC4\u7C7B\u578B\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role.create_user.not_blank=\u7528\u6237\u7EC4\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
user_role.create_user.length_range=\u7528\u6237\u7EC4\u521B\u5EFA\u4EBA\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role.scope_id.not_blank=\u7528\u6237\u7EC4\u5E94\u7528\u8303\u56F4\u4E0D\u80FD\u4E3A\u7A7A
user_role.scope_id.length_range=\u7528\u6237\u7EC4\u5E94\u7528\u8303\u56F4\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role_permission.id.not_blank=\u7528\u6237\u7EC4\u6743\u9650ID\u4E0D\u80FD\u4E3A\u7A7A
user_role_permission.role_id.not_blank=\u7528\u6237\u7EC4\u6743\u9650\u7528\u6237\u7EC4ID\u4E0D\u80FD\u4E3A\u7A7A
user_role_permission.role_id.length_range=\u7528\u6237\u7EC4\u6743\u9650\u7528\u6237\u7EC4ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role_permission.permission_id.not_blank=\u7528\u6237\u7EC4\u6743\u9650\u6743\u9650ID\u4E0D\u80FD\u4E3A\u7A7A
user_role_permission.permission_id.length_range=\u7528\u6237\u7EC4\u6743\u9650\u6743\u9650ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role_permission.module_id.not_blank=\u7528\u6237\u7EC4\u6743\u9650\u6A21\u5757ID\u4E0D\u80FD\u4E3A\u7A7A
user_role_permission.module_id.length_range=\u7528\u6237\u7EC4\u6743\u9650\u6A21\u5757ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role_relation.id.not_blank=\u7528\u6237\u7EC4\u5173\u7CFBID\u4E0D\u80FD\u4E3A\u7A7A
user_role_relation.user_id.not_blank=\u7528\u6237\u7EC4\u5173\u7CFB\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
user_role_relation.user_id.length_range=\u7528\u6237\u7EC4\u5173\u7CFB\u7528\u6237ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role_relation.role_id.not_blank=\u7528\u6237\u7EC4\u5173\u7CFB\u7528\u6237\u7EC4ID\u4E0D\u80FD\u4E3A\u7A7A
user_role_relation.role_id.length_range=\u7528\u6237\u7EC4\u5173\u7CFB\u7528\u6237\u7EC4ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
user_role_relation.source_id.not_blank=\u7528\u6237\u7EC4\u5173\u7CFB\u6765\u6E90ID\u4E0D\u80FD\u4E3A\u7A7A
user_role_relation.source_id.length_range=\u7528\u6237\u7EC4\u5173\u7CFB\u6765\u6E90ID\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
organization.id.not_blank=\u5DE5\u4F5C\u7A7A\u95F4ID\u4E0D\u80FD\u4E3A\u7A7A
organization.name.not_blank=\u5DE5\u4F5C\u7A7A\u95F4\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A
organization.name.length_range=\u5DE5\u4F5C\u7A7A\u95F4\u540D\u79F0\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
organization.create_user.not_blank=\u5DE5\u4F5C\u7A7A\u95F4\u521B\u5EFA\u4EBA\u4E0D\u80FD\u4E3A\u7A7A
organization.create_user.length_range=\u5DE5\u4F5C\u7A7A\u95F4\u521B\u5EFA\u4EBA\u957F\u5EA6\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4

View File

@ -1,141 +1,147 @@
auth_source.id.not_blank=認證源ID不能為空
auth_source.status.length_range=認證源狀態長度必須在{min}和{max}之間
auth_source.status.not_blank=認證源狀態不能為空
license.id.not_blank=License ID不能為空
message_task.id.not_blank=消息通知任務ID不能為空
message_task.type.not_blank=消息通知任務類型不能為空
message_task.type.length_range=消息通知任務類型長度必須在{min}和{max}之間
message_task.event.not_blank=消息通知任務事件不能為空
message_task.event.length_range=消息通知任務事件長度必須在{min}和{max}之間
message_task.receiver.not_blank=消息通知任務接收者不能為空
message_task.receiver.length_range=消息通知任務接收者長度必須在{min}和{max}之間
message_task.task_type.not_blank=消息通知任務任務類型不能為空
message_task.task_type.length_range=消息通知任務任務類型長度必須在{min}和{max}之間
message_task.test_id.not_blank=消息通知任務測試ID不能為空
message_task.test_id.length_range=消息通知任務測試ID長度必須在{min}和{max}之間
message_task.project_id.not_blank=消息通知任務項目ID不能為空
message_task.project_id.length_range=消息通知任務項目ID長度必須在{min}和{max}之間
message_task_blob.id.not_blank=消息通知任務ID不能為空
notification.id.not_blank=消息通知ID不能為空
notification.type.not_blank=消息通知類型不能為空
notification.type.length_range=消息通知類型長度必須在{min}和{max}之間
notification.receiver.not_blank=消息通知接收者不能為空
notification.receiver.length_range=消息通知接收者長度必須在{min}和{max}之間
notification.title.not_blank=消息通知標題不能為空
notification.title.length_range=消息通知標題長度必須在{min}和{max}之間
notification.status.not_blank=消息通知狀態不能為空
notification.status.length_range=消息通知狀態長度必須在{min}和{max}之間
notification.operator.not_blank=消息通知操作者不能為空
notification.operator.length_range=消息通知操作者長度必須在{min}和{max}之間
notification.operation.not_blank=消息通知操作不能為空
notification.operation.length_range=消息通知操作長度必須在{min}和{max}之間
notification.resource_id.not_blank=消息通知資源ID不能為空
notification.resource_id.length_range=消息通知資源ID長度必須在{min}和{max}之間
notification.resource_type.not_blank=消息通知資源類型不能為空
notification.resource_type.length_range=消息通知資源類型長度必須在{min}和{max}之間
notification.resource_name.not_blank=消息通知資源名稱不能為空
notification.resource_name.length_range=消息通知資源名稱長度必須在{min}和{max}之間
novice_statistics.id.not_blank=新手村ID不能為空
novice_statistics.guide_step.not_blank=新手村步驟不能為空
novice_statistics.guide_step.length_range=新手村步驟長度必須在{min}和{max}之間
operating_log.id.not_blank=操作日誌ID不能為空
operating_log.project_id.not_blank=操作日誌項目ID不能為空
operating_log.project_id.length_range=操作日誌項目ID長度必須在{min}和{max}之間
operating_log_resource.id.not_blank=操作日誌資源ID不能為空
operating_log_resource.operating_log_id.not_blank=操作日誌資源操作日誌ID不能為空
operating_log_resource.operating_log_id.length_range=操作日誌資源操作日誌ID長度必須在{min}和{max}之間
operating_log_resource.source_id.not_blank=操作日誌資源來源ID不能為空
operating_log_resource.source_id.length_range=操作日誌資源來源ID長度必須在{min}和{max}之間
plugin.id.not_blank=插件主鍵不能為空
plugin.plugin_id.not_blank=插件ID不能為空
plugin.plugin_id.length_range=插件ID長度必須在{min}和{max}之間
plugin.script_id.not_blank=插件腳本ID不能為空
plugin.script_id.length_range=插件腳本ID長度必須在{min}和{max}之間
plugin.clazz_name.not_blank=插件類名不能為空
plugin.clazz_name.length_range=插件類名長度必須在{min}和{max}之間
plugin.jmeter_clazz.not_blank=插件jmeter類名不能為空
plugin.jmeter_clazz.length_range=插件jmeter類名長度必須在{min}和{max}之間
plugin.source_path.not_blank=插件源路徑不能為空
plugin.source_path.length_range=插件源路徑長度必須在{min}和{max}之間
plugin.source_name.not_blank=插件源名稱不能為空
plugin.source_name.length_range=插件源名稱長度必須在{min}和{max}之間
plugin.scenario.not_blank=插件場景不能為空
plugin.scenario.length_range=插件場景長度必須在{min}和{max}之間
plugin_blob.id.not_blank=插件ID不能為空
quota.id.not_blank=配額ID不能為空
schedule.id.not_blank=定時任務ID不能為空
schedule.type.not_blank=定時任務類型不能為空
schedule.type.length_range=定時任務類型長度必須在{min}和{max}之間
schedule.value.not_blank=定時任務值不能為空
schedule.value.length_range=定時任務值長度必須在{min}和{max}之間
schedule.job.not_blank=定時任務不能為空
schedule.job.length_range=定時任務長度必須在{min}和{max}之間
schedule.create_user.not_blank=定時任務創建人不能為空
schedule.create_user.length_range=定時任務創建人長度必須在{min}和{max}之間
service_integration.id.not_blank=服務集成ID不能為空
service_integration.platform.not_blank=服務集成平台不能為空
service_integration.platform.length_range=服務集成平台長度必須在{min}和{max}之間
system_parameter.param_key.not_blank=系統參數Key不能為空
system_parameter.type.not_blank=系統參數類型不能為空
system_parameter.type.length_range=系統參數類型長度必須在{min}和{max}之間
test_resource.id.not_blank=資源池節點ID不能為空
test_resource.test_resource_pool_id.not_blank=資源池ID不能為空
test_resource.test_resource_pool_id.length_range=資源池ID長度必須在{min}和{max}之間
test_resource.status.not_blank=資源池節點狀態不能為空
test_resource.status.length_range=資源池節點狀態長度必須在{min}和{max}之間
test_resource_pool.id.not_blank=資源池ID不能為空
test_resource_pool.name.not_blank=資源池名稱不能為空
test_resource_pool.name.length_range=資源池名稱長度必須在{min}和{max}之間
test_resource_pool.type.not_blank=資源池類型不能為空
test_resource_pool.type.length_range=資源池類型長度必須在{min}和{max}之間
test_resource_pool.status.not_blank=資源池狀態不能為空
test_resource_pool.status.length_range=資源池狀態長度必須在{min}和{max}之間
user.id.not_blank=用戶ID不能為空
user.name.not_blank=用戶名稱不能為空
user.name.length_range=用戶名稱長度必須在{min}和{max}之間
user.email.not_blank=用戶email不能為空
user.email.length_range=用戶email長度必須在{min}和{max}之間
user.status.not_blank=用戶狀態不能為空
user.status.length_range=用戶狀態長度必須在{min}和{max}之間
user.source.not_blank=用戶來源不能為空
user.source.length_range=用戶來源長度必須在{min}和{max}之間
user.create_user.not_blank=用戶創建人不能為空
user.create_user.length_range=用戶創建人長度必須在{min}和{max}之間
user_extend.id.not_blank=用戶ID不能為空
user_key.id.not_blank=用戶ApiKey ID不能為空
user_key.create_user.not_blank=用戶ApiKey創建人不能為空
user_key.create_user.length_range=用戶ApiKey創建人長度必須在{min}和{max}之間
user_key.access_key.not_blank=用戶ApiKey access key不能為空
user_key.access_key.length_range=用戶ApiKey access key長度必須在{min}和{max}之間
user_key.secret_key.not_blank=用戶ApiKey secret key不能為空
user_key.secret_key.length_range=用戶ApiKey secret key長度必須在{min}和{max}之間
user_role.id.not_blank=用戶組ID不能為空
user_role.name.not_blank=用戶組名稱不能為空
user_role.name.length_range=用戶組名稱長度必須在{min}和{max}之間
user_role.system.not_blank=是否是系統用戶組不能為空
user_role.system.length_range=是否是系統用戶組長度必須在{min}和{max}之間
user_role.type.not_blank=用戶組類型不能為空
user_role.type.length_range=用戶組類型長度必須在{min}和{max}之間
user_role.create_user.not_blank=用戶組創建人不能為空
user_role.create_user.length_range=用戶組創建人長度必須在{min}和{max}之間
user_role.scope_id.not_blank=用戶組應用範圍不能為空
user_role.scope_id.length_range=用戶組應用範圍長度必須在{min}和{max}之間
user_role_permission.id.not_blank=用戶組權限ID不能為空
user_role_permission.role_id.not_blank=用戶組權限用戶組ID不能為空
user_role_permission.role_id.length_range=用戶組權限用戶組ID長度必須在{min}和{max}之間
user_role_permission.permission_id.not_blank=用戶組權限權限ID不能為空
user_role_permission.permission_id.length_range=用戶組權限權限ID長度必須在{min}和{max}之間
user_role_permission.module_id.not_blank=用戶組權限模塊ID不能為空
user_role_permission.module_id.length_range=用戶組權限模塊ID長度必須在{min}和{max}之間
user_role_relation.id.not_blank=用戶組關係ID不能為空
user_role_relation.user_id.not_blank=用戶組關係用戶ID不能為空
user_role_relation.user_id.length_range=用戶組關係用戶ID長度必須在{min}和{max}之間
user_role_relation.role_id.not_blank=用戶組關係用戶組ID不能為空
user_role_relation.role_id.length_range=用戶組關係用戶組ID長度必須在{min}和{max}之間
user_role_relation.source_id.not_blank=用戶組關係來源ID不能為空
user_role_relation.source_id.length_range=用戶組關係來源ID長度必須在{min}和{max}之間
organization.id.not_blank=工作空間ID不能為空
organization.name.not_blank=工作空間名稱不能為空
organization.name.length_range=工作空間名稱長度必須在{min}和{max}之間
organization.create_user.not_blank=工作空間創建人不能為空
organization.create_user.length_range=工作空間創建人長度必須在{min}和{max}之間
user.not.login=\u672A\u7372\u53D6\u5230\u767B\u9304\u7528\u6236
auth_source.id.not_blank=\u8A8D\u8B49\u6E90ID\u4E0D\u80FD\u70BA\u7A7A
auth_source.status.length_range=\u8A8D\u8B49\u6E90\u72C0\u614B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
auth_source.status.not_blank=\u8A8D\u8B49\u6E90\u72C0\u614B\u4E0D\u80FD\u70BA\u7A7A
license.id.not_blank=License ID\u4E0D\u80FD\u70BA\u7A7A
message_task.id.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9ID\u4E0D\u80FD\u70BA\u7A7A
message_task.type.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
message_task.type.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u985E\u578B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
message_task.event.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u4E8B\u4EF6\u4E0D\u80FD\u70BA\u7A7A
message_task.event.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u4E8B\u4EF6\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
message_task.receiver.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u63A5\u6536\u8005\u4E0D\u80FD\u70BA\u7A7A
message_task.receiver.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u63A5\u6536\u8005\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
message_task.task_type.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u4EFB\u52D9\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
message_task.task_type.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u4EFB\u52D9\u985E\u578B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
message_task.test_id.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u6E2C\u8A66ID\u4E0D\u80FD\u70BA\u7A7A
message_task.test_id.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u6E2C\u8A66ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
message_task.project_id.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u9805\u76EEID\u4E0D\u80FD\u70BA\u7A7A
message_task.project_id.length_range=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9\u9805\u76EEID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
message_task_blob.id.not_blank=\u6D88\u606F\u901A\u77E5\u4EFB\u52D9ID\u4E0D\u80FD\u70BA\u7A7A
notification.id.not_blank=\u6D88\u606F\u901A\u77E5ID\u4E0D\u80FD\u70BA\u7A7A
notification.type.not_blank=\u6D88\u606F\u901A\u77E5\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
notification.type.length_range=\u6D88\u606F\u901A\u77E5\u985E\u578B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
notification.receiver.not_blank=\u6D88\u606F\u901A\u77E5\u63A5\u6536\u8005\u4E0D\u80FD\u70BA\u7A7A
notification.receiver.length_range=\u6D88\u606F\u901A\u77E5\u63A5\u6536\u8005\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
notification.title.not_blank=\u6D88\u606F\u901A\u77E5\u6A19\u984C\u4E0D\u80FD\u70BA\u7A7A
notification.title.length_range=\u6D88\u606F\u901A\u77E5\u6A19\u984C\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
notification.status.not_blank=\u6D88\u606F\u901A\u77E5\u72C0\u614B\u4E0D\u80FD\u70BA\u7A7A
notification.status.length_range=\u6D88\u606F\u901A\u77E5\u72C0\u614B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
notification.operator.not_blank=\u6D88\u606F\u901A\u77E5\u64CD\u4F5C\u8005\u4E0D\u80FD\u70BA\u7A7A
notification.operator.length_range=\u6D88\u606F\u901A\u77E5\u64CD\u4F5C\u8005\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
notification.operation.not_blank=\u6D88\u606F\u901A\u77E5\u64CD\u4F5C\u4E0D\u80FD\u70BA\u7A7A
notification.operation.length_range=\u6D88\u606F\u901A\u77E5\u64CD\u4F5C\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
notification.resource_id.not_blank=\u6D88\u606F\u901A\u77E5\u8CC7\u6E90ID\u4E0D\u80FD\u70BA\u7A7A
notification.resource_id.length_range=\u6D88\u606F\u901A\u77E5\u8CC7\u6E90ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
notification.resource_type.not_blank=\u6D88\u606F\u901A\u77E5\u8CC7\u6E90\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
notification.resource_type.length_range=\u6D88\u606F\u901A\u77E5\u8CC7\u6E90\u985E\u578B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
notification.resource_name.not_blank=\u6D88\u606F\u901A\u77E5\u8CC7\u6E90\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
notification.resource_name.length_range=\u6D88\u606F\u901A\u77E5\u8CC7\u6E90\u540D\u7A31\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
novice_statistics.id.not_blank=\u65B0\u624B\u6751ID\u4E0D\u80FD\u70BA\u7A7A
novice_statistics.guide_step.not_blank=\u65B0\u624B\u6751\u6B65\u9A5F\u4E0D\u80FD\u70BA\u7A7A
novice_statistics.guide_step.length_range=\u65B0\u624B\u6751\u6B65\u9A5F\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
operating_log.id.not_blank=\u64CD\u4F5C\u65E5\u8A8CID\u4E0D\u80FD\u70BA\u7A7A
operating_log.project_id.not_blank=\u64CD\u4F5C\u65E5\u8A8C\u9805\u76EEID\u4E0D\u80FD\u70BA\u7A7A
operating_log.project_id.length_range=\u64CD\u4F5C\u65E5\u8A8C\u9805\u76EEID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
operating_log_resource.id.not_blank=\u64CD\u4F5C\u65E5\u8A8C\u8CC7\u6E90ID\u4E0D\u80FD\u70BA\u7A7A
operating_log_resource.operating_log_id.not_blank=\u64CD\u4F5C\u65E5\u8A8C\u8CC7\u6E90\u64CD\u4F5C\u65E5\u8A8CID\u4E0D\u80FD\u70BA\u7A7A
operating_log_resource.operating_log_id.length_range=\u64CD\u4F5C\u65E5\u8A8C\u8CC7\u6E90\u64CD\u4F5C\u65E5\u8A8CID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
operating_log_resource.source_id.not_blank=\u64CD\u4F5C\u65E5\u8A8C\u8CC7\u6E90\u4F86\u6E90ID\u4E0D\u80FD\u70BA\u7A7A
operating_log_resource.source_id.length_range=\u64CD\u4F5C\u65E5\u8A8C\u8CC7\u6E90\u4F86\u6E90ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
plugin.id.not_blank=\u63D2\u4EF6\u4E3B\u9375\u4E0D\u80FD\u70BA\u7A7A
plugin.plugin_id.not_blank=\u63D2\u4EF6ID\u4E0D\u80FD\u70BA\u7A7A
plugin.plugin_id.length_range=\u63D2\u4EF6ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
plugin.script_id.not_blank=\u63D2\u4EF6\u8173\u672CID\u4E0D\u80FD\u70BA\u7A7A
plugin.script_id.length_range=\u63D2\u4EF6\u8173\u672CID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
plugin.clazz_name.not_blank=\u63D2\u4EF6\u985E\u540D\u4E0D\u80FD\u70BA\u7A7A
plugin.clazz_name.length_range=\u63D2\u4EF6\u985E\u540D\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
plugin.jmeter_clazz.not_blank=\u63D2\u4EF6jmeter\u985E\u540D\u4E0D\u80FD\u70BA\u7A7A
plugin.jmeter_clazz.length_range=\u63D2\u4EF6jmeter\u985E\u540D\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
plugin.source_path.not_blank=\u63D2\u4EF6\u6E90\u8DEF\u5F91\u4E0D\u80FD\u70BA\u7A7A
plugin.source_path.length_range=\u63D2\u4EF6\u6E90\u8DEF\u5F91\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
plugin.source_name.not_blank=\u63D2\u4EF6\u6E90\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
plugin.source_name.length_range=\u63D2\u4EF6\u6E90\u540D\u7A31\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
plugin.scenario.not_blank=\u63D2\u4EF6\u5834\u666F\u4E0D\u80FD\u70BA\u7A7A
plugin.scenario.length_range=\u63D2\u4EF6\u5834\u666F\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
plugin_blob.id.not_blank=\u63D2\u4EF6ID\u4E0D\u80FD\u70BA\u7A7A
quota.id.not_blank=\u914D\u984DID\u4E0D\u80FD\u70BA\u7A7A
schedule.id.not_blank=\u5B9A\u6642\u4EFB\u52D9ID\u4E0D\u80FD\u70BA\u7A7A
schedule.type.not_blank=\u5B9A\u6642\u4EFB\u52D9\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
schedule.type.length_range=\u5B9A\u6642\u4EFB\u52D9\u985E\u578B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
schedule.value.not_blank=\u5B9A\u6642\u4EFB\u52D9\u503C\u4E0D\u80FD\u70BA\u7A7A
schedule.value.length_range=\u5B9A\u6642\u4EFB\u52D9\u503C\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
schedule.job.not_blank=\u5B9A\u6642\u4EFB\u52D9\u4E0D\u80FD\u70BA\u7A7A
schedule.job.length_range=\u5B9A\u6642\u4EFB\u52D9\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
schedule.create_user.not_blank=\u5B9A\u6642\u4EFB\u52D9\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
schedule.create_user.length_range=\u5B9A\u6642\u4EFB\u52D9\u5275\u5EFA\u4EBA\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
service_integration.id.not_blank=\u670D\u52D9\u96C6\u6210ID\u4E0D\u80FD\u70BA\u7A7A
service_integration.platform.not_blank=\u670D\u52D9\u96C6\u6210\u5E73\u53F0\u4E0D\u80FD\u70BA\u7A7A
service_integration.platform.length_range=\u670D\u52D9\u96C6\u6210\u5E73\u53F0\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
system_parameter.param_key.not_blank=\u7CFB\u7D71\u53C3\u6578Key\u4E0D\u80FD\u70BA\u7A7A
system_parameter.type.not_blank=\u7CFB\u7D71\u53C3\u6578\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
system_parameter.type.length_range=\u7CFB\u7D71\u53C3\u6578\u985E\u578B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
test_resource.id.not_blank=\u8CC7\u6E90\u6C60\u7BC0\u9EDEID\u4E0D\u80FD\u70BA\u7A7A
test_resource.test_resource_pool_id.not_blank=\u8CC7\u6E90\u6C60ID\u4E0D\u80FD\u70BA\u7A7A
test_resource.test_resource_pool_id.length_range=\u8CC7\u6E90\u6C60ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
test_resource.status.not_blank=\u8CC7\u6E90\u6C60\u7BC0\u9EDE\u72C0\u614B\u4E0D\u80FD\u70BA\u7A7A
test_resource.status.length_range=\u8CC7\u6E90\u6C60\u7BC0\u9EDE\u72C0\u614B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
test_resource_pool.id.not_blank=\u8CC7\u6E90\u6C60ID\u4E0D\u80FD\u70BA\u7A7A
test_resource_pool.name.not_blank=\u8CC7\u6E90\u6C60\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
test_resource_pool.name.length_range=\u8CC7\u6E90\u6C60\u540D\u7A31\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
test_resource_pool.type.not_blank=\u8CC7\u6E90\u6C60\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
test_resource_pool.type.length_range=\u8CC7\u6E90\u6C60\u985E\u578B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
test_resource_pool.status.not_blank=\u8CC7\u6E90\u6C60\u72C0\u614B\u4E0D\u80FD\u70BA\u7A7A
test_resource_pool.status.length_range=\u8CC7\u6E90\u6C60\u72C0\u614B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user.id.not_blank=\u7528\u6236ID\u4E0D\u80FD\u70BA\u7A7A
user.name.not_blank=\u7528\u6236\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
user.name.length_range=\u7528\u6236\u540D\u7A31\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user.email.not_blank=\u7528\u6236email\u4E0D\u80FD\u70BA\u7A7A
user.email.length_range=\u7528\u6236email\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user.email.repeat=\u7528\u6236email\u5DF2\u5B58\u5728
user.email.invalid=\u7528\u6236email\u683C\u5F0F\u4E0D\u6B63\u78BA
user.status.not_blank=\u7528\u6236\u72C0\u614B\u4E0D\u80FD\u70BA\u7A7A
user.status.length_range=\u7528\u6236\u72C0\u614B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user.source.not_blank=\u7528\u6236\u4F86\u6E90\u4E0D\u80FD\u70BA\u7A7A
user.source.length_range=\u7528\u6236\u4F86\u6E90\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user.create_user.not_blank=\u7528\u6236\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
user.create_user.length_range=\u7528\u6236\u5275\u5EFA\u4EBA\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_extend.id.not_blank=\u7528\u6236ID\u4E0D\u80FD\u70BA\u7A7A
user_key.id.not_blank=\u7528\u6236ApiKey ID\u4E0D\u80FD\u70BA\u7A7A
user_key.create_user.not_blank=\u7528\u6236ApiKey\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
user_key.create_user.length_range=\u7528\u6236ApiKey\u5275\u5EFA\u4EBA\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_key.access_key.not_blank=\u7528\u6236ApiKey access key\u4E0D\u80FD\u70BA\u7A7A
user_key.access_key.length_range=\u7528\u6236ApiKey access key\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_key.secret_key.not_blank=\u7528\u6236ApiKey secret key\u4E0D\u80FD\u70BA\u7A7A
user_key.secret_key.length_range=\u7528\u6236ApiKey secret key\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user.info.not_empty=\u7528\u6236\u4FE1\u606F\u4E0D\u80FD\u70BA\u7A7A
user.organizationId.not_blank=\u7528\u6236\u7D44\u7E54\u4E0D\u80FD\u70BA\u7A7A
user.projectId.not_blank=\u7528\u6236\u9805\u76EE\u4E0D\u80FD\u70BA\u7A7A
user_role.id.not_blank=\u7528\u6236\u7D44ID\u4E0D\u80FD\u70BA\u7A7A
user_role.name.not_blank=\u7528\u6236\u7D44\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
user_role.name.length_range=\u7528\u6236\u7D44\u540D\u7A31\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role.system.not_blank=\u662F\u5426\u662F\u7CFB\u7D71\u7528\u6236\u7D44\u4E0D\u80FD\u70BA\u7A7A
user_role.system.length_range=\u662F\u5426\u662F\u7CFB\u7D71\u7528\u6236\u7D44\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role.type.not_blank=\u7528\u6236\u7D44\u985E\u578B\u4E0D\u80FD\u70BA\u7A7A
user_role.type.length_range=\u7528\u6236\u7D44\u985E\u578B\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role.create_user.not_blank=\u7528\u6236\u7D44\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
user_role.create_user.length_range=\u7528\u6236\u7D44\u5275\u5EFA\u4EBA\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role.scope_id.not_blank=\u7528\u6236\u7D44\u61C9\u7528\u7BC4\u570D\u4E0D\u80FD\u70BA\u7A7A
user_role.scope_id.length_range=\u7528\u6236\u7D44\u61C9\u7528\u7BC4\u570D\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role_permission.id.not_blank=\u7528\u6236\u7D44\u6B0A\u9650ID\u4E0D\u80FD\u70BA\u7A7A
user_role_permission.role_id.not_blank=\u7528\u6236\u7D44\u6B0A\u9650\u7528\u6236\u7D44ID\u4E0D\u80FD\u70BA\u7A7A
user_role_permission.role_id.length_range=\u7528\u6236\u7D44\u6B0A\u9650\u7528\u6236\u7D44ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role_permission.permission_id.not_blank=\u7528\u6236\u7D44\u6B0A\u9650\u6B0A\u9650ID\u4E0D\u80FD\u70BA\u7A7A
user_role_permission.permission_id.length_range=\u7528\u6236\u7D44\u6B0A\u9650\u6B0A\u9650ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role_permission.module_id.not_blank=\u7528\u6236\u7D44\u6B0A\u9650\u6A21\u584AID\u4E0D\u80FD\u70BA\u7A7A
user_role_permission.module_id.length_range=\u7528\u6236\u7D44\u6B0A\u9650\u6A21\u584AID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role_relation.id.not_blank=\u7528\u6236\u7D44\u95DC\u4FC2ID\u4E0D\u80FD\u70BA\u7A7A
user_role_relation.user_id.not_blank=\u7528\u6236\u7D44\u95DC\u4FC2\u7528\u6236ID\u4E0D\u80FD\u70BA\u7A7A
user_role_relation.user_id.length_range=\u7528\u6236\u7D44\u95DC\u4FC2\u7528\u6236ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role_relation.role_id.not_blank=\u7528\u6236\u7D44\u95DC\u4FC2\u7528\u6236\u7D44ID\u4E0D\u80FD\u70BA\u7A7A
user_role_relation.role_id.length_range=\u7528\u6236\u7D44\u95DC\u4FC2\u7528\u6236\u7D44ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
user_role_relation.source_id.not_blank=\u7528\u6236\u7D44\u95DC\u4FC2\u4F86\u6E90ID\u4E0D\u80FD\u70BA\u7A7A
user_role_relation.source_id.length_range=\u7528\u6236\u7D44\u95DC\u4FC2\u4F86\u6E90ID\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
organization.id.not_blank=\u5DE5\u4F5C\u7A7A\u9593ID\u4E0D\u80FD\u70BA\u7A7A
organization.name.not_blank=\u5DE5\u4F5C\u7A7A\u9593\u540D\u7A31\u4E0D\u80FD\u70BA\u7A7A
organization.name.length_range=\u5DE5\u4F5C\u7A7A\u9593\u540D\u7A31\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593
organization.create_user.not_blank=\u5DE5\u4F5C\u7A7A\u9593\u5275\u5EFA\u4EBA\u4E0D\u80FD\u70BA\u7A7A
organization.create_user.length_range=\u5DE5\u4F5C\u7A7A\u9593\u5275\u5EFA\u4EBA\u9577\u5EA6\u5FC5\u9808\u5728{min}\u548C{max}\u4E4B\u9593

View File

@ -39,7 +39,7 @@ public class BugService {
example.createCriteria().andProjectIdEqualTo(bug.getProjectId());
List<Bug> bugs = bugMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(bugs)) {
MSException.throwException(BugMgtResultCode.BUG_EXIST_EXCEPTION);
throw new MSException(BugMgtResultCode.BUG_EXIST_EXCEPTION);
}
bug.setCreateTime(System.currentTimeMillis());
bug.setUpdateTime(System.currentTimeMillis());

View File

@ -1,9 +1,6 @@
package io.metersphere.project.controller;
import com.jayway.jsonpath.JsonPath;
import io.metersphere.project.domain.Project;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.util.JSON;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
@ -16,7 +13,6 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -47,54 +43,55 @@ public class ProjectControllerTests {
}
// 添加项目
@Test
@Order(1)
public void testAddProject() throws Exception {
Project project = new Project();
project.setName("test");
project.setCreateUser("admin");
project.setOrganizationId("default");
var result = mockMvc.perform(MockMvcRequestBuilders.post("/project/add")
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(project))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
projectId = JsonPath.read(result.getResponse().getContentAsString(), "$.data.id");
}
@Test
@Order(2)
public void testEditProject() throws Exception {
Project project = new Project();
project.setId(projectId);
project.setName("test2");
project.setCreateUser("admin");
project.setOrganizationId("default");
mockMvc.perform(MockMvcRequestBuilders.post("/project/edit")
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(project))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andDo(print());
}
@Test
@Order(3)
public void testSelectAll() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/project/list-all")
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
// .andExpect(jsonPath("$.person.name").value("Jason"))
.andDo(print());
}
// @Test
// @Order(1)
// public void testAddProject() throws Exception {
// Project project = new Project();
// project.setName("test");
// project.setCreateUser("admin");
// project.setOrganizationId("default");
//
//
// var result = mockMvc.perform(MockMvcRequestBuilders.post("/project/add")
// .header(SessionConstants.HEADER_TOKEN, sessionId)
// .header(SessionConstants.CSRF_TOKEN, csrfToken)
// .content(JSON.toJSONString(project))
// .contentType(MediaType.APPLICATION_JSON))
// .andExpect(status().isOk())
// .andExpect(content().contentType(MediaType.APPLICATION_JSON))
// .andReturn();
// projectId = JsonPath.read(result.getResponse().getContentAsString(), "$.data.id");
// }
//
// @Test
// @Order(2)
// public void testEditProject() throws Exception {
// Project project = new Project();
// project.setId(projectId);
// project.setName("test2");
// project.setCreateUser("admin");
// project.setOrganizationId("default");
//
// mockMvc.perform(MockMvcRequestBuilders.post("/project/edit")
// .header(SessionConstants.HEADER_TOKEN, sessionId)
// .header(SessionConstants.CSRF_TOKEN, csrfToken)
// .content(JSON.toJSONString(project))
// .contentType(MediaType.APPLICATION_JSON))
// .andExpect(status().isOk())
// .andExpect(content().contentType(MediaType.APPLICATION_JSON))
// .andDo(print());
// }
//
// @Test
// @Order(3)
// public void testSelectAll() throws Exception {
// mockMvc.perform(MockMvcRequestBuilders.get("/project/list-all")
// .header(SessionConstants.HEADER_TOKEN, sessionId)
// .header(SessionConstants.CSRF_TOKEN, csrfToken))
// .andExpect(status().isOk())
// .andExpect(content().contentType(MediaType.APPLICATION_JSON))
// // .andExpect(jsonPath("$.person.name").value("Jason"))
// .andDo(print());
// }
}

View File

@ -3,57 +3,31 @@ package io.metersphere.system.controller;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.UserDTO;
import io.metersphere.system.domain.User;
import io.metersphere.sdk.util.SessionUtils;
import io.metersphere.system.dto.UserMaintainRequest;
import io.metersphere.system.service.UserService;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import jakarta.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@GetMapping("/get/{userId}")
@GetMapping("/get/{email}")
@RequiresPermissions(PermissionConstants.SYSTEM_USER_READ)
public User getUser(@PathVariable String userId) {
return userService.getById(userId);
public UserDTO getUser(@PathVariable String email) {
return userService.getByEmail(email);
}
@PostMapping("/add")
@RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_ADD)
public UserDTO addUser(@Validated({Created.class}) @RequestBody UserDTO user) {
return userService.add(user);
public UserMaintainRequest addUser(@Validated({Created.class}) @RequestBody UserMaintainRequest userCreateDTO) {
userCreateDTO.setCreateUserToList(SessionUtils.getSessionId());
return userService.add(userCreateDTO);
}
@PostMapping("/update")
@RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_UPDATE)
public UserDTO updateUser(@Validated({Updated.class}) @RequestBody UserDTO user) {
return userService.update(user);
}
@GetMapping("/delete/{userId}")
@RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_DELETE)
public UserDTO deleteUser(@PathVariable String userId) {
return userService.delete(userId);
}
@PostMapping("/batch-add3")
@RequiresPermissions(PermissionConstants.SYSTEM_USER_READ_ADD)
public boolean batchSaveUser3(@Validated({Created.class}) @RequestBody List<User> user) {
return userService.batchSave3(user);
}
@GetMapping("/count")
@RequiresPermissions(PermissionConstants.SYSTEM_USER_READ)
public long batchSaveUser() {
return userService.count();
}
}

View File

@ -0,0 +1,39 @@
package io.metersphere.system.dto;
import io.metersphere.system.domain.User;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.util.List;
@Data
public class UserMaintainRequest {
@Schema(title = "用户信息集合", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(groups = {Created.class, Updated.class}, message = "{user.info.not_empty}")
List<@Valid User> userInfoList;
@Schema(title = "组织Id", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(groups = {Created.class, Updated.class}, message = "{user.organizationId.not_blank}")
String organizationId;
@Schema(title = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(groups = {Created.class, Updated.class}, message = "{user.projectId.not_blank}")
String projectId;
public void setCreateUserToList(String userSessionId) {
userInfoList.forEach(user -> {
user.setCreateUser(userSessionId);
user.setUpdateUser(userSessionId);
});
}
public void setUpdateUserToList(String userSessionId) {
userInfoList.forEach(user -> {
user.setUpdateUser(userSessionId);
});
}
}

View File

@ -1,21 +1,23 @@
package io.metersphere.system.service;
import io.metersphere.sdk.dto.UserDTO;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.mapper.BaseUserMapper;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.CodingUtil;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.User;
import io.metersphere.system.domain.UserExample;
import io.metersphere.system.domain.UserExtend;
import io.metersphere.system.mapper.UserExtendMapper;
import io.metersphere.system.dto.UserMaintainRequest;
import io.metersphere.system.mapper.UserMapper;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
@ -24,78 +26,50 @@ public class UserService {
private BaseUserMapper baseUserMapper;
@Resource
private UserMapper userMapper;
@Resource
private UserExtendMapper userExtendMapper;
@Resource
private SqlSessionFactory sqlSessionFactory;
public UserDTO add(UserDTO entity) {
// todo 后台直接获取在线用户
entity.setCreateUser("admin");
entity.setCreateTime(System.currentTimeMillis());
entity.setUpdateTime(System.currentTimeMillis());
userMapper.insert(entity);
UserExtend userExtend = new UserExtend();
BeanUtils.copyBean(userExtend, entity);
userExtendMapper.insert(userExtend);
return entity;
}
public UserDTO update(UserDTO entity) {
entity.setCreateUser(null);
entity.setCreateTime(null);
entity.setUpdateTime(System.currentTimeMillis());
userMapper.updateByPrimaryKeySelective(entity);
// 扩展属性按需更新
if (entity.getPlatformInfo() != null || StringUtils.isNotEmpty(entity.getSeleniumServer())) {
UserExtend userExtend = new UserExtend();
BeanUtils.copyBean(userExtend, entity);
userExtendMapper.updateByPrimaryKeySelective(userExtend);
}
return baseUserMapper.selectById(entity.getId());
}
public UserDTO getById(String id) {
return baseUserMapper.selectById(id);
}
public boolean batchSave3(List<User> users) {
long start = System.currentTimeMillis();
int batchSize = 100;
int size = users.size();
int pageSize = size / batchSize;
users.forEach(user -> {
user.setCreateUser("admin");
user.setCreateTime(System.currentTimeMillis());
user.setUpdateTime(System.currentTimeMillis());
});
for (int i = 0; i < pageSize; i++) {
int startIndex = i * batchSize;
List<User> sub = users.subList(startIndex, startIndex + batchSize);
baseUserMapper.batchSave(sub);
private void validateUserInfo(List<User> userList) {
//判断参数内是否含有重复邮箱
List<String> emailList = new ArrayList<>();
List<String> repeatEmailList = new ArrayList<>();
var userInDbMap = baseUserMapper.selectUserIdByEmailList(
userList.stream().map(User::getEmail).collect(Collectors.toList()))
.stream().collect(Collectors.toMap(User::getEmail, User::getId));
for (User user : userList) {
if (emailList.contains(user.getEmail())) {
repeatEmailList.add(user.getEmail());
} else {
//判断邮箱是否已存在数据库中
if (userInDbMap.containsKey(user.getEmail())) {
repeatEmailList.add(user.getEmail());
} else {
emailList.add(user.getEmail());
}
}
}
if (size % batchSize != 0) {
int startIndex = pageSize * batchSize;
List<User> sub = users.subList(startIndex, size);
baseUserMapper.batchSave(sub);
if (CollectionUtils.isNotEmpty(repeatEmailList)) {
throw new MSException(Translator.get("user.email.repeat", repeatEmailList.toString()));
}
System.out.println("batch save cost: " + (System.currentTimeMillis() - start) + "ms");
return true;
}
public long count() {
return userMapper.countByExample(new UserExample());
public UserMaintainRequest add(UserMaintainRequest userCreateDTO) {
this.validateUserInfo(userCreateDTO.getUserInfoList());
long createTime = System.currentTimeMillis();
for (User user : userCreateDTO.getUserInfoList()) {
user.setId(UUID.randomUUID().toString());
if (StringUtils.isEmpty(user.getPassword())) {
user.setPassword(CodingUtil.md5(user.getEmail()));
}
user.setCreateTime(createTime);
user.setUpdateTime(createTime);
userMapper.insertSelective(user);
}
return userCreateDTO;
}
public UserDTO delete(String userId) {
UserDTO userDTO = baseUserMapper.selectById(userId);
userMapper.deleteByPrimaryKey(userId);
userExtendMapper.deleteByPrimaryKey(userId);
return userDTO;
public UserDTO getByEmail(String email) {
return baseUserMapper.selectByEmail(email);
}
}

View File

@ -2,21 +2,32 @@ package io.metersphere.system.controller;
import com.jayway.jsonpath.JsonPath;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.controller.handler.ResultHolder;
import io.metersphere.sdk.dto.UserDTO;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.User;
import io.metersphere.system.dto.UserMaintainRequest;
import io.metersphere.system.utils.UserTestUtils;
import io.metersphere.utils.JsonUtils;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@ -28,124 +39,223 @@ public class UserControllerTests {
private static String sessionId;
private static String csrfToken;
private static final List<User> USER_LIST = new ArrayList<>();
//成功入库的用户保存内存中其他用例会使用到
private void addUser2List(MvcResult mvcResult) throws Exception {
String returnData = mvcResult.getResponse().getContentAsString();
ResultHolder resultHolder = JsonUtils.parseObject(returnData, ResultHolder.class);
//返回请求正常
Assertions.assertNotNull(resultHolder);
UserMaintainRequest userMaintainRequest = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), UserMaintainRequest.class);
//返回值不为空
Assertions.assertNotNull(userMaintainRequest);
USER_LIST.addAll(userMaintainRequest.getUserInfoList());
}
private void checkUserList() throws Exception {
if (CollectionUtils.isEmpty(USER_LIST)) {
//测试数据初始化入库
this.testAddSuccess();
}
}
@BeforeEach
public void login() throws Exception {
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/login")
.content("{\"username\":\"admin\",\"password\":\"metersphere\"}")
if (StringUtils.isAnyBlank(sessionId, csrfToken)) {
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/login")
.content("{\"username\":\"admin\",\"password\":\"metersphere\"}")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
sessionId = JsonPath.read(mvcResult.getResponse().getContentAsString(), "$.data.sessionId");
csrfToken = JsonPath.read(mvcResult.getResponse().getContentAsString(), "$.data.csrfToken");
}
}
private void requestPost(String url, Object param, ResultMatcher resultMatcher) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post(url)
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(param))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
sessionId = JsonPath.read(mvcResult.getResponse().getContentAsString(), "$.data.sessionId");
csrfToken = JsonPath.read(mvcResult.getResponse().getContentAsString(), "$.data.csrfToken");
.andExpect(resultMatcher).andDo(print())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
private MvcResult responsePost(String url, Object param) throws Exception {
return mockMvc.perform(MockMvcRequestBuilders.post(url)
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(param))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(print())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
}
private MvcResult responseGet(String url) throws Exception {
return mockMvc.perform(MockMvcRequestBuilders.get(url)
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk()).andDo(print())
.andExpect(content().contentType(MediaType.APPLICATION_JSON)).andReturn();
}
@Test
@Order(1)
public void testAddUser() throws Exception {
UserDTO user = new UserDTO();
user.setId("user");
user.setName("user");
user.setSource("LOCAL");
user.setEmail("bin@fit2cloud.com");
public void testAddSuccess() throws Exception {
String url = "/user/add";
//模拟前台批量添加用户
UserMaintainRequest userMaintainRequest = UserTestUtils.getSimpleUserCreateDTO();
MvcResult mvcResult = this.responsePost(url, userMaintainRequest);
this.addUser2List(mvcResult);
user.setSeleniumServer("http://localhost:4444");
//含有重复的用户名称
userMaintainRequest = UserTestUtils.getSimpleUserCreateDTO();
userMaintainRequest.setUserInfoList(
new ArrayList<>() {{
add(new User() {{
setName("tianyang.repeat");
setEmail("tianyang.repeat.name.1@126.com");
setSource("LOCAL");
}});
mockMvc.perform(MockMvcRequestBuilders.post("/user/add")
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(user))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
add(new User() {{
setName("tianyang.repeat");
setEmail("tianyang.repeat.name.2@126.com");
setSource("LOCAL");
}});
}}
);
mvcResult = this.responsePost(url, userMaintainRequest);
this.addUser2List(mvcResult);
}
@Test
@Order(2)
public void testAddUserFailed() throws Exception {
UserDTO user = new UserDTO();
user.setId("user2");
public void testAddError() throws Exception {
String url = "/user/add";
UserMaintainRequest userMaintainRequest;
boolean projectIsEmpty = true;
boolean organizationIsEmpty = true;
boolean userIsEmpty = true;
/*
* 校验参数不合法的反例
* 每一次校验使用getErrorUserCreateDTO方法重新获取参数避免上一步的参数干扰
*/
ResultMatcher resultMatcher = status().isBadRequest();
//所有参数都为空
userMaintainRequest = UserTestUtils.getErrorUserCreateDTO(organizationIsEmpty, projectIsEmpty, userIsEmpty);
this.requestPost(url, userMaintainRequest, resultMatcher);
//组织ID为空
userMaintainRequest = UserTestUtils.getErrorUserCreateDTO(organizationIsEmpty, !projectIsEmpty, !userIsEmpty);
this.requestPost(url, userMaintainRequest, resultMatcher);
//项目ID为空
userMaintainRequest = UserTestUtils.getErrorUserCreateDTO(!organizationIsEmpty, projectIsEmpty, !userIsEmpty);
this.requestPost(url, userMaintainRequest, resultMatcher);
//没有用户
userMaintainRequest = UserTestUtils.getErrorUserCreateDTO(!organizationIsEmpty, !projectIsEmpty, userIsEmpty);
this.requestPost(url, userMaintainRequest, resultMatcher);
//含有用户名称为空的数据
userMaintainRequest = UserTestUtils.getSimpleUserCreateDTO();
userMaintainRequest.getUserInfoList().add(new User() {{
setEmail("tianyang.name.empty@126.com");
setSource("LOCAL");
}});
this.requestPost(url, userMaintainRequest, resultMatcher);
//含有用户邮箱为空的数据
userMaintainRequest = UserTestUtils.getSimpleUserCreateDTO();
userMaintainRequest.getUserInfoList().add(new User() {{
setName("tianyang.email.empty");
setSource("LOCAL");
}});
this.requestPost(url, userMaintainRequest, resultMatcher);
//用户邮箱不符合标准
userMaintainRequest = UserTestUtils.getSimpleUserCreateDTO();
userMaintainRequest.getUserInfoList().add(new User() {{
setName("用户邮箱放飞自我");
setEmail("用户邮箱放飞自我");
setSource("LOCAL");
}});
this.requestPost(url, userMaintainRequest, resultMatcher);
//用户来源为空
userMaintainRequest = UserTestUtils.getSimpleUserCreateDTO();
userMaintainRequest.getUserInfoList().add(new User() {{
setName("tianyang.source.empty");
setEmail("tianyang.source.empty@126.com");
}});
this.requestPost(url, userMaintainRequest, resultMatcher);
user.setSeleniumServer("http://localhost:4444");
mockMvc.perform(MockMvcRequestBuilders.post("/user/add")
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(user))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
/*
* 校验业务判断出错的反例 500 error)
* 需要保证数据库有正常数据
*/
resultMatcher = status().is5xxServerError();
this.checkUserList();
//含有重复的用户邮箱
userMaintainRequest = UserTestUtils.getErrorUserCreateDTO(!organizationIsEmpty, !projectIsEmpty, !userIsEmpty);
String firstUserEmail = userMaintainRequest.getUserInfoList().get(0).getEmail();
userMaintainRequest.getUserInfoList().add(new User() {{
setName("tianyang.no.error4");
setEmail(firstUserEmail);
setSource("LOCAL");
}});
this.requestPost(url, userMaintainRequest, resultMatcher);
//测试请求参数中含有数据库中已存在的邮箱情况
userMaintainRequest = UserTestUtils.getErrorUserCreateDTO(!organizationIsEmpty, !projectIsEmpty, userIsEmpty);
userMaintainRequest.setUserInfoList(
new ArrayList<>() {{
add(new User() {{
setName("tianyang.repeat.email.db");
setEmail(UserTestUtils.USER_DEFAULT_EMAIL);
setSource("LOCAL");
}});
}}
);
this.requestPost(url, userMaintainRequest, resultMatcher);
}
@Test
@Order(3)
public void testGetUser() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/user/get/user")
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.data.id").value("user"));
}
public void testGetByEmailSuccess() throws Exception {
this.checkUserList();
String url = "/user/get/" + UserTestUtils.USER_DEFAULT_EMAIL;
MvcResult mvcResult = this.responseGet(url);
String returnData = mvcResult.getResponse().getContentAsString();
ResultHolder resultHolder = JsonUtils.parseObject(returnData, ResultHolder.class);
//返回请求正常
Assertions.assertNotNull(resultHolder);
@Test
@Order(4)
public void testUpdateUser() throws Exception {
UserDTO user = new UserDTO();
user.setId("user");
user.setName("useristrator");
UserDTO userDTO = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), UserDTO.class);
//返回值不为空
Assertions.assertNotNull(userDTO);
mockMvc.perform(MockMvcRequestBuilders.post("/user/update")
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(user))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
//返回邮箱等于参数邮箱且用户名合法
Assertions.assertEquals(userDTO.getEmail(), UserTestUtils.USER_DEFAULT_EMAIL);
Assertions.assertNotNull(userDTO.getName());
}
@Test
@Order(5)
public void testDeleteUser() throws Exception {
@Order(3)
public void testGetByEmailError() throws Exception {
//测试使用任意参数不能获取到任何用户信息
this.checkUserList();
String url = "/user/get/" + UUID.randomUUID();
MvcResult mvcResult = this.responseGet(url);
mockMvc.perform(MockMvcRequestBuilders.get("/user/delete/user")
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.data.id").value("user"));
}
@Test
@Order(7)
public void testBatchAddUser3() throws Exception {
var users = new ArrayList<User>();
int size = 123;
for (int i = 0; i < size; i++) {
User user = new User();
user.setId("batch3_" + i);
user.setName("batch3_" + i);
user.setSource("LOCAL");
user.setEmail("bin@fit2cloud.com");
users.add(user);
}
mockMvc.perform(MockMvcRequestBuilders.post("/user/batch-add3")
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(users))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
// mockMvc.perform(MockMvcRequestBuilders.get("/user/count")
// .header(SessionConstants.HEADER_TOKEN, sessionId)
// .header(SessionConstants.CSRF_TOKEN, csrfToken)
// .contentType(MediaType.APPLICATION_JSON))
// .andExpect(status().isOk())
// .andExpect(content().contentType(MediaType.APPLICATION_JSON))
// .andExpect(jsonPath("$.data").value(size));
String returnData = mvcResult.getResponse().getContentAsString();
ResultHolder resultHolder = JsonUtils.parseObject(returnData, ResultHolder.class);
//返回请求正常
Assertions.assertNotNull(resultHolder);
//返回值为空
Assertions.assertNull(resultHolder.getData());
}
}

View File

@ -0,0 +1,58 @@
package io.metersphere.system.utils;
import io.metersphere.system.domain.User;
import io.metersphere.system.dto.UserMaintainRequest;
import java.util.ArrayList;
public class UserTestUtils {
public static final String USER_DEFAULT_NAME = "tianyang.no.1";
public static final String USER_DEFAULT_EMAIL = "tianyang.no.1@126.com";
public static final String ORGANIZATION_ID = "ms-organization";
public static final String PROJECT_ID = "ms-project";
public static UserMaintainRequest getSimpleUserCreateDTO() {
UserMaintainRequest userMaintainRequest = new UserMaintainRequest();
userMaintainRequest.setOrganizationId(ORGANIZATION_ID);
userMaintainRequest.setProjectId(PROJECT_ID);
userMaintainRequest.setUserInfoList(new ArrayList<>() {{
add(new User() {{
setName(USER_DEFAULT_NAME);
setEmail(USER_DEFAULT_EMAIL);
setSource("LOCAL");
}});
add(new User() {{
setName("tianyang.no.2");
setEmail("tianyang.no.2@126.com");
setSource("LOCAL");
}});
}});
return userMaintainRequest;
}
public static UserMaintainRequest getErrorUserCreateDTO(boolean organizationIsEmpty, boolean projectIsEmpty, boolean userIsEmpty) {
UserMaintainRequest userMaintainRequest = new UserMaintainRequest();
if (!organizationIsEmpty) {
userMaintainRequest.setOrganizationId(ORGANIZATION_ID);
}
if (!projectIsEmpty) {
userMaintainRequest.setProjectId(PROJECT_ID);
}
if (!userIsEmpty) {
userMaintainRequest.setUserInfoList(new ArrayList<>() {{
add(new User() {{
setName("tianyang.error.1");
setEmail("tianyang.error.1@126.com");
setSource("LOCAL");
}});
add(new User() {{
setName("tianyang.error.2");
setEmail("tianyang.error.2@126.com");
setSource("LOCAL");
}});
}});
}
return userMaintainRequest;
}
}

View File

@ -26,7 +26,7 @@ public class TestPlanController {
@PostMapping("/delete/batch")
public void deleteBatch(@RequestBody List<String> idList) {
if (CollectionUtils.isEmpty(idList)) {
MSException.throwException("The ids cannot be empty!");
throw new MSException("The ids cannot be empty!");
}
testPlanService.batchDelete(idList);
}

View File

@ -52,10 +52,10 @@ public class TestPlanService {
public TestPlanDTO add(@NotNull TestPlanDTO testPlanCreateRequest) {
User user = SessionUtils.getUser();
if (user == null) {
MSException.throwException("Cannot find user!");
throw new MSException("Cannot find user!");
}
if (StringUtils.equals(testPlanCreateRequest.getParentId(), testPlanCreateRequest.getId())) {
MSException.throwException("The parent test plan cannot be the same as the current test plan!");
throw new MSException("The parent test plan cannot be the same as the current test plan!");
}
if (StringUtils.isBlank(testPlanCreateRequest.getId())) {