From dc6f7cd691d0510a4b149a8ddfcbb501b0e1abd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90li?= <15040126243@163.com> Date: Mon, 21 Feb 2022 13:34:58 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E5=AE=8C=E6=88=90=20=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96=20=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- config/dev/application.yml | 4 + .../ruoyi/system/api/RemoteUserService.java | 7 - .../java/com/ruoyi/auth/form/LoginBody.java | 8 +- .../ruoyi/auth/service/SysLoginService.java | 33 +- .../core/exception/CaptchaException.java | 32 +- .../core/exception/ServiceException.java | 3 +- .../core/exception/base/BaseException.java | 14 + .../core/exception/user/UserException.java | 4 +- .../ruoyi/common/core/utils/MessageUtils.java | 28 ++ .../ruoyi/common/web/config/I18nConfig.java | 21 + .../common/web/core/I18nLocaleResolver.java | 31 ++ .../main/resources/META-INF/spring.factories | 3 +- .../main/resources/i18n/messages.properties | 39 ++ .../resources/i18n/messages_en_US.properties | 39 ++ .../resources/i18n/messages_zh_CN.properties | 39 ++ .../service/impl/ValidateCodeServiceImpl.java | 7 +- .../system/dubbo/RemoteUserServiceImpl.java | 13 +- ruoyi-ui/src/utils/request.js | 324 +++++++------- ruoyi-ui/src/views/register.vue | 419 +++++++++--------- 20 files changed, 640 insertions(+), 430 deletions(-) create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/I18nConfig.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/I18nLocaleResolver.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages.properties create mode 100644 ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages_en_US.properties create mode 100644 ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages_zh_CN.properties diff --git a/README.md b/README.md index 7b47b2eb..9ea44b54 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ | 工具类框架 | Hutool、Lombok | [Hutool文档](https://www.hutool.cn/docs/) | 减少代码冗余 增加安全性 | | 代码生成器 | 适配MP、Knife4j规范化代码 | [Hutool文档](https://www.hutool.cn/docs/) | 一键生成前后端代码 | | 部署方式 | Docker | [Docker文档](https://docs.docker.com/) | 容器编排 一键部署业务集群 | -| 国际化(未完成) | SpringMessage | [SpringMVC文档](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc) | Spring标准国际化方案 | +| 国际化 | SpringMessage | [SpringMVC文档](https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc) | Spring标准国际化方案 | ## 软件架构图 diff --git a/config/dev/application.yml b/config/dev/application.yml index d33d9fe9..68a49b04 100644 --- a/config/dev/application.yml +++ b/config/dev/application.yml @@ -55,6 +55,10 @@ spring: pathmatch: # 适配 boot 2.6 路由与 springfox 兼容 matching-strategy: ANT_PATH_MATCHER + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages servlet: multipart: # 整个请求大小限制 diff --git a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java index 6771b11c..42febe1f 100644 --- a/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java +++ b/ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java @@ -26,11 +26,4 @@ public interface RemoteUserService { */ Boolean registerUserInfo(SysUser sysUser); - /** - * 检查用户名是否唯一 - * - * @param username 用户名 - * @return 结果 - */ - String checkUserNameUnique(String username); } diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/form/LoginBody.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/form/LoginBody.java index 852aef62..c8770d45 100644 --- a/ruoyi-auth/src/main/java/com/ruoyi/auth/form/LoginBody.java +++ b/ruoyi-auth/src/main/java/com/ruoyi/auth/form/LoginBody.java @@ -22,16 +22,16 @@ public class LoginBody { /** * 用户名 */ - @NotBlank(message = "用户名不能为空") - @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "账户长度必须在2到20个字符之间") + @NotBlank(message = "{user.username.not.blank}") + @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}") @ApiModelProperty(value = "用户名") private String username; /** * 用户密码 */ - @NotBlank(message = "密码不能为空") - @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "密码长度必须在5到20个字符之间") + @NotBlank(message = "{user.password.not.blank}") + @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}") @ApiModelProperty(value = "用户密码") private String password; diff --git a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java b/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java index 043d9c49..6a00bf95 100644 --- a/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java +++ b/ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java @@ -5,9 +5,10 @@ import cn.hutool.core.util.ObjectUtil; import com.ruoyi.auth.form.RegisterBody; import com.ruoyi.common.core.constant.CacheConstants; import com.ruoyi.common.core.constant.Constants; -import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.enums.UserType; import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.exception.user.UserException; +import com.ruoyi.common.core.utils.MessageUtils; import com.ruoyi.common.core.utils.ServletUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.redis.utils.RedisUtils; @@ -44,8 +45,8 @@ public class SysLoginService { userInfo = remoteUserService.getUserInfo(username); if (ObjectUtil.isNull(userInfo)) { - recordLogininfor(username, Constants.LOGIN_FAIL, "登录用户不存在"); - throw new ServiceException("登录用户:" + username + " 不存在"); + recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists", username)); + throw new UserException("user.not.exists", username); } } catch (Exception e) { recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()); @@ -56,9 +57,8 @@ public class SysLoginService { Integer errorNumber = RedisUtils.getCacheObject(CacheConstants.LOGIN_ERROR + username); // 锁定时间内登录 则踢出 if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(CacheConstants.LOGIN_ERROR_NUMBER)) { - String msg = "密码错误次数过多,帐户锁定" + CacheConstants.LOGIN_ERROR_LIMIT_TIME + "分钟"; - recordLogininfor(username, Constants.LOGIN_FAIL, msg); - throw new ServiceException(msg, null); + recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", CacheConstants.LOGIN_ERROR_LIMIT_TIME)); + throw new UserException("user.password.retry.limit.exceed", CacheConstants.LOGIN_ERROR_LIMIT_TIME); } if (!BCrypt.checkpw(password, userInfo.getPassword())) { @@ -66,26 +66,24 @@ public class SysLoginService { errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1; // 达到规定错误次数 则锁定登录 if (errorNumber.equals(CacheConstants.LOGIN_ERROR_NUMBER)) { - String msg = "密码错误次数过多,帐户锁定" + CacheConstants.LOGIN_ERROR_LIMIT_TIME + "分钟"; RedisUtils.setCacheObject(CacheConstants.LOGIN_ERROR + username, errorNumber, CacheConstants.LOGIN_ERROR_LIMIT_TIME, TimeUnit.MINUTES); - recordLogininfor(username, Constants.LOGIN_FAIL, msg); - throw new ServiceException(msg, null); + recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.exceed", CacheConstants.LOGIN_ERROR_LIMIT_TIME)); + throw new UserException("user.password.retry.limit.exceed", CacheConstants.LOGIN_ERROR_LIMIT_TIME); } else { // 未达到规定错误次数 则递增 - String msg = "密码输入错误" + errorNumber + "次"; RedisUtils.setCacheObject(CacheConstants.LOGIN_ERROR + username, errorNumber); - recordLogininfor(username, Constants.LOGIN_FAIL, msg); - throw new ServiceException(msg, null); + recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.retry.limit.count", errorNumber)); + throw new UserException("user.password.retry.limit.count", errorNumber); } } // 登录成功 清空错误次数 RedisUtils.deleteObject(CacheConstants.LOGIN_ERROR + username); - recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功"); + recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); return userInfo; } public void logout(String loginName) { - recordLogininfor(loginName, Constants.LOGOUT, "退出成功"); + recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message("user.logout.success")); } /** @@ -97,9 +95,6 @@ public class SysLoginService { // 校验用户类型是否存在 String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); - if (UserConstants.NOT_UNIQUE.equals(remoteUserService.checkUserNameUnique(username))) { - throw new ServiceException("保存用户 " + username + " 失败,注册账号已存在"); - } // 注册用户信息 SysUser sysUser = new SysUser(); sysUser.setUserName(username); @@ -108,9 +103,9 @@ public class SysLoginService { sysUser.setUserType(userType); boolean regFlag = remoteUserService.registerUserInfo(sysUser); if (!regFlag) { - throw new ServiceException("注册失败,请联系系统管理人员"); + throw new UserException("user.register.error"); } - recordLogininfor(username, Constants.REGISTER, "注册成功"); + recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success")); } /** diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CaptchaException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CaptchaException.java index 961f6045..9cca4111 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CaptchaException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/CaptchaException.java @@ -1,14 +1,18 @@ -package com.ruoyi.common.core.exception; - -/** - * 验证码错误异常类 - * - * @author ruoyi - */ -public class CaptchaException extends RuntimeException { - private static final long serialVersionUID = 1L; - - public CaptchaException(String msg) { - super(msg); - } -} +package com.ruoyi.common.core.exception; + +/** + * 验证码错误异常类 + * + * @author Lion Li + */ +public class CaptchaException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public CaptchaException() { + super("user.jcaptcha.error"); + } + + public CaptchaException(String msg) { + super(msg); + } +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java index ba5b87fa..022366b6 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java @@ -42,6 +42,7 @@ public final class ServiceException extends RuntimeException { return detailMessage; } + @Override public String getMessage() { return message; } @@ -59,4 +60,4 @@ public final class ServiceException extends RuntimeException { this.detailMessage = detailMessage; return this; } -} \ No newline at end of file +} diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java index 95c1becd..aa00f84b 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java @@ -1,5 +1,7 @@ package com.ruoyi.common.core.exception.base; +import com.ruoyi.common.core.utils.MessageUtils; +import com.ruoyi.common.core.utils.StringUtils; import lombok.AllArgsConstructor; import lombok.Getter; @@ -49,4 +51,16 @@ public class BaseException extends RuntimeException { this(null, null, null, defaultMessage); } + @Override + public String getMessage() { + String message = null; + if (!StringUtils.isEmpty(code)) { + message = MessageUtils.message(code, args); + } + if (message == null) { + message = defaultMessage; + } + return message; + } + } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java index a65c0564..561b1b63 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java @@ -5,12 +5,12 @@ import com.ruoyi.common.core.exception.base.BaseException; /** * 用户信息异常类 * - * @author ruoyi + * @author Lion Li */ public class UserException extends BaseException { private static final long serialVersionUID = 1L; - public UserException(String code, Object[] args) { + public UserException(String code, Object... args) { super("user", code, args, null); } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java new file mode 100644 index 00000000..24928f88 --- /dev/null +++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java @@ -0,0 +1,28 @@ +package com.ruoyi.common.core.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.springframework.context.MessageSource; +import org.springframework.context.i18n.LocaleContextHolder; + +/** + * 获取i18n资源文件 + * + * @author Lion Li + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class MessageUtils { + + private static final MessageSource MESSAGE_SOURCE = SpringUtils.getBean(MessageSource.class); + + /** + * 根据消息键和参数 获取消息 委托给spring messageSource + * + * @param code 消息键 + * @param args 参数 + * @return 获取国际化翻译值 + */ + public static String message(String code, Object... args) { + return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale()); + } +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/I18nConfig.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/I18nConfig.java new file mode 100644 index 00000000..2f4b1539 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/config/I18nConfig.java @@ -0,0 +1,21 @@ +package com.ruoyi.common.web.config; + +import com.ruoyi.common.web.core.I18nLocaleResolver; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.LocaleResolver; + +/** + * 国际化配置 + * + * @author Lion Li + */ +@Configuration +public class I18nConfig { + + @Bean + public LocaleResolver localeResolver() { + return new I18nLocaleResolver(); + } + +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/I18nLocaleResolver.java b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/I18nLocaleResolver.java new file mode 100644 index 00000000..73fe5b0c --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/java/com/ruoyi/common/web/core/I18nLocaleResolver.java @@ -0,0 +1,31 @@ +package com.ruoyi.common.web.core; + +import org.springframework.web.servlet.LocaleResolver; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Locale; + +/** + * 获取请求头国际化信息 + * + * @author Lion Li + */ +public class I18nLocaleResolver implements LocaleResolver { + + @Override + public Locale resolveLocale(HttpServletRequest httpServletRequest) { + String language = httpServletRequest.getHeader("content-language"); + Locale locale = Locale.getDefault(); + if (language != null && language.length() > 0) { + String[] split = language.split("_"); + locale = new Locale(split[0], split[1]); + } + return locale; + } + + @Override + public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { + + } +} diff --git a/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring.factories b/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring.factories index 485802b1..f6c18046 100644 --- a/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring.factories +++ b/ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring.factories @@ -1 +1,2 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration= \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.ruoyi.common.web.config.I18nConfig diff --git a/ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages.properties b/ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages.properties new file mode 100644 index 00000000..e0e65ce1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages.properties @@ -0,0 +1,39 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.not.blank=验证码不能为空 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码错误次数过多,帐户锁定{0}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] diff --git a/ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages_en_US.properties b/ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 00000000..f113ca8b --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,39 @@ +#错误消息 +not.null=* Required fill in +user.jcaptcha.not.blank=Captcha cannot be blank +user.jcaptcha.error=Captcha error +user.jcaptcha.expire=Captcha invalid +user.not.exists=Sorry, your account: {0} does not exist +user.password.not.match=User does not exist/Password error +user.password.retry.limit.count=Password input error {0} times +user.password.retry.limit.exceed=Too many password errors, account locked for {0} minutes +user.password.delete=Sorry, your account:{0} has been deleted +user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator +role.blocked=Role disabled,please contact administrators +user.logout.success=Exit successful +length.not.valid=The length must be between {min} and {max} characters +user.username.not.blank=Username cannot be blank +user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number +user.username.length.valid=Account length must be between {min} and {max} characters +user.password.not.blank=Password cannot be empty +user.password.length.valid=Password length must be between {min} and {max} characters +user.password.not.valid=* 5-50 characters +user.email.not.valid=Mailbox format error +user.mobile.phone.number.not.valid=Phone number format error +user.login.success=Login successful +user.register.success=Register successful +user.register.save.error=Failed to save user {0}, The registered account already exists +user.register.error=Register failed, please contact system administrator +user.notfound=Please login again +user.forcelogout=The administrator is forced to exit,please login again +user.unknown.error=Unknown error, please login again +##文件上传消息 +upload.exceed.maxSize=The uploaded file size exceeds the limit file size!
the maximum allowed file size is:{0}MB! +upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters +##权限 +no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}] +no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}] +no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}] +no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}] +no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}] +no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}] diff --git a/ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 00000000..e0e65ce1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-web/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,39 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.not.blank=验证码不能为空 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码错误次数过多,帐户锁定{0}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.email.not.valid=邮箱格式错误 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] diff --git a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java index 7b31a612..a770bed2 100644 --- a/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java +++ b/ruoyi-gateway/src/main/java/com/ruoyi/gateway/service/impl/ValidateCodeServiceImpl.java @@ -7,6 +7,7 @@ import cn.hutool.core.util.IdUtil; import com.ruoyi.common.core.constant.Constants; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.exception.CaptchaException; +import com.ruoyi.common.core.exception.user.CaptchaExpireException; import com.ruoyi.common.core.utils.SpringUtils; import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.reflect.ReflectUtils; @@ -85,17 +86,17 @@ public class ValidateCodeServiceImpl implements ValidateCodeService { @Override public void checkCaptcha(String code, String uuid) throws CaptchaException { if (StringUtils.isEmpty(code)) { - throw new CaptchaException("验证码不能为空"); + throw new CaptchaException("user.jcaptcha.not.blank"); } if (StringUtils.isEmpty(uuid)) { - throw new CaptchaException("验证码已失效"); + throw new CaptchaExpireException(); } String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid; String captcha = RedisUtils.getCacheObject(verifyKey); RedisUtils.deleteObject(verifyKey); if (!code.equalsIgnoreCase(captcha)) { - throw new CaptchaException("验证码错误"); + throw new CaptchaException(); } } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/dubbo/RemoteUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/dubbo/RemoteUserServiceImpl.java index 5a0fa081..950bdc0c 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/dubbo/RemoteUserServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/dubbo/RemoteUserServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import com.ruoyi.common.core.constant.UserConstants; import com.ruoyi.common.core.enums.UserStatus; import com.ruoyi.common.core.exception.ServiceException; +import com.ruoyi.common.core.exception.user.UserException; import com.ruoyi.system.api.RemoteUserService; import com.ruoyi.system.api.domain.SysUser; import com.ruoyi.system.api.model.LoginUser; @@ -37,13 +38,13 @@ public class RemoteUserServiceImpl implements RemoteUserService { public LoginUser getUserInfo(String username) { SysUser sysUser = userService.selectUserByUserName(username); if (ObjectUtil.isNull(sysUser)) { - throw new ServiceException("用户名或密码错误"); + throw new UserException("user.not.exists", username); } if (UserStatus.DELETED.getCode().equals(sysUser.getDelFlag())) { - throw new ServiceException("对不起,您的账号:" + username + " 已被删除"); + throw new UserException("user.password.delete", username); } if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) { - throw new ServiceException("对不起,您的账号:" + username + " 已停用"); + throw new UserException("user.blocked", username); } // 角色集合 Set rolePermission = permissionService.getRolePermission(sysUser.getUserId()); @@ -70,13 +71,9 @@ public class RemoteUserServiceImpl implements RemoteUserService { throw new ServiceException("当前系统没有开启注册功能"); } if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(username))) { - throw new ServiceException("保存用户'" + username + "'失败,注册账号已存在"); + throw new UserException("user.register.save.error", username); } return userService.registerUser(sysUser); } - @Override - public String checkUserNameUnique(String username) { - return userService.checkUserNameUnique(username); - } } diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js index 925732ff..dd83fb92 100644 --- a/ruoyi-ui/src/utils/request.js +++ b/ruoyi-ui/src/utils/request.js @@ -1,161 +1,163 @@ -import axios from 'axios' -import { Notification, MessageBox, Message, Loading } from 'element-ui' -import store from '@/store' -import { getToken } from '@/utils/auth' -import errorCode from '@/utils/errorCode' -import { tansParams, blobValidate } from "@/utils/ruoyi"; -import cache from '@/plugins/cache' -import { saveAs } from 'file-saver' - -let downloadLoadingInstance; -// 是否显示重新登录 -let isReloginShow; - -axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' -// 创建axios实例 -const service = axios.create({ - // axios中请求配置有baseURL选项,表示请求URL公共部分 - baseURL: process.env.VUE_APP_BASE_API, - // 超时 - timeout: 10000 -}) - -// request拦截器 -service.interceptors.request.use(config => { - // 是否需要设置 token - const isToken = (config.headers || {}).isToken === false - // 是否需要防止数据重复提交 - const isRepeatSubmit = (config.headers || {}).repeatSubmit === false - if (getToken() && !isToken) { - config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 - } - // get请求映射params参数 - if (config.method === 'get' && config.params) { - let url = config.url + '?' + tansParams(config.params); - url = url.slice(0, -1); - config.params = {}; - config.url = url; - } - if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { - const requestObj = { - url: config.url, - data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, - time: new Date().getTime() - } - const sessionObj = cache.session.getJSON('sessionObj') - if (sessionObj === undefined || sessionObj === null || sessionObj === '') { - cache.session.setJSON('sessionObj', requestObj) - } else { - const s_url = sessionObj.url; // 请求地址 - const s_data = sessionObj.data; // 请求数据 - const s_time = sessionObj.time; // 请求时间 - const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交 - if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) { - const message = '数据正在处理,请勿重复提交'; - console.warn(`[${s_url}]: ` + message) - return Promise.reject(new Error(message)) - } else { - cache.session.setJSON('sessionObj', requestObj) - } - } - } - return config -}, error => { - console.log(error) - Promise.reject(error) -}) - -// 响应拦截器 -service.interceptors.response.use(res => { - // 未设置状态码则默认成功状态 - const code = res.data.code || 200; - // 获取错误信息 - const msg = errorCode[code] || res.data.msg || errorCode['default'] - // 二进制数据则直接返回 - if(res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer'){ - return res.data - } - if (code === 401) { - if (!isReloginShow) { - isReloginShow = true; - MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { - confirmButtonText: '重新登录', - cancelButtonText: '取消', - type: 'warning' - } - ).then(() => { - isReloginShow = false; - store.dispatch('LogOut').then(() => { - // 如果是登录页面不需要重新加载 - if (window.location.hash.indexOf("#/login") != 0) { - location.href = '/index'; - } - }) - }).catch(() => { - isReloginShow = false; - }); - } - return Promise.reject('无效的会话,或者会话已过期,请重新登录。') - } else if (code === 500) { - Message({ - message: msg, - type: 'error' - }) - return Promise.reject(new Error(msg)) - } else if (code !== 200) { - Notification.error({ - title: msg - }) - return Promise.reject('error') - } else { - return res.data - } - }, - error => { - console.log('err' + error) - let { message } = error; - if (message == "Network Error") { - message = "后端接口连接异常"; - } - else if (message.includes("timeout")) { - message = "系统接口请求超时"; - } - else if (message.includes("Request failed with status code")) { - message = "系统接口" + message.substr(message.length - 3) + "异常"; - } - Message({ - message: message, - type: 'error', - duration: 5 * 1000 - }) - return Promise.reject(error) - } -) - -// 通用下载方法 -export function download(url, params, filename) { - downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", }) - return service.post(url, params, { - transformRequest: [(params) => { return tansParams(params) }], - headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, - responseType: 'blob' - }).then(async (data) => { - const isLogin = await blobValidate(data); - if (isLogin) { - const blob = new Blob([data]) - saveAs(blob, filename) - } else { - const resText = await data.text(); - const rspObj = JSON.parse(resText); - const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] - Message.error(errMsg); - } - downloadLoadingInstance.close(); - }).catch((r) => { - console.error(r) - Message.error('下载文件出现错误,请联系管理员!') - downloadLoadingInstance.close(); - }) -} - -export default service +import axios from 'axios' +import { Notification, MessageBox, Message, Loading } from 'element-ui' +import store from '@/store' +import { getToken } from '@/utils/auth' +import errorCode from '@/utils/errorCode' +import { tansParams, blobValidate } from "@/utils/ruoyi"; +import cache from '@/plugins/cache' +import { saveAs } from 'file-saver' + +let downloadLoadingInstance; +// 是否显示重新登录 +let isReloginShow; + +axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8' +// 对应国际化资源文件后缀 +axios.defaults.headers['Content-Language'] = 'zh_CN' +// 创建axios实例 +const service = axios.create({ + // axios中请求配置有baseURL选项,表示请求URL公共部分 + baseURL: process.env.VUE_APP_BASE_API, + // 超时 + timeout: 10000 +}) + +// request拦截器 +service.interceptors.request.use(config => { + // 是否需要设置 token + const isToken = (config.headers || {}).isToken === false + // 是否需要防止数据重复提交 + const isRepeatSubmit = (config.headers || {}).repeatSubmit === false + if (getToken() && !isToken) { + config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改 + } + // get请求映射params参数 + if (config.method === 'get' && config.params) { + let url = config.url + '?' + tansParams(config.params); + url = url.slice(0, -1); + config.params = {}; + config.url = url; + } + if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) { + const requestObj = { + url: config.url, + data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data, + time: new Date().getTime() + } + const sessionObj = cache.session.getJSON('sessionObj') + if (sessionObj === undefined || sessionObj === null || sessionObj === '') { + cache.session.setJSON('sessionObj', requestObj) + } else { + const s_url = sessionObj.url; // 请求地址 + const s_data = sessionObj.data; // 请求数据 + const s_time = sessionObj.time; // 请求时间 + const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交 + if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) { + const message = '数据正在处理,请勿重复提交'; + console.warn(`[${s_url}]: ` + message) + return Promise.reject(new Error(message)) + } else { + cache.session.setJSON('sessionObj', requestObj) + } + } + } + return config +}, error => { + console.log(error) + Promise.reject(error) +}) + +// 响应拦截器 +service.interceptors.response.use(res => { + // 未设置状态码则默认成功状态 + const code = res.data.code || 200; + // 获取错误信息 + const msg = errorCode[code] || res.data.msg || errorCode['default'] + // 二进制数据则直接返回 + if(res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer'){ + return res.data + } + if (code === 401) { + if (!isReloginShow) { + isReloginShow = true; + MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { + confirmButtonText: '重新登录', + cancelButtonText: '取消', + type: 'warning' + } + ).then(() => { + isReloginShow = false; + store.dispatch('LogOut').then(() => { + // 如果是登录页面不需要重新加载 + if (window.location.hash.indexOf("#/login") != 0) { + location.href = '/index'; + } + }) + }).catch(() => { + isReloginShow = false; + }); + } + return Promise.reject('无效的会话,或者会话已过期,请重新登录。') + } else if (code === 500) { + Message({ + message: msg, + type: 'error' + }) + return Promise.reject(new Error(msg)) + } else if (code !== 200) { + Notification.error({ + title: msg + }) + return Promise.reject('error') + } else { + return res.data + } + }, + error => { + console.log('err' + error) + let { message } = error; + if (message == "Network Error") { + message = "后端接口连接异常"; + } + else if (message.includes("timeout")) { + message = "系统接口请求超时"; + } + else if (message.includes("Request failed with status code")) { + message = "系统接口" + message.substr(message.length - 3) + "异常"; + } + Message({ + message: message, + type: 'error', + duration: 5 * 1000 + }) + return Promise.reject(error) + } +) + +// 通用下载方法 +export function download(url, params, filename) { + downloadLoadingInstance = Loading.service({ text: "正在下载数据,请稍候", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", }) + return service.post(url, params, { + transformRequest: [(params) => { return tansParams(params) }], + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + responseType: 'blob' + }).then(async (data) => { + const isLogin = await blobValidate(data); + if (isLogin) { + const blob = new Blob([data]) + saveAs(blob, filename) + } else { + const resText = await data.text(); + const rspObj = JSON.parse(resText); + const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'] + Message.error(errMsg); + } + downloadLoadingInstance.close(); + }).catch((r) => { + console.error(r) + Message.error('下载文件出现错误,请联系管理员!') + downloadLoadingInstance.close(); + }) +} + +export default service diff --git a/ruoyi-ui/src/views/register.vue b/ruoyi-ui/src/views/register.vue index 5bda9892..266e2c2d 100644 --- a/ruoyi-ui/src/views/register.vue +++ b/ruoyi-ui/src/views/register.vue @@ -1,209 +1,210 @@ - - - - - + + + + +