Browse Source

add change password

main
wangshaoping 1 year ago
parent
commit
8244737c23
  1. 5
      io.sc.platform.core.frontend/src/platform/PConst.ts
  2. 20
      io.sc.platform.core.frontend/src/platform/layout/sub-layout/About.vue
  3. 39
      io.sc.platform.core.frontend/src/platform/layout/sub-layout/AboutDialog.vue
  4. 68
      io.sc.platform.core.frontend/src/platform/layout/sub-layout/ChangePasswordDialog.vue
  5. 20
      io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue
  6. 46
      io.sc.platform.core.frontend/src/platform/plugin/axios.ts
  7. 4
      io.sc.platform.core.frontend/src/platform/plugin/manager/NotifyManager.ts
  8. 2
      io.sc.platform.core.frontend/src/platform/plugin/quasar.ts
  9. 28
      io.sc.platform.core.frontend/src/platform/utils/Tools.ts
  10. 9
      io.sc.platform.core/src/main/java/io/sc/platform/core/bean/GlobalExceptionHandler.java
  11. 21
      io.sc.platform.core/src/main/java/io/sc/platform/core/response/ErrorResponseWrapper.java
  12. 3
      io.sc.platform.core/src/main/java/io/sc/platform/core/response/ResponseWrapper.java
  13. 41
      io.sc.platform.core/src/main/java/io/sc/platform/core/util/ValidatorUtil.java
  14. 4
      io.sc.platform.core/src/main/resources/META-INF/platform/plugins/messages.json
  15. 2
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception.properties
  16. 2
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception_tw_CN.properties
  17. 2
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception_zh_CN.properties
  18. 55
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/validator.properties
  19. 52
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/validator_tw_CN.properties
  20. 42
      io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/validator_zh_CN.properties
  21. 13
      io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/autoconfigure/MvcWebMvcAutoConfiguration.java
  22. 172
      io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/autoconfigure/support/RequestHeaderLocaleChangeInterceptor.java
  23. 33
      io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/controller/support/RestCrudController.java
  24. 2
      io.sc.platform.mvc/src/main/resources/META-INF/platform/plugins/application-properties.json
  25. 19
      io.sc.platform.security.oauth2.server.authorization/src/main/java/io/sc/platform/security/oauth2/server/authorization/configure/PlatformWebSecurityAutoConfiguration.java
  26. 31
      io.sc.platform.system/src/main/java/io/sc/platform/system/user/controller/UserWebController.java
  27. 40
      io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/support/ChangePassword.java

5
io.sc.platform.core.frontend/src/platform/PConst.ts

@ -73,6 +73,11 @@ class PConst {
* *
*/ */
static MAIN_LAYOUT_PROVIDER_NAME: string = 'MAIN'; static MAIN_LAYOUT_PROVIDER_NAME: string = 'MAIN';
/**
*
*/
static REQUEST_PARAMETER_VALIDATE_ERROR_CODE = 1001;
} }
export { PConst }; export { PConst };

20
io.sc.platform.core.frontend/src/platform/layout/sub-layout/About.vue

@ -1,20 +0,0 @@
<template>
<q-card class="shadow-transition">
<q-card-section class="row items-center q-pb-none">
<div class="text-h6">{{ $t('about') }}</div>
<q-space />
<q-btn v-close-popup icon="close" flat round dense />
</q-card-section>
<q-card-section>
<div class="row justify-items-center">
<div class="text-base w-full text-center py-4 font-bold">{{ $t('application.title') }}</div>
<div class="text-base w-full text-center">{{ $t('version') }} : {{ $t('application.version') }}</div>
<div class="text-base w-full text-center">{{ $t('springbootVersion') }} : {{ $t('springboot.version') }}</div>
<div class="text-base w-full text-center">{{ $t('application.copyright') }}</div>
</div>
</q-card-section>
<q-card-section></q-card-section>
</q-card>
</template>
<script setup lang="ts"></script>

39
io.sc.platform.core.frontend/src/platform/layout/sub-layout/AboutDialog.vue

@ -0,0 +1,39 @@
<template>
<q-dialog ref="dialogRef">
<q-card class="shadow-transition">
<q-card-section class="row items-center q-pb-none">
<div class="text-h6">{{ $t('about') }}</div>
<q-space />
<q-btn v-close-popup icon="close" flat round dense />
</q-card-section>
<q-card-section>
<div class="row justify-items-center">
<div class="text-base w-full text-center py-4 font-bold">{{ $t('application.title') }}</div>
<div class="text-base w-full text-center">{{ $t('version') }} : {{ $t('application.version') }}</div>
<div class="text-base w-full text-center">{{ $t('springbootVersion') }} : {{ $t('springboot.version') }}</div>
<div class="text-base w-full text-center">{{ $t('application.copyright') }}</div>
</div>
</q-card-section>
<q-card-section></q-card-section>
</q-card>
</q-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const dialogRef = ref();
const open = () => {
dialogRef.value.show();
};
const close = () => {
dialogRef.value.hide();
};
defineExpose({
open,
close,
});
</script>

68
io.sc.platform.core.frontend/src/platform/layout/sub-layout/ChangePasswordDialog.vue

@ -1,24 +1,35 @@
<template> <template>
<w-dialog <w-dialog
ref="changePasswordDialogRef" ref="changePasswordDialogRef"
width="400px" width="500px"
height="300px" height="300px"
:title="$t('changePassword')" :title="$t('changePassword')"
:can-maximize="false" :can-maximize="false"
:buttons="[ :buttons="[
{ {
label: $t('submit'), label: $t('submit'),
noCaps: true,
click: changePassword, click: changePassword,
}, },
]" ]"
> >
<w-form <w-form ref="changePasswordFormRef" :cols-num="1" :fields="computedFormFields" class="p-2"></w-form>
ref="changePasswordFormRef" </w-dialog>
:cols-num="1" </template>
:fields="[ <script setup lang="ts">
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { PConst, Environment, axios, NotifyManager } from '@/platform';
const { t } = useI18n();
const changePasswordDialogRef = ref();
const changePasswordFormRef = ref();
const computedFormFields = computed(() => {
return [
{ {
name: 'rawPassword', name: 'rawPassword',
label: $t('rawPassword'), label: t('rawPassword'),
type: 'password', type: 'password',
requiredIf: () => { requiredIf: () => {
return true; return true;
@ -26,7 +37,7 @@
}, },
{ {
name: 'newPassword', name: 'newPassword',
label: $t('newPassword'), label: t('newPassword'),
type: 'password', type: 'password',
requiredIf: () => { requiredIf: () => {
return true; return true;
@ -34,52 +45,47 @@
}, },
{ {
name: 'confirmNewPassword', name: 'confirmNewPassword',
label: $t('confirmNewPassword'), label: t('confirmNewPassword'),
type: 'password', type: 'password',
requiredIf: () => { requiredIf: () => {
return true; return true;
}, },
rules: [ rules: [
(val) => { (value) => {
return changePasswordFormRef.data.newPassword != val ? $t('passwordAndConfirmPasswordMustEqual') : true; return changePasswordFormRef.value.data.newPassword != value ? t('passwordAndConfirmPasswordMustEqual') : true;
}, },
], ],
}, },
]" ];
class="p-2" });
></w-form>
</w-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { Environment } from '@/platform/plugin/environment';
import { axios, NotifyManager } from '@/platform/plugin';
const { t } = useI18n();
const changePasswordDialogRef = ref();
const changePasswordFormRef = ref();
const changePassword = async () => { const changePassword = async () => {
const result = await changePasswordFormRef.value.validate(); const result = await changePasswordFormRef.value.validate();
if (result) { if (result) {
axios.post(Environment.apiContextPath('/api/system/user/changePassword'), changePasswordFormRef.value.getData()).then((response) => { axios
hide(); .post(Environment.apiContextPath('/api/system/user/changePassword'), changePasswordFormRef.value.getData())
NotifyManager.info(t('operationSuccess')); .then(() => {
close();
NotifyManager.success();
})
.catch((error) => {
if (error.code === PConst.REQUEST_PARAMETER_VALIDATE_ERROR_CODE) {
changePasswordFormRef.value.setValidationErrors(error.data);
}
}); });
} }
}; };
const show = () => { const open = () => {
changePasswordDialogRef.value.show(); changePasswordDialogRef.value.show();
}; };
const hide = () => { const close = () => {
changePasswordDialogRef.value.hide(); changePasswordDialogRef.value.hide();
}; };
defineExpose({ defineExpose({
show, open,
hide, close,
}); });
</script> </script>

20
io.sc.platform.core.frontend/src/platform/layout/sub-layout/Topper.vue

@ -15,6 +15,7 @@
:height="gc.theme.topper.logoHeight + 'px'" :height="gc.theme.topper.logoHeight + 'px'"
:style="{ :style="{
'min-width': gc.theme.topper.logoWidth + 'px', 'min-width': gc.theme.topper.logoWidth + 'px',
fill: 'red',
}" }"
/> />
@ -150,31 +151,26 @@
</q-btn> </q-btn>
</q-toolbar> </q-toolbar>
<q-dialog v-model="showAboutDialog"> <q-form ref="logoutForm" :action="Environment.apiContextPath('/logout')" method="post"> </q-form>
<About></About>
</q-dialog>
<AboutDialog ref="aboutDialog"></AboutDialog>
<ChangePasswordDialog ref="changePasswordDialog"></ChangePasswordDialog> <ChangePasswordDialog ref="changePasswordDialog"></ChangePasswordDialog>
<q-form ref="logoutForm" :action="Environment.apiContextPath('/logout')" method="post"> </q-form>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { UserSessionType } from '@/platform/types'; import type { UserSessionType } from '@/platform/types';
import { ref } from 'vue'; import { ref } from 'vue';
import { useRouter } from 'vue-router';
import { useQuasar, SessionStorage } from 'quasar'; import { useQuasar, SessionStorage } from 'quasar';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { Environment, SessionManager, I18nMessageManager } from '@/platform'; import { Environment, SessionManager, I18nMessageManager, Tools } from '@/platform';
import About from './About.vue'; import AboutDialog from './AboutDialog.vue';
import ChangePasswordDialog from './ChangePasswordDialog.vue'; import ChangePasswordDialog from './ChangePasswordDialog.vue';
const gc = Environment.getConfigure(); const gc = Environment.getConfigure();
const quasar = useQuasar(); const quasar = useQuasar();
const router = useRouter();
const searchContent = ref(''); const searchContent = ref('');
const showAboutDialog = ref(false); const aboutDialog = ref();
const changePasswordDialog = ref(); const changePasswordDialog = ref();
const { t } = useI18n(); const { t } = useI18n();
const session: UserSessionType = SessionManager.getSession() as UserSessionType; const session: UserSessionType = SessionManager.getSession() as UserSessionType;
@ -226,11 +222,11 @@ const doLogout = () => {
}; };
const about = () => { const about = () => {
showAboutDialog.value = true; aboutDialog.value.open();
}; };
const changePassword = () => { const changePassword = () => {
changePasswordDialog.value.show(); changePasswordDialog.value.open();
}; };
Environment.registAction('about', about); Environment.registAction('about', about);

46
io.sc.platform.core.frontend/src/platform/plugin/axios.ts

@ -17,6 +17,7 @@ const axios = Axios.create({
// 请求拦截器 // 请求拦截器
axios.interceptors.request.use( axios.interceptors.request.use(
(config: any) => { (config: any) => {
config.headers.locale = gc.setting.i18n.locale;
// 忽略无需认证的请求 URL // 忽略无需认证的请求 URL
for (const url of ignoredUrls) { for (const url of ignoredUrls) {
if (config.url.includes(url)) { if (config.url.includes(url)) {
@ -38,17 +39,8 @@ axios.interceptors.request.use(
// 响应拦截器 // 响应拦截器
axios.interceptors.response.use( axios.interceptors.response.use(
(response: any) => { (response: any) => {
// 请求正确, 进入该方法说明 response 的状态码为 2xx // 请求成功, 进入该方法说明 response 的状态码为 2xx
const data = response.data; return response.data;
if (data.code === 200) {
// 业务正确
response.data = data.data;
return response;
} else {
// 业务错误
NotifyManager.error(i18n.global.t(data.errorMessageI18nKey));
return Promise.reject(data);
}
}, },
(error: any) => { (error: any) => {
// 请求失败, 进入该方法说明 response 的状态码不为 2xx // 请求失败, 进入该方法说明 response 的状态码不为 2xx
@ -56,19 +48,33 @@ axios.interceptors.response.use(
// 发生网络错误 // 发生网络错误
const $t = i18n.global.t; const $t = i18n.global.t;
NotifyManager.error($t('NetworkError')); NotifyManager.error($t('NetworkError'));
return Promise.reject(error); return Promise.reject({
code: 'NetworkError',
errorMessageI18nKey: 'NetworkError',
errorMessage: error.message,
exception: 'NetworkError',
stackTrace: error.stack,
data: null,
});
} else { } else {
// 服务器端错误
const response = error?.response; const response = error?.response;
const status = response?.status;
const data = response?.data; const data = response?.data;
let messageKey = data?.errorMessageI18nKey; if (status === 500) {
if (Tools.isUndefinedOrNull(messageKey)) { NotifyManager.error(i18n.global.t(data?.errorMessageI18nKey));
messageKey = response?.status; return Promise.reject(response.data);
} } else {
if (Tools.isUndefinedOrNull(messageKey)) { NotifyManager.error(i18n.global.t(status));
messageKey = 'error'; return Promise.reject({
code: status,
errorMessageI18nKey: status,
errorMessage: error.message,
exception: error.code,
stackTrace: error.stack,
data: null,
});
} }
NotifyManager.error(i18n.global.t(messageKey));
return Promise.reject(data);
} }
}, },
); );

4
io.sc.platform.core.frontend/src/platform/plugin/manager/NotifyManager.ts

@ -29,6 +29,10 @@ class NotifyManager {
NotifyManager.#closeFunctions[options['uuid']] = Notify.create(options); NotifyManager.#closeFunctions[options['uuid']] = Notify.create(options);
} }
public static success() {
NotifyManager.info(i18n.global.t('operationSuccess'));
}
public static info(options: QNotifyCreateOptions | string) { public static info(options: QNotifyCreateOptions | string) {
const notifyCreateOptions = NotifyManager.createOptions('info', options); const notifyCreateOptions = NotifyManager.createOptions('info', options);
if (NotifyManager.#initialized) { if (NotifyManager.#initialized) {

2
io.sc.platform.core.frontend/src/platform/plugin/quasar.ts

@ -4,6 +4,8 @@ import type { I18nMessageLocaleType } from '@/platform/types';
import { Environment } from '@/platform/plugin/environment'; import { Environment } from '@/platform/plugin/environment';
import { I18nMessageManager } from '@/platform/plugin/manager'; import { I18nMessageManager } from '@/platform/plugin/manager';
import { QBtn } from 'quasar';
const gc = Environment.getConfigure(); const gc = Environment.getConfigure();
const eventBus: any = new EventBus(); const eventBus: any = new EventBus();

28
io.sc.platform.core.frontend/src/platform/utils/Tools.ts

@ -767,6 +767,34 @@ class Tools {
} }
return []; return [];
} }
public static uuid() {
if (typeof crypto === 'object') {
if (typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
if (typeof crypto.getRandomValues === 'function' && typeof Uint8Array === 'function') {
const callback = (c) => {
const num = Number(c);
return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(16);
};
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, callback);
}
}
let timestamp = new Date().getTime();
let perforNow = (typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0;
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
let random = Math.random() * 16;
if (timestamp > 0) {
random = (timestamp + random) % 16 | 0;
timestamp = Math.floor(timestamp / 16);
} else {
random = (perforNow + random) % 16 | 0;
perforNow = Math.floor(perforNow / 16);
}
return (c === 'x' ? random : (random & 0x3) | 0x8).toString(16);
});
}
} }
export { Tools }; export { Tools };

9
io.sc.platform.core/src/main/java/io/sc/platform/core/bean/GlobalExceptionHandler.java

@ -1,7 +1,9 @@
package io.sc.platform.core.bean; package io.sc.platform.core.bean;
import io.sc.platform.core.response.ErrorResponseWrapper;
import io.sc.platform.core.response.ResponseWrapper; import io.sc.platform.core.response.ResponseWrapper;
import io.sc.platform.core.response.ResponseWrapperBuilder; import io.sc.platform.core.response.ResponseWrapperBuilder;
import io.sc.platform.core.response.ValidateException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -26,6 +28,13 @@ public class GlobalExceptionHandler {
@ResponseBody @ResponseBody
public ResponseWrapper exceptionHandler(HttpServletRequest request, Exception e){ public ResponseWrapper exceptionHandler(HttpServletRequest request, Exception e){
log.error("",e); log.error("",e);
if(e instanceof ValidateException){
ValidateException exception =(ValidateException)e;
ErrorResponseWrapper error =(ErrorResponseWrapper)ResponseWrapperBuilder.error(e);
error.setCode(ResponseWrapper.VALIDATE_ERROR);
error.setData(exception.getErrors());
return error;
}
return ResponseWrapperBuilder.error(e); return ResponseWrapperBuilder.error(e);
} }
} }

21
io.sc.platform.core/src/main/java/io/sc/platform/core/response/ErrorResponseWrapper.java

@ -6,11 +6,12 @@ import java.io.StringWriter;
/** /**
* 错误返回值封装器 * 错误返回值封装器
*/ */
public class ErrorResponseWrapper extends ResponseWrapper{ public class ErrorResponseWrapper<T> extends ResponseWrapper{
private String errorMessageI18nKey; private String errorMessageI18nKey;
private String errorMessage; private String errorMessage;
private String exception; private String exception;
private String stackTrace; private String stackTrace;
private T data;
public ErrorResponseWrapper(Exception e){ public ErrorResponseWrapper(Exception e){
this.setErrorMessageI18nKey(e.getClass().getName()); this.setErrorMessageI18nKey(e.getClass().getName());
@ -21,6 +22,16 @@ public class ErrorResponseWrapper extends ResponseWrapper{
this.setStackTrace(sw.toString()); this.setStackTrace(sw.toString());
} }
public ErrorResponseWrapper(Exception e,T data){
this.setErrorMessageI18nKey(e.getClass().getName());
this.setErrorMessage(e.getMessage());
this.setException(e.getClass().getName());
StringWriter sw =new StringWriter();
e.printStackTrace(new PrintWriter(sw,true));
this.setStackTrace(sw.toString());
this.setData(data);
}
public String getErrorMessageI18nKey() { public String getErrorMessageI18nKey() {
return errorMessageI18nKey; return errorMessageI18nKey;
} }
@ -52,4 +63,12 @@ public class ErrorResponseWrapper extends ResponseWrapper{
public void setStackTrace(String stackTrace) { public void setStackTrace(String stackTrace) {
this.stackTrace = stackTrace; this.stackTrace = stackTrace;
} }
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
} }

3
io.sc.platform.core/src/main/java/io/sc/platform/core/response/ResponseWrapper.java

@ -6,7 +6,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
* 返回值封装器 * 返回值封装器
*/ */
public class ResponseWrapper { public class ResponseWrapper {
protected static final int SUCCESS_CODE =200; public static final int SUCCESS_CODE =200;
public static final int VALIDATE_ERROR =1001;
protected int code; protected int code;

41
io.sc.platform.core/src/main/java/io/sc/platform/core/util/ValidatorUtil.java

@ -0,0 +1,41 @@
package io.sc.platform.core.util;
import io.sc.platform.core.response.ValidateException;
import io.sc.platform.core.response.ValidationError;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import javax.validation.MessageInterpolator;
import java.util.ArrayList;
import java.util.List;
public class ValidatorUtil {
public static ValidateException validate(BindingResult bindingResult) throws ValidateException {
if(bindingResult==null || !bindingResult.hasErrors()){
return null;
}
List<FieldError> errors =bindingResult.getFieldErrors();
if(errors==null || errors.size()==0){
return null;
}
List<ValidationError> errorList =new ArrayList<ValidationError>();
for(FieldError error : errors){
Object[] objects =error.getArguments();
for(Object o : objects){
System.out.println(o.getClass().getName());
}
errorList.add(new ValidationError(getFieldName(error.getField()),error.getDefaultMessage()));
}
throw new ValidateException(errorList);
}
private static String getFieldName(String field){
int index =field.lastIndexOf(".");
if(index>-1){
return field.substring(index+1);
}else{
return field;
}
}
}

4
io.sc.platform.core/src/main/resources/META-INF/platform/plugins/messages.json

@ -1,9 +1,11 @@
{ {
"includes":[ "includes":[
"io/sc/platform/core/i18n/enums", "io/sc/platform/core/i18n/enums",
"io/sc/platform/core/i18n/exception",
"io/sc/platform/core/i18n/language", "io/sc/platform/core/i18n/language",
"io/sc/platform/core/i18n/messages", "io/sc/platform/core/i18n/messages",
"io/sc/platform/core/i18n/network-error", "io/sc/platform/core/i18n/network-error",
"io/sc/platform/core/i18n/words" "io/sc/platform/core/i18n/words",
"io/sc/platform/core/i18n/validator"
] ]
} }

2
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception.properties

@ -0,0 +1,2 @@
io.sc.platform.core.response.ValidateException=Request Parameter Validate Error
io.sc.platform.orm.api.exception.UserRawPasswordNotMatchException=Raw Password Error

2
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception_tw_CN.properties

@ -0,0 +1,2 @@
io.sc.platform.core.response.ValidateException=\u8ACB\u6C42\u53C3\u6578\u9A57\u8B49\u932F\u8AA4
io.sc.platform.orm.api.exception.UserRawPasswordNotMatchException=\u539F\u5BC6\u78BC\u932F\u8AA4

2
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/exception_zh_CN.properties

@ -0,0 +1,2 @@
io.sc.platform.core.response.ValidateException=\u8BF7\u6C42\u53C2\u6570\u9A8C\u8BC1\u9519\u8BEF
io.sc.platform.orm.api.exception.UserRawPasswordNotMatchException=\u539F\u5BC6\u7801\u9519\u8BEF

55
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/validator.properties

@ -0,0 +1,55 @@
javax.validation.constraints.AssertFalse.message = must be false
javax.validation.constraints.AssertTrue.message = must be true
javax.validation.constraints.DecimalMax.message = must be less than ${inclusive == true ? 'or equal to ' : ''}{value}
javax.validation.constraints.DecimalMin.message = must be greater than ${inclusive == true ? 'or equal to ' : ''}{value}
javax.validation.constraints.Digits.message = numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected)
javax.validation.constraints.Email.message = must be a well-formed email address
javax.validation.constraints.Future.message = must be a future date
javax.validation.constraints.FutureOrPresent.message = must be a date in the present or in the future
javax.validation.constraints.Max.message = must be less than or equal to {value}
javax.validation.constraints.Min.message = must be greater than or equal to {value}
javax.validation.constraints.Negative.message = must be less than 0
javax.validation.constraints.NegativeOrZero.message = must be less than or equal to 0
javax.validation.constraints.NotBlank.message = must not be blank
javax.validation.constraints.NotEmpty.message = must not be empty
javax.validation.constraints.NotNull.message = must not be null
javax.validation.constraints.Null.message = must be null
javax.validation.constraints.Past.message = must be a past date
javax.validation.constraints.PastOrPresent.message = must be a date in the past or in the present
javax.validation.constraints.Pattern.message = must match "{regexp}"
javax.validation.constraints.Positive.message = must be greater than 0
javax.validation.constraints.PositiveOrZero.message = must be greater than or equal to 0
javax.validation.constraints.Size.message = size must be between {min} and {max}
org.hibernate.validator.constraints.CreditCardNumber.message = invalid credit card number
org.hibernate.validator.constraints.Currency.message = invalid currency (must be one of {value})
org.hibernate.validator.constraints.EAN.message = invalid {type} barcode
org.hibernate.validator.constraints.Email.message = not a well-formed email address
org.hibernate.validator.constraints.ISBN.message = invalid ISBN
org.hibernate.validator.constraints.Length.message = length must be between {min} and {max}
org.hibernate.validator.constraints.CodePointLength.message = length must be between {min} and {max}
org.hibernate.validator.constraints.LuhnCheck.message = the check digit for ${validatedValue} is invalid, Luhn Modulo 10 checksum failed
org.hibernate.validator.constraints.Mod10Check.message = the check digit for ${validatedValue} is invalid, Modulo 10 checksum failed
org.hibernate.validator.constraints.Mod11Check.message = the check digit for ${validatedValue} is invalid, Modulo 11 checksum failed
org.hibernate.validator.constraints.ModCheck.message = the check digit for ${validatedValue} is invalid, {modType} checksum failed
org.hibernate.validator.constraints.Normalized.message = must be normalized
org.hibernate.validator.constraints.NotBlank.message = may not be empty
org.hibernate.validator.constraints.NotEmpty.message = may not be empty
org.hibernate.validator.constraints.ParametersScriptAssert.message = script expression "{script}" didn't evaluate to true
org.hibernate.validator.constraints.Range.message = must be between {min} and {max}
org.hibernate.validator.constraints.ScriptAssert.message = script expression "{script}" didn't evaluate to true
org.hibernate.validator.constraints.UniqueElements.message = must only contain unique elements
org.hibernate.validator.constraints.URL.message = must be a valid URL
org.hibernate.validator.constraints.br.CNPJ.message = invalid Brazilian corporate taxpayer registry number (CNPJ)
org.hibernate.validator.constraints.br.CPF.message = invalid Brazilian individual taxpayer registry number (CPF)
org.hibernate.validator.constraints.br.TituloEleitoral.message = invalid Brazilian Voter ID card number
org.hibernate.validator.constraints.pl.REGON.message = invalid Polish Taxpayer Identification Number (REGON)
org.hibernate.validator.constraints.pl.NIP.message = invalid VAT Identification Number (NIP)
org.hibernate.validator.constraints.pl.PESEL.message = invalid Polish National Identification Number (PESEL)
org.hibernate.validator.constraints.ru.INN.message = invalid Russian taxpayer identification number (INN)
org.hibernate.validator.constraints.time.DurationMax.message = must be shorter than${inclusive == true ? ' or equal to' : ''}${days == 0 ? '' : days == 1 ? ' 1 day' : ' ' += days += ' days'}${hours == 0 ? '' : hours == 1 ? ' 1 hour' : ' ' += hours += ' hours'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minute' : ' ' += minutes += ' minutes'}${seconds == 0 ? '' : seconds == 1 ? ' 1 second' : ' ' += seconds += ' seconds'}${millis == 0 ? '' : millis == 1 ? ' 1 milli' : ' ' += millis += ' millis'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nano' : ' ' += nanos += ' nanos'}
org.hibernate.validator.constraints.time.DurationMin.message = must be longer than${inclusive == true ? ' or equal to' : ''}${days == 0 ? '' : days == 1 ? ' 1 day' : ' ' += days += ' days'}${hours == 0 ? '' : hours == 1 ? ' 1 hour' : ' ' += hours += ' hours'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minute' : ' ' += minutes += ' minutes'}${seconds == 0 ? '' : seconds == 1 ? ' 1 second' : ' ' += seconds += ' seconds'}${millis == 0 ? '' : millis == 1 ? ' 1 milli' : ' ' += millis += ' millis'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nano' : ' ' += nanos += ' nanos'}

52
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/validator_tw_CN.properties

@ -0,0 +1,52 @@
javax.validation.constraints.AssertFalse.message = \u5FC5\u9808\u662F false
javax.validation.constraints.AssertTrue.message = \u5FC5\u9808\u662F true
javax.validation.constraints.DecimalMax.message = \u5FC5\u9808\u5C0F\u65BC ${inclusive == true ? 'or equal to ' : ''}{value}
javax.validation.constraints.DecimalMin.message = \u5FC5\u9808\u5927\u65BC ${inclusive == true ? 'or equal to ' : ''}{value}
javax.validation.constraints.Digits.message = \u6578\u503C\u8D85\u51FA\u7BC4\u570D\uFF08\u9810\u671F\u70BA <{integer} digits>.<{fraction} digits>\uFF09
javax.validation.constraints.Email.message = \u5FC5\u9808\u662F\u5F62\u5F0F\u5B8C\u6574\u7684\u96FB\u5B50\u90F5\u4EF6\u4F4D\u5740
javax.validation.constraints.Future.message = \u5FC5\u9808\u662F\u672A\u4F86\u7684\u65E5\u671F
javax.validation.constraints.FutureOrPresent.message = \u5FC5\u9808\u662F\u7576\u5929\u6216\u672A\u4F86\u7684\u65E5\u671F
javax.validation.constraints.Max.message = \u5FC5\u9808\u5C0F\u65BC\u6216\u7B49\u65BC {value}
javax.validation.constraints.Min.message = \u5FC5\u9808\u5927\u65BC\u6216\u7B49\u65BC {value}
javax.validation.constraints.Negative.message = \u5FC5\u9808\u5C0F\u65BC 0
javax.validation.constraints.NegativeOrZero.message = \u5FC5\u9808\u5C0F\u65BC\u6216\u7B49\u65BC 0
javax.validation.constraints.NotBlank.message = \u4E0D\u5F97\u7A7A\u767D
javax.validation.constraints.NotEmpty.message = \u4E0D\u5F97\u662F\u7A7A\u7684
javax.validation.constraints.NotNull.message = \u4E0D\u5F97\u662F\u7A7A\u503C
javax.validation.constraints.Null.message = \u5FC5\u9808\u662F\u7A7A\u503C
javax.validation.constraints.Past.message = \u5FC5\u9808\u662F\u904E\u53BB\u7684\u65E5\u671F
javax.validation.constraints.PastOrPresent.message = \u5FC5\u9808\u662F\u904E\u53BB\u6216\u7576\u5929\u7684\u65E5\u671F
javax.validation.constraints.Pattern.message = \u5FC5\u9808\u7B26\u5408 "{regexp}"
javax.validation.constraints.Positive.message = \u5FC5\u9808\u5927\u65BC 0
javax.validation.constraints.PositiveOrZero.message = \u5FC5\u9808\u5927\u65BC\u6216\u7B49\u65BC 0
javax.validation.constraints.Size.message = \u5927\u5C0F\u5FC5\u9808\u5728 {min} \u548C {max} \u4E4B\u9593
org.hibernate.validator.constraints.CreditCardNumber.message = \u7121\u6548\u7684\u4FE1\u7528\u5361\u5361\u865F
org.hibernate.validator.constraints.Currency.message = \u7121\u6548\u7684\u8CA8\u5E63\uFF08\u5FC5\u9808\u662F {value} \u4E4B\u4E00\uFF09
org.hibernate.validator.constraints.EAN.message = \u7121\u6548\u7684 {type} \u689D\u78BC
org.hibernate.validator.constraints.Email.message = \u4E0D\u662F\u5F62\u5F0F\u5B8C\u6574\u7684\u96FB\u5B50\u90F5\u4EF6\u4F4D\u5740
org.hibernate.validator.constraints.ISBN.message = \u7121\u6548\u7684 ISBN
org.hibernate.validator.constraints.Length.message = \u9577\u5EA6\u5FC5\u9808\u5728 {min} \u548C {max} \u4E4B\u9593
org.hibernate.validator.constraints.CodePointLength.message = \u9577\u5EA6\u5FC5\u9808\u5728 {min} \u548C {max} \u4E4B\u9593
org.hibernate.validator.constraints.LuhnCheck.message = ${validatedValue} \u7684\u6AA2\u67E5\u78BC\u7121\u6548\uFF0CLuhn \u6A21\u6578 10 \u7E3D\u548C\u6AA2\u67E5\u5931\u6557
org.hibernate.validator.constraints.Mod10Check.message = ${validatedValue} \u7684\u6AA2\u67E5\u78BC\u7121\u6548\uFF0C\u6A21\u6578 10 \u7E3D\u548C\u6AA2\u67E5\u5931\u6557
org.hibernate.validator.constraints.Mod11Check.message = ${validatedValue} \u7684\u6AA2\u67E5\u78BC\u7121\u6548\uFF0C\u6A21\u6578 11 \u7E3D\u548C\u6AA2\u67E5\u5931\u6557
org.hibernate.validator.constraints.ModCheck.message = ${validatedValue} \u7684\u6AA2\u67E5\u78BC\u7121\u6548\uFF0C{modType} \u7E3D\u548C\u6AA2\u67E5\u5931\u6557
org.hibernate.validator.constraints.NotBlank.message = \u4E0D\u80FD\u662F\u7A7A\u7684
org.hibernate.validator.constraints.NotEmpty.message = \u4E0D\u80FD\u662F\u7A7A\u7684
org.hibernate.validator.constraints.ParametersScriptAssert.message = Script \u8868\u793A\u5F0F "{script}" \u4E0D\u662F\u6C42\u503C\u70BA true
org.hibernate.validator.constraints.Range.message = \u5FC5\u9808\u5728 {min} \u548C {max} \u4E4B\u9593
org.hibernate.validator.constraints.ScriptAssert.message = Script \u8868\u793A\u5F0F "{script}" \u4E0D\u662F\u6C42\u503C\u70BA true
org.hibernate.validator.constraints.UniqueElements.message = \u53EA\u80FD\u5305\u542B\u552F\u4E00\u5143\u7D20
org.hibernate.validator.constraints.URL.message = \u5FC5\u9808\u662F\u6709\u6548\u7684 URL
org.hibernate.validator.constraints.br.CNPJ.message = \u7121\u6548\u7684\u5DF4\u897F\u516C\u53F8\u7D0D\u7A05\u767B\u9304\u78BC (CNPJ)
org.hibernate.validator.constraints.br.CPF.message = \u7121\u6548\u7684\u5DF4\u897F\u500B\u4EBA\u7D0D\u7A05\u767B\u9304\u78BC (CPF)
org.hibernate.validator.constraints.br.TituloEleitoral.message = \u7121\u6548\u7684\u5DF4\u897F\u9078\u6C11 ID \u5361\u865F
org.hibernate.validator.constraints.pl.REGON.message = \u7121\u6548\u7684\u6CE2\u862D\u7D0D\u7A05\u4EBA\u8B58\u5225\u78BC (REGON)
org.hibernate.validator.constraints.pl.NIP.message = \u7121\u6548\u7684 VAT \u8B58\u5225\u78BC (NIP)
org.hibernate.validator.constraints.pl.PESEL.message = \u7121\u6548\u7684\u6CE2\u862D\u570B\u5BB6\u8B58\u5225\u78BC (PESEL)
org.hibernate.validator.constraints.time.DurationMax.message = \u5FC5\u9808\u77ED\u65BC ${inclusive == true ? ' or equal to' : ''}${days == 0 ? '' : days == 1 ? ' 1 day' : ' ' += days += ' days'}${hours == 0 ? '' : hours == 1 ? ' 1 hour' : ' ' += hours += ' hours'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minute' : ' ' += minutes += ' minutes'}${seconds == 0 ? '' : seconds == 1 ? ' 1 second' : ' ' += seconds += ' seconds'}${millis == 0 ? '' : millis == 1 ? ' 1 milli' : ' ' += millis += ' millis'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nano' : ' ' += nanos += ' nanos'}
org.hibernate.validator.constraints.time.DurationMin.message = \u5FC5\u9808\u9577\u65BC ${inclusive == true ? ' or equal to' : ''}${days == 0 ? '' : days == 1 ? ' 1 day' : ' ' += days += ' days'}${hours == 0 ? '' : hours == 1 ? ' 1 hour' : ' ' += hours += ' hours'}${minutes == 0 ? '' : minutes == 1 ? ' 1 minute' : ' ' += minutes += ' minutes'}${seconds == 0 ? '' : seconds == 1 ? ' 1 second' : ' ' += seconds += ' seconds'}${millis == 0 ? '' : millis == 1 ? ' 1 milli' : ' ' += millis += ' millis'}${nanos == 0 ? '' : nanos == 1 ? ' 1 nano' : ' ' += nanos += ' nanos'}

42
io.sc.platform.core/src/main/resources/io/sc/platform/core/i18n/validator_zh_CN.properties

@ -0,0 +1,42 @@
javax.validation.constraints.AssertFalse.message = \u53EA\u80FD\u4E3Afalse
javax.validation.constraints.AssertTrue.message = \u53EA\u80FD\u4E3Atrue
javax.validation.constraints.DecimalMax.message = \u5FC5\u987B\u5C0F\u4E8E${inclusive == true ? '\u6216\u7B49\u4E8E' : ''}{value}
javax.validation.constraints.DecimalMin.message = \u5FC5\u987B\u5927\u4E8E${inclusive == true ? '\u6216\u7B49\u4E8E' : ''}{value}
javax.validation.constraints.Digits.message = \u6570\u5B57\u7684\u503C\u8D85\u51FA\u4E86\u5141\u8BB8\u8303\u56F4(\u53EA\u5141\u8BB8\u5728{integer}\u4F4D\u6574\u6570\u548C{fraction}\u4F4D\u5C0F\u6570\u8303\u56F4\u5185)
javax.validation.constraints.Email.message = \u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684\u7535\u5B50\u90AE\u4EF6\u5730\u5740
javax.validation.constraints.Future.message = \u9700\u8981\u662F\u4E00\u4E2A\u5C06\u6765\u7684\u65F6\u95F4
javax.validation.constraints.FutureOrPresent.message = \u9700\u8981\u662F\u4E00\u4E2A\u5C06\u6765\u6216\u73B0\u5728\u7684\u65F6\u95F4
javax.validation.constraints.Max.message = \u6700\u5927\u4E0D\u80FD\u8D85\u8FC7{value}
javax.validation.constraints.Min.message = \u6700\u5C0F\u4E0D\u80FD\u5C0F\u4E8E{value}
javax.validation.constraints.Negative.message = \u5FC5\u987B\u662F\u8D1F\u6570
javax.validation.constraints.NegativeOrZero.message = \u5FC5\u987B\u662F\u8D1F\u6570\u6216\u96F6
javax.validation.constraints.NotBlank.message = \u4E0D\u80FD\u4E3A\u7A7A
javax.validation.constraints.NotEmpty.message = \u4E0D\u80FD\u4E3A\u7A7A
javax.validation.constraints.NotNull.message = \u4E0D\u80FD\u4E3Anull
javax.validation.constraints.Null.message = \u5FC5\u987B\u4E3Anull
javax.validation.constraints.Past.message = \u9700\u8981\u662F\u4E00\u4E2A\u8FC7\u53BB\u7684\u65F6\u95F4
javax.validation.constraints.PastOrPresent.message = \u9700\u8981\u662F\u4E00\u4E2A\u8FC7\u53BB\u6216\u73B0\u5728\u7684\u65F6\u95F4
javax.validation.constraints.Pattern.message = \u9700\u8981\u5339\u914D\u6B63\u5219\u8868\u8FBE\u5F0F"{regexp}"
javax.validation.constraints.Positive.message = \u5FC5\u987B\u662F\u6B63\u6570
javax.validation.constraints.PositiveOrZero.message = \u5FC5\u987B\u662F\u6B63\u6570\u6216\u96F6
javax.validation.constraints.Size.message = \u4E2A\u6570\u5FC5\u987B\u5728{min}\u548C{max}\u4E4B\u95F4
org.hibernate.validator.constraints.CreditCardNumber.message = \u4E0D\u5408\u6CD5\u7684\u4FE1\u7528\u5361\u53F7\u7801
org.hibernate.validator.constraints.Currency.message = \u4E0D\u5408\u6CD5\u7684\u8D27\u5E01 (\u5FC5\u987B\u662F{value}\u5176\u4E2D\u4E4B\u4E00)
org.hibernate.validator.constraints.EAN.message = \u4E0D\u5408\u6CD5\u7684{type}\u6761\u5F62\u7801
org.hibernate.validator.constraints.Email.message = \u4E0D\u662F\u4E00\u4E2A\u5408\u6CD5\u7684\u7535\u5B50\u90AE\u4EF6\u5730\u5740
org.hibernate.validator.constraints.Length.message = \u957F\u5EA6\u9700\u8981\u5728{min}\u548C{max}\u4E4B\u95F4
org.hibernate.validator.constraints.CodePointLength.message = \u957F\u5EA6\u9700\u8981\u5728{min}\u548C{max}\u4E4B\u95F4
org.hibernate.validator.constraints.LuhnCheck.message = ${validatedValue}\u7684\u6821\u9A8C\u7801\u4E0D\u5408\u6CD5, Luhn\u6A2110\u6821\u9A8C\u548C\u4E0D\u5339\u914D
org.hibernate.validator.constraints.Mod10Check.message = ${validatedValue}\u7684\u6821\u9A8C\u7801\u4E0D\u5408\u6CD5, \u6A2110\u6821\u9A8C\u548C\u4E0D\u5339\u914D
org.hibernate.validator.constraints.Mod11Check.message = ${validatedValue}\u7684\u6821\u9A8C\u7801\u4E0D\u5408\u6CD5, \u6A2111\u6821\u9A8C\u548C\u4E0D\u5339\u914D
org.hibernate.validator.constraints.ModCheck.message = ${validatedValue}\u7684\u6821\u9A8C\u7801\u4E0D\u5408\u6CD5, {modType}\u6821\u9A8C\u548C\u4E0D\u5339\u914D
org.hibernate.validator.constraints.NotBlank.message = \u4E0D\u80FD\u4E3A\u7A7A
org.hibernate.validator.constraints.NotEmpty.message = \u4E0D\u80FD\u4E3A\u7A7A
org.hibernate.validator.constraints.ParametersScriptAssert.message = \u6267\u884C\u811A\u672C\u8868\u8FBE\u5F0F"{script}"\u6CA1\u6709\u8FD4\u56DE\u671F\u671B\u7ED3\u679C
org.hibernate.validator.constraints.Range.message = \u9700\u8981\u5728{min}\u548C{max}\u4E4B\u95F4
org.hibernate.validator.constraints.ScriptAssert.message = \u6267\u884C\u811A\u672C\u8868\u8FBE\u5F0F"{script}"\u6CA1\u6709\u8FD4\u56DE\u671F\u671B\u7ED3\u679C
org.hibernate.validator.constraints.URL.message = \u9700\u8981\u662F\u4E00\u4E2A\u5408\u6CD5\u7684URL
org.hibernate.validator.constraints.time.DurationMax.message = \u5FC5\u987B\u5C0F\u4E8E${inclusive == true ? '\u6216\u7B49\u4E8E' : ''}${days == 0 ? '' : days += '\u5929'}${hours == 0 ? '' : hours += '\u5C0F\u65F6'}${minutes == 0 ? '' : minutes += '\u5206\u949F'}${seconds == 0 ? '' : seconds += '\u79D2'}${millis == 0 ? '' : millis += '\u6BEB\u79D2'}${nanos == 0 ? '' : nanos += '\u7EB3\u79D2'}
org.hibernate.validator.constraints.time.DurationMin.message = \u5FC5\u987B\u5927\u4E8E${inclusive == true ? '\u6216\u7B49\u4E8E' : ''}${days == 0 ? '' : days += '\u5929'}${hours == 0 ? '' : hours += '\u5C0F\u65F6'}${minutes == 0 ? '' : minutes += '\u5206\u949F'}${seconds == 0 ? '' : seconds += '\u79D2'}${millis == 0 ? '' : millis += '\u6BEB\u79D2'}${nanos == 0 ? '' : nanos += '\u7EB3\u79D2'}

13
io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/autoconfigure/MvcWebMvcAutoConfiguration.java

@ -1,5 +1,6 @@
package io.sc.platform.mvc.autoconfigure; package io.sc.platform.mvc.autoconfigure;
import io.sc.platform.mvc.autoconfigure.support.RequestHeaderLocaleChangeInterceptor;
import io.sc.platform.mvc.plugins.PluginManager; import io.sc.platform.mvc.plugins.PluginManager;
import io.sc.platform.mvc.plugins.item.Resource; import io.sc.platform.mvc.plugins.item.Resource;
import org.hibernate.validator.HibernateValidator; import org.hibernate.validator.HibernateValidator;
@ -12,16 +13,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.validation.Validator; import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
@ -31,8 +24,6 @@ import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver; import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor; import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ -69,7 +60,7 @@ public class MvcWebMvcAutoConfiguration implements WebMvcConfigurer{
@Override @Override
public void addInterceptors(InterceptorRegistry registry) { public void addInterceptors(InterceptorRegistry registry) {
//区域拦截器 //区域拦截器
registry.addInterceptor(new LocaleChangeInterceptor()); registry.addInterceptor(new RequestHeaderLocaleChangeInterceptor());
//主题拦截器 //主题拦截器
registry.addInterceptor(new ThemeChangeInterceptor()); registry.addInterceptor(new ThemeChangeInterceptor());
} }

172
io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/autoconfigure/support/RequestHeaderLocaleChangeInterceptor.java

@ -0,0 +1,172 @@
package io.sc.platform.mvc.autoconfigure.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.support.RequestContextUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
public class RequestHeaderLocaleChangeInterceptor implements HandlerInterceptor {
/**
* Default name of the locale specification parameter: "locale".
*/
public static final String DEFAULT_PARAM_NAME = "locale";
protected final Log logger = LogFactory.getLog(getClass());
private String paramName = DEFAULT_PARAM_NAME;
@Nullable
private String[] httpMethods;
private boolean ignoreInvalidLocale = false;
/**
* Set the name of the parameter that contains a locale specification
* in a locale change request. Default is "locale".
*/
public void setParamName(String paramName) {
this.paramName = paramName;
}
/**
* Return the name of the parameter that contains a locale specification
* in a locale change request.
*/
public String getParamName() {
return this.paramName;
}
/**
* Configure the HTTP method(s) over which the locale can be changed.
* @param httpMethods the methods
* @since 4.2
*/
public void setHttpMethods(@Nullable String... httpMethods) {
this.httpMethods = httpMethods;
}
/**
* Return the configured HTTP methods.
* @since 4.2
*/
@Nullable
public String[] getHttpMethods() {
return this.httpMethods;
}
/**
* Set whether to ignore an invalid value for the locale parameter.
* @since 4.2.2
*/
public void setIgnoreInvalidLocale(boolean ignoreInvalidLocale) {
this.ignoreInvalidLocale = ignoreInvalidLocale;
}
/**
* Return whether to ignore an invalid value for the locale parameter.
* @since 4.2.2
*/
public boolean isIgnoreInvalidLocale() {
return this.ignoreInvalidLocale;
}
/**
* Specify whether to parse request parameter values as BCP 47 language tags
* instead of Java's legacy locale specification format.
* <p><b>NOTE: As of 5.1, this resolver leniently accepts the legacy
* {@link Locale#toString} format as well as BCP 47 language tags.</b>
* @since 4.3
* @see Locale#forLanguageTag(String)
* @see Locale#toLanguageTag()
* @deprecated as of 5.1 since it only accepts {@code true} now
*/
@Deprecated
public void setLanguageTagCompliant(boolean languageTagCompliant) {
if (!languageTagCompliant) {
throw new IllegalArgumentException("LocaleChangeInterceptor always accepts BCP 47 language tags");
}
}
/**
* Return whether to use BCP 47 language tags instead of Java's legacy
* locale specification format.
* @since 4.3
* @deprecated as of 5.1 since it always returns {@code true} now
*/
@Deprecated
public boolean isLanguageTagCompliant() {
return true;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws ServletException {
String newLocale = request.getHeader("locale");
if(!StringUtils.hasText(newLocale)){
newLocale =request.getParameter(getParamName());
}
if (newLocale != null) {
if (checkHttpMethod(request.getMethod())) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver == null) {
throw new IllegalStateException(
"No LocaleResolver found: not in a DispatcherServlet request?");
}
try {
localeResolver.setLocale(request, response, parseLocaleValue(newLocale));
}
catch (IllegalArgumentException ex) {
if (isIgnoreInvalidLocale()) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring invalid locale value [" + newLocale + "]: " + ex.getMessage());
}
}
else {
throw ex;
}
}
}
}
// Proceed in any case.
return true;
}
private boolean checkHttpMethod(String currentMethod) {
String[] configuredMethods = getHttpMethods();
if (ObjectUtils.isEmpty(configuredMethods)) {
return true;
}
for (String configuredMethod : configuredMethods) {
if (configuredMethod.equalsIgnoreCase(currentMethod)) {
return true;
}
}
return false;
}
/**
* Parse the given locale value as coming from a request parameter.
* <p>The default implementation calls {@link StringUtils#parseLocale(String)},
* accepting the {@link Locale#toString} format as well as BCP 47 language tags.
* @param localeValue the locale value to parse
* @return the corresponding {@code Locale} instance
* @since 4.3
*/
@Nullable
protected Locale parseLocaleValue(String localeValue) {
return StringUtils.parseLocale(localeValue);
}
}

33
io.sc.platform.mvc/src/main/java/io/sc/platform/mvc/controller/support/RestCrudController.java

@ -3,7 +3,7 @@ package io.sc.platform.mvc.controller.support;
import io.sc.platform.core.annotation.AuditLog; import io.sc.platform.core.annotation.AuditLog;
import io.sc.platform.core.audit.AuditLogAction; import io.sc.platform.core.audit.AuditLogAction;
import io.sc.platform.core.response.ValidateException; import io.sc.platform.core.response.ValidateException;
import io.sc.platform.core.response.ValidationError; import io.sc.platform.core.util.ValidatorUtil;
import io.sc.platform.orm.api.vo.BaseVo; import io.sc.platform.orm.api.vo.BaseVo;
import io.sc.platform.orm.entity.BaseEntity; import io.sc.platform.orm.entity.BaseEntity;
import io.sc.platform.orm.repository.DaoRepository; import io.sc.platform.orm.repository.DaoRepository;
@ -14,7 +14,6 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageImpl;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -31,7 +30,7 @@ public abstract class RestCrudController<V extends BaseVo, E extends BaseEntity<
@PostMapping("") @PostMapping("")
@ResponseBody @ResponseBody
public V _add(HttpServletRequest request,HttpServletResponse response,@RequestBody @Valid E entity,BindingResult bindingResult) throws Exception{ public V _add(HttpServletRequest request,HttpServletResponse response,@RequestBody @Valid E entity,BindingResult bindingResult) throws Exception{
ValidateException result =validationError(bindingResult); ValidateException result = ValidatorUtil.validate(bindingResult);
if(result!=null){ if(result!=null){
throw result; throw result;
} }
@ -61,7 +60,7 @@ public abstract class RestCrudController<V extends BaseVo, E extends BaseEntity<
@PutMapping("{id}") @PutMapping("{id}")
@ResponseBody @ResponseBody
public V _update(HttpServletRequest request,HttpServletResponse response,@PathVariable(name="id")ID id,@RequestBody @Valid E entity,BindingResult bindingResult) throws Exception{ public V _update(HttpServletRequest request,HttpServletResponse response,@PathVariable(name="id")ID id,@RequestBody @Valid E entity,BindingResult bindingResult) throws Exception{
ValidateException result =validationError(bindingResult); ValidateException result =ValidatorUtil.validate(bindingResult);
if(result!=null){ if(result!=null){
throw result; throw result;
} }
@ -113,32 +112,6 @@ public abstract class RestCrudController<V extends BaseVo, E extends BaseEntity<
return new PageImpl<>(vos,page.getPageable(),page.getTotalElements()); return new PageImpl<>(vos,page.getPageable(),page.getTotalElements());
} }
private ValidateException validationError(BindingResult bindingResult) {
if(bindingResult==null || !bindingResult.hasErrors()){
return null;
}
List<FieldError> errors =bindingResult.getFieldErrors();
if(errors==null || errors.size()==0){
return null;
}
List<ValidationError> errorList =new ArrayList<ValidationError>();
for(FieldError error : errors){
errorList.add(new ValidationError(getFieldName(error.getField()),error.getDefaultMessage()));
}
return new ValidateException(errorList);
}
private String getFieldName(String field){
int index =field.lastIndexOf(".");
if(index>-1){
return field.substring(index+1);
}else{
return field;
}
}
/* /*
@AuditLog(AuditLogAction.ADD) @AuditLog(AuditLogAction.ADD)
@PostMapping("") @PostMapping("")

2
io.sc.platform.mvc/src/main/resources/META-INF/platform/plugins/application-properties.json

@ -78,7 +78,7 @@
"spring.messages.cacheDuration = -1", "spring.messages.cacheDuration = -1",
"spring.messages.encoding = UTF-8", "spring.messages.encoding = UTF-8",
"spring.messages.fallbackToSystemLocale = false", "spring.messages.fallbackToSystemLocale = false",
"spring.messages.useCodeAsDefaultMessage = true" "spring.messages.useCodeAsDefaultMessage = false"
] ]
} }
] ]

19
io.sc.platform.security.oauth2.server.authorization/src/main/java/io/sc/platform/security/oauth2/server/authorization/configure/PlatformWebSecurityAutoConfiguration.java

@ -2,7 +2,7 @@ package io.sc.platform.security.oauth2.server.authorization.configure;
import io.sc.platform.core.service.RuntimeService; import io.sc.platform.core.service.RuntimeService;
import io.sc.platform.security.oauth2.server.authorization.configure.support.PlatformSecurityProperties; import io.sc.platform.security.SecurityProperties;
import io.sc.platform.security.service.SecurityConfigureService; import io.sc.platform.security.service.SecurityConfigureService;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -11,7 +11,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
@ -20,18 +19,18 @@ import org.springframework.security.web.SecurityFilterChain;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 200) @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 200)
@EnableConfigurationProperties(PlatformSecurityProperties.class) @EnableConfigurationProperties(SecurityProperties.class)
public class PlatformWebSecurityAutoConfiguration { public class PlatformWebSecurityAutoConfiguration {
private static final Logger log = LoggerFactory.getLogger(PlatformWebSecurityAutoConfiguration.class); private static final Logger log = LoggerFactory.getLogger(PlatformWebSecurityAutoConfiguration.class);
private RuntimeService runtimeService; private RuntimeService runtimeService;
private SecurityConfigureService securityConfigureService; private SecurityConfigureService securityConfigureService;
private PlatformSecurityProperties platformSecurityProperties; private SecurityProperties securityProperties;
public PlatformWebSecurityAutoConfiguration(RuntimeService runtimeService, SecurityConfigureService securityConfigureService, PlatformSecurityProperties platformSecurityProperties){ public PlatformWebSecurityAutoConfiguration(RuntimeService runtimeService, SecurityConfigureService securityConfigureService, SecurityProperties securityProperties){
this.runtimeService =runtimeService; this.runtimeService =runtimeService;
this.securityConfigureService =securityConfigureService; this.securityConfigureService =securityConfigureService;
this.platformSecurityProperties =platformSecurityProperties; this.securityProperties =securityProperties;
} }
@Bean @Bean
@ -54,14 +53,14 @@ public class PlatformWebSecurityAutoConfiguration {
corsConfigurer.configurationSource(securityConfigureService.getCorsConfigurationSource()); corsConfigurer.configurationSource(securityConfigureService.getCorsConfigurationSource());
}) })
.formLogin(formLoginConfigurer -> { .formLogin(formLoginConfigurer -> {
PlatformSecurityProperties.FormLogin formLogin =platformSecurityProperties.getFormLogin(); SecurityProperties.FormLogin formLogin =securityProperties.getFormLogin();
formLoginConfigurer.loginPage(formLogin.getLoginPage()).permitAll(); formLoginConfigurer.loginPage(formLogin.getLoginPage()).permitAll();
formLoginConfigurer.loginProcessingUrl(formLogin.getLoginProcessingUrl()).permitAll(); formLoginConfigurer.loginProcessingUrl(formLogin.getLoginProcessingUrl()).permitAll();
formLoginConfigurer.failureUrl(platformSecurityProperties.getFormLogin().getFailureUrl()).permitAll(); formLoginConfigurer.failureUrl(securityProperties.getFormLogin().getFailureUrl()).permitAll();
}) })
.logout(logoutConfigurer -> { .logout(logoutConfigurer -> {
logoutConfigurer.logoutUrl(platformSecurityProperties.getLogout().getLogoutUrl()); logoutConfigurer.logoutUrl(securityProperties.getLogout().getLogoutUrl());
logoutConfigurer.logoutSuccessUrl(platformSecurityProperties.getLogout().getLogoutSuccessUrl()); logoutConfigurer.logoutSuccessUrl(securityProperties.getLogout().getLogoutSuccessUrl());
}) })
.headers(headersConfigurer -> { .headers(headersConfigurer -> {
headersConfigurer.frameOptions().disable(); headersConfigurer.frameOptions().disable();

31
io.sc.platform.system/src/main/java/io/sc/platform/system/user/controller/UserWebController.java

@ -1,5 +1,7 @@
package io.sc.platform.system.user.controller; package io.sc.platform.system.user.controller;
import io.sc.platform.core.response.ValidateException;
import io.sc.platform.core.util.ValidatorUtil;
import io.sc.platform.mvc.controller.support.RestCrudController; import io.sc.platform.mvc.controller.support.RestCrudController;
import io.sc.platform.mvc.support.One2Many; import io.sc.platform.mvc.support.One2Many;
import io.sc.platform.orm.api.exception.UserNewPasswordAndConfirmNewPasswordNotMatchException; import io.sc.platform.orm.api.exception.UserNewPasswordAndConfirmNewPasswordNotMatchException;
@ -12,13 +14,18 @@ import io.sc.platform.system.api.user.UserVo;
import io.sc.platform.system.user.jpa.entity.UserEntity; import io.sc.platform.system.user.jpa.entity.UserEntity;
import io.sc.platform.system.user.jpa.repository.UserRepository; import io.sc.platform.system.user.jpa.repository.UserRepository;
import io.sc.platform.system.user.service.UserService; import io.sc.platform.system.user.service.UserService;
import io.sc.platform.system.user.service.support.ChangePassword;
import io.sc.platform.system.user.service.support.SetUserPasswordWrapper; import io.sc.platform.system.user.service.support.SetUserPasswordWrapper;
import io.sc.platform.system.user.service.support.UserSession; import io.sc.platform.system.user.service.support.UserSession;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintValidator;
import javax.validation.Valid;
import java.security.Principal; import java.security.Principal;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -72,29 +79,15 @@ public class UserWebController extends RestCrudController<UserVo, UserEntity, St
/** /**
* 修改当前登录用户的登录密码 * 修改当前登录用户的登录密码
* @param parameters 密码参数 Map包括原始密码新密码 * @param changePassword 密码参数对象包括原始密码新密码
* @param principal 当前登录用户的登录凭证信息对象 * @param principal 当前登录用户的登录凭证信息对象
* @throws Exception 违例 * @throws Exception 违例
*/ */
@PostMapping("changePassword") @PostMapping("changePassword")
public void changePassword(@RequestBody Map<String,String> parameters, Principal principal) throws Exception{ public void changePassword(@RequestBody @Valid ChangePassword changePassword, BindingResult bindingResult, Principal principal) throws Exception{
if(parameters!=null && parameters.size()>0){ ValidatorUtil.validate(bindingResult);
String rawPassword =parameters.get("rawPassword"); if(changePassword!=null){
String newPassword =parameters.get("newPassword"); service.changPassword(principal.getName(),changePassword.getRawPassword(),changePassword.getNewPassword());
String confirmNewPassword =parameters.get("confirmNewPassword");
if(!StringUtils.hasText(rawPassword)){
throw new UserRawPasswordEmptyException();
}
if(!StringUtils.hasText(newPassword)){
throw new UserNewPasswordEmptyException();
}
if(!newPassword.equals(confirmNewPassword)){
throw new UserNewPasswordAndConfirmNewPasswordNotMatchException();
}
service.changPassword(principal.getName(),rawPassword,newPassword);
} }
} }

40
io.sc.platform.system/src/main/java/io/sc/platform/system/user/service/support/ChangePassword.java

@ -0,0 +1,40 @@
package io.sc.platform.system.user.service.support;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
public class ChangePassword {
@NotEmpty
@Size(min = 1,max = 4)
private String rawPassword;
@NotEmpty
private String newPassword;
@NotEmpty
private String confirmNewPassword;
public String getRawPassword() {
return rawPassword;
}
public void setRawPassword(String rawPassword) {
this.rawPassword = rawPassword;
}
public String getNewPassword() {
return newPassword;
}
public void setNewPassword(String newPassword) {
this.newPassword = newPassword;
}
public String getConfirmNewPassword() {
return confirmNewPassword;
}
public void setConfirmNewPassword(String confirmNewPassword) {
this.confirmNewPassword = confirmNewPassword;
}
}
Loading…
Cancel
Save