From 26a293ea9409034ec8ab9728d63fd68955e4c941 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Wed, 30 Jul 2025 20:56:12 +0800 Subject: [PATCH 01/25] =?UTF-8?q?[fit]=20=E5=AE=9E=E7=8E=B0=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E5=9C=B0=E5=8C=BA=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/util/i18n/DefualtLocaleResolver.java | 82 +++++++++++++++++++ .../fit/http/util/i18n/LocaleContext.java | 27 ++++++ .../http/util/i18n/LocaleContextHolder.java | 45 ++++++++++ .../http/util/i18n/LocaleResolveFilter.java | 77 +++++++++++++++++ .../fit/http/util/i18n/LocaleResolver.java | 36 ++++++++ 5 files changed, 267 insertions(+) create mode 100644 framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java create mode 100644 framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContext.java create mode 100644 framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContextHolder.java create mode 100644 framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java create mode 100644 framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java new file mode 100644 index 000000000..bd1f9d599 --- /dev/null +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -0,0 +1,82 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +package modelengine.fit.http.util.i18n; + +import modelengine.fit.http.Cookie; +import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.http.server.HttpClassicServerResponse; + +import java.util.Locale; + + +public class DefualtLocaleResolver implements LocaleResolver{ + + public static final String DEFAULT_COOKIE_NAME = "locale"; + public static final int DEFAULT_COOKIE_MAX_AGE = 60 * 60 * 24 * 365; + public static final String DEFAULT_COOKIE_DOMAIN = "/"; + public static final String DEFAULT_COOKIE_PATH = "/"; + private String cookieName = DEFAULT_COOKIE_NAME; + private int cookieMaxAge = DEFAULT_COOKIE_MAX_AGE; + private String cookieDomain = DEFAULT_COOKIE_DOMAIN; + private String cookiePath = DEFAULT_COOKIE_PATH; + private Locale defaultLocale; + + @Override + public Locale resolveLocale(HttpClassicServerRequest request) { + // 先解析 Cookie,如果没有则使用 Accept-Language 头 + String newLocale = request.cookies().get(this.cookieName).map(Cookie::value).orElse(null); + if(newLocale != null){ + return Locale.forLanguageTag(newLocale); + } + + String acceptLanguage = request.headers().require("Accept-Language"); + if (acceptLanguage != null && !acceptLanguage.trim().isEmpty()) { + return Locale.forLanguageTag(acceptLanguage); + } + + return defaultLocale; + } + + @Override + public void setLocale(HttpClassicServerResponse response, Locale locale) { + + if(locale != null){ + response.cookies().add(Cookie.builder() + .name(cookieName) + .value(locale.toLanguageTag()) + .maxAge(cookieMaxAge) + .domain(cookieDomain) + .path(cookiePath) + .build()); + }else{ + response.cookies().add(Cookie.builder() + .name(cookieName) + .maxAge(0) + .build()); + } + } + + public void setCookieName(String cookieName) { + this.cookieName = cookieName; + } + + public void setCookieMaxAge(int cookieMaxAge) { + this.cookieMaxAge = cookieMaxAge; + } + + public void setCookieDomain(String cookieDomain) { + this.cookieDomain = cookieDomain; + } + + public void setCookiePath(String cookiePath) { + this.cookiePath = cookiePath; + } + + public void setDefaultLocale(Locale defaultLocale) { + this.defaultLocale = defaultLocale; + } + +} diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContext.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContext.java new file mode 100644 index 000000000..b1cbd0659 --- /dev/null +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContext.java @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fit.http.util.i18n; + +import java.util.Locale; + +/** + * 地区上下文,包含地区信息 + * + * @author fit-framework + * @since 2025-01-01 + */ +public class LocaleContext { + private final Locale locale; + + public LocaleContext(Locale locale) { + this.locale = locale; + } + + public Locale getLocale() { + return locale; + } +} diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContextHolder.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContextHolder.java new file mode 100644 index 000000000..ea50341d2 --- /dev/null +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContextHolder.java @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fit.http.util.i18n; + +import java.util.Locale; + + +public class LocaleContextHolder { + + private static final ThreadLocal LOCALE_CONTEXT_HOLDER = new ThreadLocal<>(); + + /** + * 设置当前线程的地区上下文 + */ + public static void setLocaleContext(LocaleContext localeContext) { + LOCALE_CONTEXT_HOLDER.set(localeContext); + } + + /** + * 获取当前线程的地区上下文 + */ + public static LocaleContext getLocaleContext() { + return LOCALE_CONTEXT_HOLDER.get(); + } + + /** + * 获取当前线程的地区 + */ + public static Locale getLocale() { + LocaleContext context = getLocaleContext(); + return context != null ? context.getLocale() : Locale.getDefault(); + } + + + /** + * 清除当前线程的地区上下文 + */ + public static void clear() { + LOCALE_CONTEXT_HOLDER.remove(); + } +} diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java new file mode 100644 index 000000000..533ab0873 --- /dev/null +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -0,0 +1,77 @@ +package modelengine.fit.http.util.i18n; + +import modelengine.fit.http.server.*; +import modelengine.fitframework.annotation.Scope; + +import java.util.List; +import java.util.Locale; + +public class LocaleResolveFilter implements HttpServerFilter { + + private LocaleResolver localeResolver = null; + + private List matchPatterns = List.of("/**"); + + private List mismatchPatterns = null; + + private Scope scope = Scope.GLOBAL; + + public LocaleResolveFilter(LocaleResolver localeResolver) { + localeResolver = localeResolver; + } + + public LocaleResolveFilter(){ + this.localeResolver = new DefualtLocaleResolver(); + } + + @Override + public String name() { + return "LocaleResolveFilter"; + } + + @Override + public int priority() { + return 0; + } + + @Override + public List matchPatterns() { + return matchPatterns; + } + + @Override + public List mismatchPatterns() { + return mismatchPatterns; + } + + @Override + public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, HttpServerFilterChain chain) throws DoHttpServerFilterException { + try { + // 如果参数中带有地区,则直接设置地区 + String paramLocale = request.queries().first("locale").orElse( null); + Locale responseLocale = null; + if(paramLocale != null && !paramLocale.trim().isEmpty()){ + responseLocale = Locale.forLanguageTag(paramLocale); + LocaleContextHolder.setLocaleContext(new LocaleContext(responseLocale)); + } + // 如果参数中不包含地区,则解析 + else{ + Locale locale =localeResolver.resolveLocale(request); + LocaleContextHolder.setLocaleContext(new LocaleContext(locale)); + } + + chain.doFilter(request, response); + + // responseLocale是用户期望设置的地区,不受 server 端处理的影响 + localeResolver.setLocale(response, responseLocale); + }finally { + LocaleContextHolder.clear(); + } + + } + + @Override + public Scope scope() { + return scope; + } +} diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java new file mode 100644 index 000000000..669915444 --- /dev/null +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +package modelengine.fit.http.util.i18n; + +import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.http.server.HttpClassicServerResponse; + +import java.util.Locale; + +/** + * 地区解析器接口,用于从HTTP请求中解析用户的地区设置 + * + * @author fit-framework + * @since 2025-01-01 + */ +public interface LocaleResolver { + + /** + * 解析用户的地区设置 + * + * @param request HTTP请求 {@link HttpClassicServerRequest}。 + * @return 解析出来的地区 {@link Locale}。 + */ + Locale resolveLocale(HttpClassicServerRequest request); + + /** + * 设置地区到响应中 + * + * @param response HTTP响应 {@link HttpClassicServerResponse}。 + * @param locale 要设置的地区 {@link Locale}。 + */ + void setLocale(HttpClassicServerResponse response, Locale locale); +} From 21fe2486181e0c8c460da6874baaa3cac7cf3cad Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Fri, 1 Aug 2025 12:32:34 +0800 Subject: [PATCH 02/25] =?UTF-8?q?[fit]=20=E5=AE=9E=E7=8E=B0=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96=E6=B6=88=E6=81=AF=E5=A4=84=E7=90=86=E5=99=A8?= =?UTF-8?q?=EF=BC=8C=E5=AE=8C=E5=96=84=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LocaleContextMessageInterpolator.java | 47 ++++++ .../LocaleValidationController.java | 28 ++++ .../LocaleValidationControllerTest.java | 149 ++++++++++++++++++ .../validation/data/localeResolveConfig.java | 13 ++ .../LocaleContextMessageInterpolator.java | 47 ++++++ .../LocaleValidationController.java | 36 +++++ .../LocaleValidationControllerTest.java | 149 ++++++++++++++++++ .../validation/data/localeResolveConfig.java | 13 ++ .../http/util/i18n/DefualtLocaleResolver.java | 12 +- .../http/util/i18n/LocaleResolveFilter.java | 4 +- .../fitframework/util}/LocaleContext.java | 10 +- .../util}/LocaleContextHolder.java | 2 +- 12 files changed, 496 insertions(+), 14 deletions(-) create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java rename framework/fit/java/{fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n => fit-util/src/main/java/modelengine/fitframework/util}/LocaleContext.java (82%) rename framework/fit/java/{fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n => fit-util/src/main/java/modelengine/fitframework/util}/LocaleContextHolder.java (97%) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java new file mode 100644 index 000000000..d5dd002c7 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import modelengine.fitframework.util.LocaleContextHolder; + +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; + +import jakarta.validation.MessageInterpolator; + +import java.util.Locale; + +/** + * 检验消息处理包装类。 + *

+ * 从 {@link LocaleContextHolder} 中获取当前线程设置的 {@link Locale} 并委托 {@link MessageInterpolator} 去处理消息。 + *

+ * + * @author 阮睿 + * @since 2025-07-31 + */ +public class LocaleContextMessageInterpolator implements MessageInterpolator { + + private final MessageInterpolator targetInterpolator; + + public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) { + this.targetInterpolator = targetInterpolator; + } + + public LocaleContextMessageInterpolator() { + this.targetInterpolator = new ParameterMessageInterpolator(); + } + + @Override + public String interpolate(String messageTemplate, Context context) { + return this.targetInterpolator.interpolate(messageTemplate, context, LocaleContextHolder.getLocale()); + } + + @Override + public String interpolate(String messageTemplate, Context context, Locale locale) { + return this.targetInterpolator.interpolate(messageTemplate, context, locale); + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java new file mode 100644 index 000000000..9e312be50 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java @@ -0,0 +1,28 @@ +package modelengine.fitframework.validation; + +import modelengine.fit.http.annotation.PostMapping; +import modelengine.fit.http.annotation.RequestBody; +import modelengine.fit.http.annotation.RequestMapping; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.validation.data.Company; + +import jakarta.validation.Valid; + +/** + * 地区验证控制器 - 测试ValidationHandler与LocaleContextMessageInterpolator的集成 + * + * @author 阮睿 + * @since 2025-01-27 + */ +@Component +@RequestMapping(path = "/validation/locale", group = "地区验证测试接口") +@Validated +public class LocaleValidationController { + + /** + * 测试验证消息的地区化 - 使用简单参数 + */ + @PostMapping(path = "/simple", description = "测试简单参数的地区化验证消息") + public void validateSimpleParam(@RequestBody @Valid Company company) {} + +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java new file mode 100644 index 000000000..abbb2ade4 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -0,0 +1,149 @@ +package modelengine.fitframework.validation; + +import modelengine.fit.http.client.HttpClassicClientResponse; +import modelengine.fit.http.entity.Entity; +import modelengine.fit.http.entity.ObjectEntity; +import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.test.annotation.MvcTest; +import modelengine.fitframework.test.domain.mvc.MockMvc; +import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; +import modelengine.fitframework.test.domain.mvc.request.MockRequestBuilder; +import modelengine.fitframework.validation.data.Company; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * {@link LocaleValidationController} 的测试集。 + * + * @author 阮睿 + * @since 2025-07-18 + */ +@MvcTest(classes = {LocaleValidationController.class}) +@DisplayName("测试地区化验证消息功能") +public class LocaleValidationControllerTest { + + @Fit + private MockMvc mockMvc; + + private HttpClassicClientResponse response; + + @AfterEach + void teardown() throws IOException { + if (this.response != null) { + this.response.close(); + } + } + + @Test + @DisplayName("测试法文地区的验证消息") + void shouldReturnChineseValidationMessage() { + Company invalidCompany = new Company(null); + + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/locale/simple") + .header("Accept-Language", "fr") + .jsonEntity(invalidCompany) + .responseType(Map.class); + + this.response = this.mockMvc.perform(requestBuilder); + // 获取JSON格式的错误信息 + String errorMessage = ""; + if (this.response.entity().isPresent()) { + Entity entity = this.response.entity().get(); + if (entity instanceof ObjectEntity) { + ObjectEntity objectEntity = (ObjectEntity) entity; + Object errorObj = objectEntity.object(); + if (errorObj instanceof Map) { + Map errorMap = (Map) errorObj; + errorMessage = + errorMap.get("error") != null ? errorMap.get("error").toString() : errorMap.toString(); + } else { + errorMessage = errorObj.toString(); + } + } + } + + assertThat(errorMessage).isEqualTo("validateSimpleParam.company.employees: ne doit pas être nul"); + assertThat(this.response.statusCode()).isEqualTo(500); + } + + @Test + @DisplayName("测试英文地区的验证消息") + void shouldReturnEnglishValidationMessage() { + Company invalidCompany = new Company(null); + + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/locale/simple") + .header("Accept-Language", "en-us") + .jsonEntity(invalidCompany) + .responseType(Map.class); + + this.response = this.mockMvc.perform(requestBuilder); + // 获取JSON格式的错误信息 + String errorMessage = ""; + if (this.response.entity().isPresent()) { + Entity entity = this.response.entity().get(); + if (entity instanceof ObjectEntity) { + ObjectEntity objectEntity = (ObjectEntity) entity; + Object errorObj = objectEntity.object(); + if (errorObj instanceof Map) { + Map errorMap = (Map) errorObj; + errorMessage = + errorMap.get("error") != null ? errorMap.get("error").toString() : errorMap.toString(); + } else { + errorMessage = errorObj.toString(); + } + } + } + + assertThat(errorMessage).isEqualTo("validateSimpleParam.company.employees: must not be null"); + assertThat(this.response.statusCode()).isEqualTo(500); + } + + @Test + @DisplayName("测试URL参数指定地区") + void shouldUseLocaleFromUrlParam() { + Company invalidCompany = new Company(null); + + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/locale/simple") + .param("locale", "en-US") + .jsonEntity(invalidCompany) + .responseType(Map.class); + + this.response = this.mockMvc.perform(requestBuilder); + + // 获取JSON格式的错误信息 + String errorMessage = ""; + if (this.response.entity().isPresent()) { + Entity entity = this.response.entity().get(); + if (entity instanceof ObjectEntity) { + ObjectEntity objectEntity = (ObjectEntity) entity; + Object errorObj = objectEntity.object(); + if (errorObj instanceof Map) { + Map errorMap = (Map) errorObj; + errorMessage = + errorMap.get("error") != null ? errorMap.get("error").toString() : errorMap.toString(); + } else { + errorMessage = errorObj.toString(); + } + } + } + + assertThat(errorMessage).isEqualTo("validateSimpleParam.company.employees: must not be null"); + assertThat(this.response.cookies().get("locale").isPresent()); + assertThat(this.response.cookies().get("locale").get().value()).isEqualTo("en-US"); + assertThat(this.response.statusCode()).isEqualTo(500); + } +} + + + + + + + diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java new file mode 100644 index 000000000..39a40bc13 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java @@ -0,0 +1,13 @@ +package modelengine.fitframework.validation.data; + +import modelengine.fit.http.util.i18n.LocaleResolveFilter; +import modelengine.fitframework.annotation.Bean; +import modelengine.fitframework.annotation.Component; + +@Component +public class localeResolveConfig { + @Bean + public LocaleResolveFilter localeResolveFilter() { + return new LocaleResolveFilter(); + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java new file mode 100644 index 000000000..b2c7263f0 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.validation; + +import modelengine.fitframework.util.LocaleContextHolder; + +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; + +import javax.validation.MessageInterpolator; + +import java.util.Locale; + +/** + * 检验消息处理包装类。 + *

+ * 从 {@link LocaleContextHolder} 中获取当前线程设置的 {@link Locale} 并委托 {@link MessageInterpolator} 去处理消息。 + *

+ * + * @author 阮睿 + * @since 2025-07-31 + */ +public class LocaleContextMessageInterpolator implements MessageInterpolator { + + private final MessageInterpolator targetInterpolator; + + public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) { + this.targetInterpolator = targetInterpolator; + } + + public LocaleContextMessageInterpolator() { + this.targetInterpolator = new ParameterMessageInterpolator(); + } + + @Override + public String interpolate(String messageTemplate, Context context) { + return this.targetInterpolator.interpolate(messageTemplate, context, LocaleContextHolder.getLocale()); + } + + @Override + public String interpolate(String messageTemplate, Context context, Locale locale) { + return this.targetInterpolator.interpolate(messageTemplate, context, locale); + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java new file mode 100644 index 000000000..8d2dce0ac --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java @@ -0,0 +1,36 @@ +package modelengine.fitframework.validation; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Min; + +import modelengine.fit.http.util.i18n.LocaleResolveFilter; +import modelengine.fitframework.annotation.Bean; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.util.LocaleContextHolder; +import modelengine.fitframework.validation.data.Company; +import modelengine.fitframework.validation.data.Employee; +import modelengine.fit.http.annotation.PostMapping; +import modelengine.fit.http.annotation.RequestBody; +import modelengine.fit.http.annotation.RequestMapping; + +import java.util.Locale; + +/** + * 地区验证控制器 - 测试ValidationHandler与LocaleContextMessageInterpolator的集成 + * + * @author 阮睿 + * @since 2025-01-27 + */ +@Component +@RequestMapping(path = "/validation/locale", group = "地区验证测试接口") +@Validated +public class LocaleValidationController { + + /** + * 测试验证消息的地区化 - 使用简单参数 + */ + @PostMapping(path = "/simple", description = "测试简单参数的地区化验证消息") + public void validateSimpleParam(@RequestBody @Valid Company company) {} + +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java new file mode 100644 index 000000000..abbb2ade4 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -0,0 +1,149 @@ +package modelengine.fitframework.validation; + +import modelengine.fit.http.client.HttpClassicClientResponse; +import modelengine.fit.http.entity.Entity; +import modelengine.fit.http.entity.ObjectEntity; +import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.test.annotation.MvcTest; +import modelengine.fitframework.test.domain.mvc.MockMvc; +import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; +import modelengine.fitframework.test.domain.mvc.request.MockRequestBuilder; +import modelengine.fitframework.validation.data.Company; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * {@link LocaleValidationController} 的测试集。 + * + * @author 阮睿 + * @since 2025-07-18 + */ +@MvcTest(classes = {LocaleValidationController.class}) +@DisplayName("测试地区化验证消息功能") +public class LocaleValidationControllerTest { + + @Fit + private MockMvc mockMvc; + + private HttpClassicClientResponse response; + + @AfterEach + void teardown() throws IOException { + if (this.response != null) { + this.response.close(); + } + } + + @Test + @DisplayName("测试法文地区的验证消息") + void shouldReturnChineseValidationMessage() { + Company invalidCompany = new Company(null); + + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/locale/simple") + .header("Accept-Language", "fr") + .jsonEntity(invalidCompany) + .responseType(Map.class); + + this.response = this.mockMvc.perform(requestBuilder); + // 获取JSON格式的错误信息 + String errorMessage = ""; + if (this.response.entity().isPresent()) { + Entity entity = this.response.entity().get(); + if (entity instanceof ObjectEntity) { + ObjectEntity objectEntity = (ObjectEntity) entity; + Object errorObj = objectEntity.object(); + if (errorObj instanceof Map) { + Map errorMap = (Map) errorObj; + errorMessage = + errorMap.get("error") != null ? errorMap.get("error").toString() : errorMap.toString(); + } else { + errorMessage = errorObj.toString(); + } + } + } + + assertThat(errorMessage).isEqualTo("validateSimpleParam.company.employees: ne doit pas être nul"); + assertThat(this.response.statusCode()).isEqualTo(500); + } + + @Test + @DisplayName("测试英文地区的验证消息") + void shouldReturnEnglishValidationMessage() { + Company invalidCompany = new Company(null); + + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/locale/simple") + .header("Accept-Language", "en-us") + .jsonEntity(invalidCompany) + .responseType(Map.class); + + this.response = this.mockMvc.perform(requestBuilder); + // 获取JSON格式的错误信息 + String errorMessage = ""; + if (this.response.entity().isPresent()) { + Entity entity = this.response.entity().get(); + if (entity instanceof ObjectEntity) { + ObjectEntity objectEntity = (ObjectEntity) entity; + Object errorObj = objectEntity.object(); + if (errorObj instanceof Map) { + Map errorMap = (Map) errorObj; + errorMessage = + errorMap.get("error") != null ? errorMap.get("error").toString() : errorMap.toString(); + } else { + errorMessage = errorObj.toString(); + } + } + } + + assertThat(errorMessage).isEqualTo("validateSimpleParam.company.employees: must not be null"); + assertThat(this.response.statusCode()).isEqualTo(500); + } + + @Test + @DisplayName("测试URL参数指定地区") + void shouldUseLocaleFromUrlParam() { + Company invalidCompany = new Company(null); + + MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/locale/simple") + .param("locale", "en-US") + .jsonEntity(invalidCompany) + .responseType(Map.class); + + this.response = this.mockMvc.perform(requestBuilder); + + // 获取JSON格式的错误信息 + String errorMessage = ""; + if (this.response.entity().isPresent()) { + Entity entity = this.response.entity().get(); + if (entity instanceof ObjectEntity) { + ObjectEntity objectEntity = (ObjectEntity) entity; + Object errorObj = objectEntity.object(); + if (errorObj instanceof Map) { + Map errorMap = (Map) errorObj; + errorMessage = + errorMap.get("error") != null ? errorMap.get("error").toString() : errorMap.toString(); + } else { + errorMessage = errorObj.toString(); + } + } + } + + assertThat(errorMessage).isEqualTo("validateSimpleParam.company.employees: must not be null"); + assertThat(this.response.cookies().get("locale").isPresent()); + assertThat(this.response.cookies().get("locale").get().value()).isEqualTo("en-US"); + assertThat(this.response.statusCode()).isEqualTo(500); + } +} + + + + + + + diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java new file mode 100644 index 000000000..39a40bc13 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java @@ -0,0 +1,13 @@ +package modelengine.fitframework.validation.data; + +import modelengine.fit.http.util.i18n.LocaleResolveFilter; +import modelengine.fitframework.annotation.Bean; +import modelengine.fitframework.annotation.Component; + +@Component +public class localeResolveConfig { + @Bean + public LocaleResolveFilter localeResolveFilter() { + return new LocaleResolveFilter(); + } +} diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index bd1f9d599..15d6cb4c5 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -22,17 +22,21 @@ public class DefualtLocaleResolver implements LocaleResolver{ private int cookieMaxAge = DEFAULT_COOKIE_MAX_AGE; private String cookieDomain = DEFAULT_COOKIE_DOMAIN; private String cookiePath = DEFAULT_COOKIE_PATH; - private Locale defaultLocale; + private Locale defaultLocale = Locale.getDefault(); @Override public Locale resolveLocale(HttpClassicServerRequest request) { // 先解析 Cookie,如果没有则使用 Accept-Language 头 String newLocale = request.cookies().get(this.cookieName).map(Cookie::value).orElse(null); - if(newLocale != null){ + if (newLocale != null) { return Locale.forLanguageTag(newLocale); } - - String acceptLanguage = request.headers().require("Accept-Language"); + String acceptLanguage; + try { + acceptLanguage = request.headers().require("Accept-Language"); + } catch (Exception e) { + acceptLanguage = null; + } if (acceptLanguage != null && !acceptLanguage.trim().isEmpty()) { return Locale.forLanguageTag(acceptLanguage); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index 533ab0873..5be9bee05 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -2,6 +2,8 @@ import modelengine.fit.http.server.*; import modelengine.fitframework.annotation.Scope; +import modelengine.fitframework.util.LocaleContext; +import modelengine.fitframework.util.LocaleContextHolder; import java.util.List; import java.util.Locale; @@ -12,7 +14,7 @@ public class LocaleResolveFilter implements HttpServerFilter { private List matchPatterns = List.of("/**"); - private List mismatchPatterns = null; + private List mismatchPatterns = List.of(); private Scope scope = Scope.GLOBAL; diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContext.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java similarity index 82% rename from framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContext.java rename to framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java index b1cbd0659..c04017b81 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContext.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java @@ -4,16 +4,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelengine.fit.http.util.i18n; +package modelengine.fitframework.util; import java.util.Locale; -/** - * 地区上下文,包含地区信息 - * - * @author fit-framework - * @since 2025-01-01 - */ public class LocaleContext { private final Locale locale; @@ -24,4 +18,4 @@ public LocaleContext(Locale locale) { public Locale getLocale() { return locale; } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContextHolder.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java similarity index 97% rename from framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContextHolder.java rename to framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java index ea50341d2..2050998ab 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleContextHolder.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelengine.fit.http.util.i18n; +package modelengine.fitframework.util; import java.util.Locale; From c79a34815e326f1e0a74f5d5ab8da54d674f5533 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Fri, 1 Aug 2025 13:19:15 +0800 Subject: [PATCH 03/25] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LocaleValidationController.java | 10 ++++++- .../LocaleValidationControllerTest.java | 8 +++++- .../validation/data/localeResolveConfig.java | 12 +++++++++ .../LocaleValidationController.java | 18 ++++++------- .../LocaleValidationControllerTest.java | 8 +++++- .../validation/data/localeResolveConfig.java | 12 +++++++++ .../http/util/i18n/DefualtLocaleResolver.java | 8 +++++- .../http/util/i18n/LocaleResolveFilter.java | 26 ++++++++++++++++--- .../fit/http/util/i18n/LocaleResolver.java | 4 +-- .../fitframework/util/LocaleContext.java | 6 +++++ .../util/LocaleContextHolder.java | 13 +++++++++- 11 files changed, 106 insertions(+), 19 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java index 9e312be50..881441471 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.validation; import modelengine.fit.http.annotation.PostMapping; @@ -12,7 +18,7 @@ * 地区验证控制器 - 测试ValidationHandler与LocaleContextMessageInterpolator的集成 * * @author 阮睿 - * @since 2025-01-27 + * @since 2025-08-01 */ @Component @RequestMapping(path = "/validation/locale", group = "地区验证测试接口") @@ -21,6 +27,8 @@ public class LocaleValidationController { /** * 测试验证消息的地区化 - 使用简单参数 + * + * @param company 表示注解验证类 {@link Company}。 */ @PostMapping(path = "/simple", description = "测试简单参数的地区化验证消息") public void validateSimpleParam(@RequestBody @Valid Company company) {} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index abbb2ade4..c82113c31 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.validation; import modelengine.fit.http.client.HttpClassicClientResponse; @@ -23,7 +29,7 @@ * {@link LocaleValidationController} 的测试集。 * * @author 阮睿 - * @since 2025-07-18 + * @since 2025-08-01 */ @MvcTest(classes = {LocaleValidationController.class}) @DisplayName("测试地区化验证消息功能") diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java index 39a40bc13..fdbb6b6f7 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java @@ -1,9 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.validation.data; import modelengine.fit.http.util.i18n.LocaleResolveFilter; import modelengine.fitframework.annotation.Bean; import modelengine.fitframework.annotation.Component; +/** + * {@link LocaleResolveFilter} 配置类 + * + * @author 阮睿 + * @since 2025-08-01 + */ @Component public class localeResolveConfig { @Bean diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java index 8d2dce0ac..3da7a4646 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java @@ -1,26 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.validation; import javax.validation.Valid; -import javax.validation.constraints.NotBlank; -import javax.validation.constraints.Min; -import modelengine.fit.http.util.i18n.LocaleResolveFilter; -import modelengine.fitframework.annotation.Bean; import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.util.LocaleContextHolder; import modelengine.fitframework.validation.data.Company; -import modelengine.fitframework.validation.data.Employee; import modelengine.fit.http.annotation.PostMapping; import modelengine.fit.http.annotation.RequestBody; import modelengine.fit.http.annotation.RequestMapping; -import java.util.Locale; - /** * 地区验证控制器 - 测试ValidationHandler与LocaleContextMessageInterpolator的集成 * * @author 阮睿 - * @since 2025-01-27 + * @since 2025-08-01 */ @Component @RequestMapping(path = "/validation/locale", group = "地区验证测试接口") @@ -29,6 +27,8 @@ public class LocaleValidationController { /** * 测试验证消息的地区化 - 使用简单参数 + * + * @param company 表示注解验证类 {@link Company}。 */ @PostMapping(path = "/simple", description = "测试简单参数的地区化验证消息") public void validateSimpleParam(@RequestBody @Valid Company company) {} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index abbb2ade4..c82113c31 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.validation; import modelengine.fit.http.client.HttpClassicClientResponse; @@ -23,7 +29,7 @@ * {@link LocaleValidationController} 的测试集。 * * @author 阮睿 - * @since 2025-07-18 + * @since 2025-08-01 */ @MvcTest(classes = {LocaleValidationController.class}) @DisplayName("测试地区化验证消息功能") diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java index 39a40bc13..fdbb6b6f7 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java @@ -1,9 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.validation.data; import modelengine.fit.http.util.i18n.LocaleResolveFilter; import modelengine.fitframework.annotation.Bean; import modelengine.fitframework.annotation.Component; +/** + * {@link LocaleResolveFilter} 配置类 + * + * @author 阮睿 + * @since 2025-08-01 + */ @Component public class localeResolveConfig { @Bean diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index 15d6cb4c5..b9ef95a8f 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -3,6 +3,7 @@ * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ + package modelengine.fit.http.util.i18n; import modelengine.fit.http.Cookie; @@ -11,7 +12,12 @@ import java.util.Locale; - +/** + * 默认地区解析器。 + * + * @author 阮睿 + * @since 2025-08-01 + */ public class DefualtLocaleResolver implements LocaleResolver{ public static final String DEFAULT_COOKIE_NAME = "locale"; diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index 5be9bee05..df5ea37a9 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fit.http.util.i18n; import modelengine.fit.http.server.*; @@ -8,6 +14,12 @@ import java.util.List; import java.util.Locale; +/** + * 地区解析过滤器。 + * + * @author 阮睿 + * @since 2025-08-01 + */ public class LocaleResolveFilter implements HttpServerFilter { private LocaleResolver localeResolver = null; @@ -46,13 +58,21 @@ public List mismatchPatterns() { return mismatchPatterns; } + /** + * 过滤请求,从请求中解析地区值并放入线程上下文和cookie。 + * + * @param request 表示服务器请求 {@link HttpClassicServerRequest}。 + * @param response 表示服务器响应 {@link HttpClassicServerResponse}。 + * @param chain 过滤链 {@link HttpServerFilterChain}。 + */ @Override - public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, HttpServerFilterChain chain) throws DoHttpServerFilterException { + public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, + HttpServerFilterChain chain) throws DoHttpServerFilterException { try { // 如果参数中带有地区,则直接设置地区 - String paramLocale = request.queries().first("locale").orElse( null); + String paramLocale = request.queries().first("locale").orElse(null); Locale responseLocale = null; - if(paramLocale != null && !paramLocale.trim().isEmpty()){ + if (paramLocale != null && !paramLocale.trim().isEmpty()) { responseLocale = Locale.forLanguageTag(paramLocale); LocaleContextHolder.setLocaleContext(new LocaleContext(responseLocale)); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java index 669915444..25bdea753 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java @@ -13,8 +13,8 @@ /** * 地区解析器接口,用于从HTTP请求中解析用户的地区设置 * - * @author fit-framework - * @since 2025-01-01 + * @author 阮睿 + * @since 2025-08-01 */ public interface LocaleResolver { diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java index c04017b81..5d63a57fc 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java @@ -8,6 +8,12 @@ import java.util.Locale; +/** + * 地区上下文。 + * + * @author 阮睿 + * @since 2025-08-01 + */ public class LocaleContext { private final Locale locale; diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java index 2050998ab..9bb048843 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java @@ -8,13 +8,20 @@ import java.util.Locale; - +/** + * 地区线程上下文。 + * + * @author 阮睿 + * @since 2025-08-01 + */ public class LocaleContextHolder { private static final ThreadLocal LOCALE_CONTEXT_HOLDER = new ThreadLocal<>(); /** * 设置当前线程的地区上下文 + * + * @param localeContext 地区上下文 {@link LocaleContext} */ public static void setLocaleContext(LocaleContext localeContext) { LOCALE_CONTEXT_HOLDER.set(localeContext); @@ -22,6 +29,8 @@ public static void setLocaleContext(LocaleContext localeContext) { /** * 获取当前线程的地区上下文 + * + * @return 地区上下文 {@link LocaleContext} */ public static LocaleContext getLocaleContext() { return LOCALE_CONTEXT_HOLDER.get(); @@ -29,6 +38,8 @@ public static LocaleContext getLocaleContext() { /** * 获取当前线程的地区 + * + * @return 地区 {@link Locale} */ public static Locale getLocale() { LocaleContext context = getLocaleContext(); From 8a97b0559b210154d78693a91508174853b989cd Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Mon, 1 Sep 2025 11:12:42 +0800 Subject: [PATCH 04/25] =?UTF-8?q?[fit]=20=E5=AE=8C=E5=96=84=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LocaleContextMessageInterpolator.java | 11 +++- .../LocaleValidationController.java | 8 +-- .../LocaleValidationControllerTest.java | 3 +- .../validation/data/localeResolveConfig.java | 7 ++- .../LocaleContextMessageInterpolator.java | 11 +++- .../LocaleValidationController.java | 8 +-- .../LocaleValidationControllerTest.java | 3 +- .../validation/data/localeResolveConfig.java | 7 ++- .../http/util/i18n/DefualtLocaleResolver.java | 55 +++++++++++++------ .../http/util/i18n/LocaleResolveFilter.java | 30 +++++----- .../fit/http/util/i18n/LocaleResolver.java | 15 ++--- .../fitframework/util/LocaleContext.java | 12 +++- .../util/LocaleContextHolder.java | 18 +++--- 13 files changed, 119 insertions(+), 69 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index d5dd002c7..339d50f10 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -15,7 +15,7 @@ import java.util.Locale; /** - * 检验消息处理包装类。 + * 检验消息处理的代理类。 *

* 从 {@link LocaleContextHolder} 中获取当前线程设置的 {@link Locale} 并委托 {@link MessageInterpolator} 去处理消息。 *

@@ -24,13 +24,20 @@ * @since 2025-07-31 */ public class LocaleContextMessageInterpolator implements MessageInterpolator { - private final MessageInterpolator targetInterpolator; + /** + * 构造函数。 + * + * @param targetInterpolator 表示目标检验消息处理对象的 {@link MessageInterpolator}。 + */ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) { this.targetInterpolator = targetInterpolator; } + /** + * 构造函数,默认使用 {@link ParameterMessageInterpolator} 作为目标检验消息处理对象。 + */ public LocaleContextMessageInterpolator() { this.targetInterpolator = new ParameterMessageInterpolator(); } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java index 881441471..4c03d15d7 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java @@ -15,7 +15,7 @@ import jakarta.validation.Valid; /** - * 地区验证控制器 - 测试ValidationHandler与LocaleContextMessageInterpolator的集成 + * 用于测试 {@link ValidationHandler} 与 {@link LocaleContextMessageInterpolator} 的集成地区验证控制器。 * * @author 阮睿 * @since 2025-08-01 @@ -24,13 +24,11 @@ @RequestMapping(path = "/validation/locale", group = "地区验证测试接口") @Validated public class LocaleValidationController { - /** - * 测试验证消息的地区化 - 使用简单参数 + * 使用简单参数测试验证消息的地区化。 * - * @param company 表示注解验证类 {@link Company}。 + * @param company 表示注解验证的测试实体类 {@link Company}。 */ @PostMapping(path = "/simple", description = "测试简单参数的地区化验证消息") public void validateSimpleParam(@RequestBody @Valid Company company) {} - } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index c82113c31..66191a754 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -26,7 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * {@link LocaleValidationController} 的测试集。 + * 表示评估国际化校验的测试类。 * * @author 阮睿 * @since 2025-08-01 @@ -34,7 +34,6 @@ @MvcTest(classes = {LocaleValidationController.class}) @DisplayName("测试地区化验证消息功能") public class LocaleValidationControllerTest { - @Fit private MockMvc mockMvc; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java index fdbb6b6f7..cea6de9b2 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java @@ -11,13 +11,18 @@ import modelengine.fitframework.annotation.Component; /** - * {@link LocaleResolveFilter} 配置类 + * 表示 {@link LocaleResolveFilter} 的配置类。 * * @author 阮睿 * @since 2025-08-01 */ @Component public class localeResolveConfig { + /** + * 注册一个 {@link LocaleResolveFilter} 的 bean。 + * + * @return 返回一个 {@link LocaleResolveFilter} 的实例。 + */ @Bean public LocaleResolveFilter localeResolveFilter() { return new LocaleResolveFilter(); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index b2c7263f0..965f6984d 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -15,7 +15,7 @@ import java.util.Locale; /** - * 检验消息处理包装类。 + * 检验消息处理的代理类。 *

* 从 {@link LocaleContextHolder} 中获取当前线程设置的 {@link Locale} 并委托 {@link MessageInterpolator} 去处理消息。 *

@@ -24,13 +24,20 @@ * @since 2025-07-31 */ public class LocaleContextMessageInterpolator implements MessageInterpolator { - private final MessageInterpolator targetInterpolator; + /** + * 构造函数。 + * + * @param targetInterpolator 表示目标检验消息处理对象的 {@link MessageInterpolator}。 + */ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) { this.targetInterpolator = targetInterpolator; } + /** + * 构造函数,默认使用 {@link ParameterMessageInterpolator} 作为目标检验消息处理对象。 + */ public LocaleContextMessageInterpolator() { this.targetInterpolator = new ParameterMessageInterpolator(); } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java index 3da7a4646..2c8e9347e 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java @@ -15,7 +15,7 @@ import modelengine.fit.http.annotation.RequestMapping; /** - * 地区验证控制器 - 测试ValidationHandler与LocaleContextMessageInterpolator的集成 + * 用于测试 {@link ValidationHandler} 与 {@link LocaleContextMessageInterpolator} 的集成地区验证控制器。 * * @author 阮睿 * @since 2025-08-01 @@ -24,13 +24,11 @@ @RequestMapping(path = "/validation/locale", group = "地区验证测试接口") @Validated public class LocaleValidationController { - /** - * 测试验证消息的地区化 - 使用简单参数 + * 使用简单参数测试验证消息的地区化。 * - * @param company 表示注解验证类 {@link Company}。 + * @param company 表示注解验证的测试实体类 {@link Company}。 */ @PostMapping(path = "/simple", description = "测试简单参数的地区化验证消息") public void validateSimpleParam(@RequestBody @Valid Company company) {} - } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index c82113c31..66191a754 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -26,7 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat; /** - * {@link LocaleValidationController} 的测试集。 + * 表示评估国际化校验的测试类。 * * @author 阮睿 * @since 2025-08-01 @@ -34,7 +34,6 @@ @MvcTest(classes = {LocaleValidationController.class}) @DisplayName("测试地区化验证消息功能") public class LocaleValidationControllerTest { - @Fit private MockMvc mockMvc; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java index fdbb6b6f7..cea6de9b2 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java @@ -11,13 +11,18 @@ import modelengine.fitframework.annotation.Component; /** - * {@link LocaleResolveFilter} 配置类 + * 表示 {@link LocaleResolveFilter} 的配置类。 * * @author 阮睿 * @since 2025-08-01 */ @Component public class localeResolveConfig { + /** + * 注册一个 {@link LocaleResolveFilter} 的 bean。 + * + * @return 返回一个 {@link LocaleResolveFilter} 的实例。 + */ @Bean public LocaleResolveFilter localeResolveFilter() { return new LocaleResolveFilter(); diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index b9ef95a8f..c39444b3c 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -18,8 +18,7 @@ * @author 阮睿 * @since 2025-08-01 */ -public class DefualtLocaleResolver implements LocaleResolver{ - +public class DefualtLocaleResolver implements LocaleResolver { public static final String DEFAULT_COOKIE_NAME = "locale"; public static final int DEFAULT_COOKIE_MAX_AGE = 60 * 60 * 24 * 365; public static final String DEFAULT_COOKIE_DOMAIN = "/"; @@ -32,7 +31,7 @@ public class DefualtLocaleResolver implements LocaleResolver{ @Override public Locale resolveLocale(HttpClassicServerRequest request) { - // 先解析 Cookie,如果没有则使用 Accept-Language 头 + // 先解析 Cookie,如果没有则解析 Accept-Language 头 String newLocale = request.cookies().get(this.cookieName).map(Cookie::value).orElse(null); if (newLocale != null) { return Locale.forLanguageTag(newLocale); @@ -52,39 +51,61 @@ public Locale resolveLocale(HttpClassicServerRequest request) { @Override public void setLocale(HttpClassicServerResponse response, Locale locale) { - - if(locale != null){ - response.cookies().add(Cookie.builder() - .name(cookieName) - .value(locale.toLanguageTag()) - .maxAge(cookieMaxAge) - .domain(cookieDomain) - .path(cookiePath) - .build()); - }else{ - response.cookies().add(Cookie.builder() - .name(cookieName) - .maxAge(0) - .build()); + if (locale != null) { + response.cookies() + .add(Cookie.builder() + .name(cookieName) + .value(locale.toLanguageTag()) + .maxAge(cookieMaxAge) + .domain(cookieDomain) + .path(cookiePath) + .build()); + } else { + response.cookies().add(Cookie.builder().name(cookieName).maxAge(0).build()); } } + /** + * 设置存储地区信息的 Cookie 名称。 + * + * @param cookieName 表示将要设置的 Cookie 名称 {@link String}。 + */ public void setCookieName(String cookieName) { this.cookieName = cookieName; } + /** + * 设置存储地区信息的 Cookie 的最大有效期。 + * + * @param cookieMaxAge 表示将要设置的 Cookie 最大有效期的 {@code int}。 + */ public void setCookieMaxAge(int cookieMaxAge) { this.cookieMaxAge = cookieMaxAge; } + /** + * 设置存储地区信息的 Cookie 的作用域。 + * + * @param cookieDomain 存储地区信息的 Cookie 作用域的 {@link String}。 + */ public void setCookieDomain(String cookieDomain) { this.cookieDomain = cookieDomain; } + /** + * 设置存储地区信息的 Cookie 的可见 URL 路径。 + * + * @param cookiePath 存储地区信息的 Cookie 作用域的 {@link String}。 + */ public void setCookiePath(String cookiePath) { this.cookiePath = cookiePath; } + /** + * 设置默认地区。 + * + * @param defaultLocale 表示默认地区的 {@link Locale}。 + */ public void setDefaultLocale(Locale defaultLocale) { this.defaultLocale = defaultLocale; } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index df5ea37a9..86d8ab5f8 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -30,11 +30,19 @@ public class LocaleResolveFilter implements HttpServerFilter { private Scope scope = Scope.GLOBAL; + /** + * 构造函数。 + * + * @param localeResolver 表示地区解析器的 {@link LocaleResolver}。 + */ public LocaleResolveFilter(LocaleResolver localeResolver) { localeResolver = localeResolver; } - public LocaleResolveFilter(){ + /** + * 默认构造函数。 + */ + public LocaleResolveFilter() { this.localeResolver = new DefualtLocaleResolver(); } @@ -58,35 +66,29 @@ public List mismatchPatterns() { return mismatchPatterns; } - /** - * 过滤请求,从请求中解析地区值并放入线程上下文和cookie。 - * - * @param request 表示服务器请求 {@link HttpClassicServerRequest}。 - * @param response 表示服务器响应 {@link HttpClassicServerResponse}。 - * @param chain 过滤链 {@link HttpServerFilterChain}。 - */ @Override public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, HttpServerFilterChain chain) throws DoHttpServerFilterException { try { - // 如果参数中带有地区,则直接设置地区 + // 如果参数中带有地区,说明用户想使用新地区执行后续的操作,直接设置地区。 String paramLocale = request.queries().first("locale").orElse(null); Locale responseLocale = null; if (paramLocale != null && !paramLocale.trim().isEmpty()) { responseLocale = Locale.forLanguageTag(paramLocale); LocaleContextHolder.setLocaleContext(new LocaleContext(responseLocale)); } - // 如果参数中不包含地区,则解析 - else{ - Locale locale =localeResolver.resolveLocale(request); + // 如果参数中不包含地区,则解析请求所带的地区参数。 + else { + Locale locale = localeResolver.resolveLocale(request); LocaleContextHolder.setLocaleContext(new LocaleContext(locale)); } + // 继续执行后续过滤器。 chain.doFilter(request, response); - // responseLocale是用户期望设置的地区,不受 server 端处理的影响 + // responseLocale 是用户期望设置的地区,不受 server 端处理的影响。 localeResolver.setLocale(response, responseLocale); - }finally { + } finally { LocaleContextHolder.clear(); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java index 25bdea753..c105d789e 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java @@ -3,6 +3,7 @@ * This file is a part of the ModelEngine Project. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ + package modelengine.fit.http.util.i18n; import modelengine.fit.http.server.HttpClassicServerRequest; @@ -11,7 +12,7 @@ import java.util.Locale; /** - * 地区解析器接口,用于从HTTP请求中解析用户的地区设置 + * 地区解析器接口,用于从HTTP请求中解析用户的地区设置。 * * @author 阮睿 * @since 2025-08-01 @@ -19,18 +20,18 @@ public interface LocaleResolver { /** - * 解析用户的地区设置 + * 解析用户的地区设置。 * - * @param request HTTP请求 {@link HttpClassicServerRequest}。 - * @return 解析出来的地区 {@link Locale}。 + * @param request 表示待解析的HTTP请求 {@link HttpClassicServerRequest}。 + * @return 表示解析出来的地区信息 {@link Locale}。 */ Locale resolveLocale(HttpClassicServerRequest request); /** - * 设置地区到响应中 + * 设置地区到返回响应中。 * - * @param response HTTP响应 {@link HttpClassicServerResponse}。 - * @param locale 要设置的地区 {@link Locale}。 + * @param response 表示将要设置地区的HTTP响应 {@link HttpClassicServerResponse}。 + * @param locale 表示要设置的地区 {@link Locale}。 */ void setLocale(HttpClassicServerResponse response, Locale locale); } diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java index 5d63a57fc..647ae1b48 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java @@ -9,7 +9,7 @@ import java.util.Locale; /** - * 地区上下文。 + * 表示存储地区信息的上下文。 * * @author 阮睿 * @since 2025-08-01 @@ -17,10 +17,20 @@ public class LocaleContext { private final Locale locale; + /** + * 构造函数。 + * + * @param locale 地区信息 {@link Locale}。 + */ public LocaleContext(Locale locale) { this.locale = locale; } + /** + * 获取上下文中的地区信息。 + * + * @return 当前上下文中存储的地区信息 {@link Locale}。 + */ public Locale getLocale() { return locale; } diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java index 9bb048843..8a1c2dd91 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java @@ -9,46 +9,44 @@ import java.util.Locale; /** - * 地区线程上下文。 + * 表示存储地区上下文的线程上下文。 * * @author 阮睿 * @since 2025-08-01 */ public class LocaleContextHolder { - private static final ThreadLocal LOCALE_CONTEXT_HOLDER = new ThreadLocal<>(); /** - * 设置当前线程的地区上下文 + * 设置当前线程的地区上下文。 * - * @param localeContext 地区上下文 {@link LocaleContext} + * @param localeContext 表示将要存储在当前线程的地区上下文 {@link LocaleContext}。 */ public static void setLocaleContext(LocaleContext localeContext) { LOCALE_CONTEXT_HOLDER.set(localeContext); } /** - * 获取当前线程的地区上下文 + * 获取当前线程的地区上下文。 * - * @return 地区上下文 {@link LocaleContext} + * @return 表示当前线程的地区上下文 {@link LocaleContext}。 */ public static LocaleContext getLocaleContext() { return LOCALE_CONTEXT_HOLDER.get(); } /** - * 获取当前线程的地区 + * 获取当前线程的地区。 * - * @return 地区 {@link Locale} + * @return 表示当前线程上下文存储的地区信息 {@link Locale}。 */ public static Locale getLocale() { LocaleContext context = getLocaleContext(); return context != null ? context.getLocale() : Locale.getDefault(); } - /** - * 清除当前线程的地区上下文 + * 清除当前线程的地区上下文。 */ public static void clear() { LOCALE_CONTEXT_HOLDER.remove(); From 53f1c3e598b78cb50470ca22e04eb9622adc3bc4 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Mon, 1 Sep 2025 14:37:02 +0800 Subject: [PATCH 05/25] =?UTF-8?q?[fit]=20=E4=BF=AE=E6=94=B9=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E5=A4=84=E7=90=86=E9=BB=98=E8=AE=A4=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=9A=84=E6=8F=92=E5=80=BC=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/ValidationHandler.java | 20 +++++++++++++++---- .../LocaleValidationControllerTest.java | 1 + .../validation/ValidationHandlerTest.java | 1 + .../LocaleValidationController.java | 5 ++++- .../validation/ValidationHandler.java | 18 ++++++++++++++--- .../LocaleValidationControllerTest.java | 1 + .../validation/ValidationHandlerTest.java | 9 +++++---- .../LocaleValidationController.java | 5 ++++- 8 files changed, 47 insertions(+), 13 deletions(-) rename framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/{ => data}/LocaleValidationController.java (84%) rename framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/{ => data}/LocaleValidationController.java (84%) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index ab4805c70..0fdc23901 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -8,6 +8,7 @@ import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; +import jakarta.validation.MessageInterpolator; import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; @@ -43,10 +44,10 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; - private final LocaleMessageInterpolator messageInterpolator; + private MessageInterpolator messageInterpolator; public ValidationHandler() { - this.messageInterpolator = new LocaleMessageInterpolator(); + this.messageInterpolator = new LocaleContextMessageInterpolator(); this.validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() .messageInterpolator(this.messageInterpolator) @@ -58,10 +59,21 @@ public ValidationHandler() { /** * 设置校验信息语言。 * - * @param locale 校验语言 {@link Locale}。 + * @param locale 表示校验语言的 {@link Locale}。 */ public void setLocale(Locale locale) { - this.messageInterpolator.setLocale(locale); + if (this.messageInterpolator instanceof LocaleMessageInterpolator) { + ((LocaleMessageInterpolator) this.messageInterpolator).setLocale(locale); + } + } + + /** + * 设置校验信息消息插值器。 + * + * @param messageInterpolator 表示校验信息消息插值器的 {@link MessageInterpolator}。 + */ + public void setMessageInterpolator(MessageInterpolator messageInterpolator) { + this.messageInterpolator = messageInterpolator; } /** diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 66191a754..1adae14a1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -15,6 +15,7 @@ import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; import modelengine.fitframework.test.domain.mvc.request.MockRequestBuilder; import modelengine.fitframework.validation.data.Company; +import modelengine.fitframework.validation.data.LocaleValidationController; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 2b5d9def0..2d0c6fc77 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -58,6 +58,7 @@ public class ValidationHandlerTest { @BeforeEach void setUp() { + this.handler.setMessageInterpolator(new LocaleMessageInterpolator()); this.handler.setLocale(Locale.CHINA); when(this.validated.value()).thenReturn(new Class[0]); when(this.fitRuntime.resolverOfAnnotations()).thenReturn(this.annotationMetadataResolver); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java similarity index 84% rename from framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java index 4c03d15d7..a202fc28e 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java @@ -4,12 +4,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelengine.fitframework.validation; +package modelengine.fitframework.validation.data; import modelengine.fit.http.annotation.PostMapping; import modelengine.fit.http.annotation.RequestBody; import modelengine.fit.http.annotation.RequestMapping; import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.validation.LocaleContextMessageInterpolator; +import modelengine.fitframework.validation.Validated; +import modelengine.fitframework.validation.ValidationHandler; import modelengine.fitframework.validation.data.Company; import jakarta.validation.Valid; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 40e9086df..a4730506d 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -25,6 +25,7 @@ import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; +import javax.validation.MessageInterpolator; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; @@ -44,10 +45,10 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; - private final LocaleMessageInterpolator messageInterpolator; + private MessageInterpolator messageInterpolator; public ValidationHandler() { - this.messageInterpolator = new LocaleMessageInterpolator(); + this.messageInterpolator = new LocaleContextMessageInterpolator(); this.validatorFactory = Validation.byProvider(HibernateValidator.class) .configure() .messageInterpolator(this.messageInterpolator) @@ -62,7 +63,18 @@ public ValidationHandler() { * @param locale 表示校验语言的 {@link Locale}。 */ public void setLocale(Locale locale) { - this.messageInterpolator.setLocale(locale); + if (this.messageInterpolator instanceof LocaleMessageInterpolator) { + ((LocaleMessageInterpolator) this.messageInterpolator).setLocale(locale); + } + } + + /** + * 设置校验信息消息插值器。 + * + * @param messageInterpolator 表示校验信息消息插值器的 {@link MessageInterpolator}。 + */ + public void setMessageInterpolator(MessageInterpolator messageInterpolator) { + this.messageInterpolator = messageInterpolator; } /** diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 66191a754..1adae14a1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -15,6 +15,7 @@ import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; import modelengine.fitframework.test.domain.mvc.request.MockRequestBuilder; import modelengine.fitframework.validation.data.Company; +import modelengine.fitframework.validation.data.LocaleValidationController; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index b23b8dd09..ba1d1d1dd 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -59,10 +59,11 @@ public class ValidationHandlerTest { @BeforeEach void setUp() { - handler.setLocale(Locale.CHINA); - when(validated.value()).thenReturn(new Class[0]); - when(fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); - when(beanContainer.runtime()).thenReturn(fitRuntime); + this.handler.setMessageInterpolator(new LocaleMessageInterpolator()); + this.handler.setLocale(Locale.ENGLISH); + when(this.validated.value()).thenReturn(new Class[0]); + when(this.fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); + when(this.beanContainer.runtime()).thenReturn(fitRuntime); } private ConstraintViolationException invokeHandleMethod(Method targetMethod, Object[] args) { diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java similarity index 84% rename from framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java rename to framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java index 2c8e9347e..728a07601 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java @@ -4,11 +4,14 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelengine.fitframework.validation; +package modelengine.fitframework.validation.data; import javax.validation.Valid; import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.validation.LocaleContextMessageInterpolator; +import modelengine.fitframework.validation.Validated; +import modelengine.fitframework.validation.ValidationHandler; import modelengine.fitframework.validation.data.Company; import modelengine.fit.http.annotation.PostMapping; import modelengine.fit.http.annotation.RequestBody; From bcb4f86499d3c76607007d6133307112a4591060 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Mon, 1 Sep 2025 15:39:55 +0800 Subject: [PATCH 06/25] =?UTF-8?q?[fit]=20=E4=BF=AE=E6=94=B9=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E5=A4=84=E7=90=86=E6=8F=92=E5=80=BC=E5=99=A8=EF=BC=8C?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E9=BB=98=E8=AE=A4=E5=9C=B0=E5=8C=BA=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LocaleContextMessageInterpolator.java | 39 ++++++++- .../validation/LocaleMessageInterpolator.java | 86 ------------------- .../validation/ValidationHandler.java | 16 +--- .../validation/ValidationHandlerTest.java | 1 - .../LocaleContextMessageInterpolator.java | 39 ++++++++- .../validation/LocaleMessageInterpolator.java | 86 ------------------- .../validation/ValidationHandler.java | 15 +--- .../validation/ValidationHandlerTest.java | 3 +- .../util/LocaleContextHolder.java | 2 +- 9 files changed, 82 insertions(+), 205 deletions(-) delete mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java delete mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index 339d50f10..a6c1c8e0c 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -26,6 +26,8 @@ public class LocaleContextMessageInterpolator implements MessageInterpolator { private final MessageInterpolator targetInterpolator; + private Locale locale; + /** * 构造函数。 * @@ -33,6 +35,7 @@ public class LocaleContextMessageInterpolator implements MessageInterpolator { */ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) { this.targetInterpolator = targetInterpolator; + this.locale = Locale.getDefault(); } /** @@ -40,11 +43,45 @@ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) */ public LocaleContextMessageInterpolator() { this.targetInterpolator = new ParameterMessageInterpolator(); + this.locale = Locale.getDefault(); + } + + /** + * 构造函数。 + * + * @param locale 表示当前设置默认的 {@link Locale}。 + */ + public LocaleContextMessageInterpolator(Locale locale) { + this.targetInterpolator = new ParameterMessageInterpolator(); + this.locale = locale; + } + + /** + * 构造函数。 + * + * @param targetInterpolator 表示目标检验消息处理对象的 {@link MessageInterpolator}。 + * @param locale 表示当前设置默认的 {@link Locale}。 + */ + public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator, Locale locale) { + this.targetInterpolator = targetInterpolator; + this.locale = locale; + } + + /** + * 设置默认的 {@link Locale}。 + * + * @param locale 默认设置的 {@link Locale}。 + */ + public void setLocale(Locale locale) { + this.locale = locale; } @Override public String interpolate(String messageTemplate, Context context) { - return this.targetInterpolator.interpolate(messageTemplate, context, LocaleContextHolder.getLocale()); + if (LocaleContextHolder.getLocale() != null) { + return this.targetInterpolator.interpolate(messageTemplate, context, LocaleContextHolder.getLocale()); + } + return this.targetInterpolator.interpolate(messageTemplate, context, this.locale); } @Override diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java deleted file mode 100644 index fc22cc98a..000000000 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java +++ /dev/null @@ -1,86 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation; - -import jakarta.validation.MessageInterpolator; - -import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; - -import java.util.Locale; - -/** - * 地区消息插值器。 - *

- * 作为 Jakarta 消息插值器的代理类,提供地区设置能力。 - *

- * - * @author 阮睿 - * @since 2025-08-18 - */ -public class LocaleMessageInterpolator implements MessageInterpolator { - private final MessageInterpolator target; - - private Locale locale; - - /** - * 构造函数,使用指定的目标消息插值器初始化实例。 - * - * @param target 表示目标消息插值器的 {@link MessageInterpolator}。 - */ - public LocaleMessageInterpolator(MessageInterpolator target) { - this.target = target; - this.locale = Locale.getDefault(); - } - - /** - * 构造函数,使用指定的地区初始化实例。 - * - * @param locale 表示指定地区的 {@link Locale}。 - */ - public LocaleMessageInterpolator(Locale locale) { - this.locale = locale; - this.target = new ParameterMessageInterpolator(); - } - - /** - * 构造函数,使用指定的目标消息插值器和地区初始化实例。 - * - * @param target 表示被代理的目标消息插值器的 {@link MessageInterpolator}。 - * @param locale 表示当前消息插值器要使用语言的相关地区的 {@link Locale}。 - */ - public LocaleMessageInterpolator(MessageInterpolator target, Locale locale) { - this.target = target; - this.locale = locale; - } - - /** - * 构造函数,使用默认地区初始化实例。 - */ - public LocaleMessageInterpolator() { - this.locale = Locale.getDefault(); - this.target = new ParameterMessageInterpolator(); - } - - @Override - public String interpolate(String messageTemplate, Context context) { - return this.target.interpolate(messageTemplate, context, this.locale); - } - - @Override - public String interpolate(String messageTemplate, Context context, Locale locale) { - return this.target.interpolate(messageTemplate, context, locale); - } - - /** - * 设置地区。 - * - * @param locale 表示当前消息插值器要使用语言的相关地区的 {@link Locale}。 - */ - public void setLocale(Locale locale) { - this.locale = locale; - } -} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 0fdc23901..f997285ca 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -8,7 +8,6 @@ import jakarta.validation.ConstraintViolation; import jakarta.validation.ConstraintViolationException; -import jakarta.validation.MessageInterpolator; import jakarta.validation.Validation; import jakarta.validation.Validator; import jakarta.validation.ValidatorFactory; @@ -44,7 +43,7 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; - private MessageInterpolator messageInterpolator; + private LocaleContextMessageInterpolator messageInterpolator; public ValidationHandler() { this.messageInterpolator = new LocaleContextMessageInterpolator(); @@ -62,18 +61,7 @@ public ValidationHandler() { * @param locale 表示校验语言的 {@link Locale}。 */ public void setLocale(Locale locale) { - if (this.messageInterpolator instanceof LocaleMessageInterpolator) { - ((LocaleMessageInterpolator) this.messageInterpolator).setLocale(locale); - } - } - - /** - * 设置校验信息消息插值器。 - * - * @param messageInterpolator 表示校验信息消息插值器的 {@link MessageInterpolator}。 - */ - public void setMessageInterpolator(MessageInterpolator messageInterpolator) { - this.messageInterpolator = messageInterpolator; + this.messageInterpolator.setLocale(locale); } /** diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 2d0c6fc77..2b5d9def0 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -58,7 +58,6 @@ public class ValidationHandlerTest { @BeforeEach void setUp() { - this.handler.setMessageInterpolator(new LocaleMessageInterpolator()); this.handler.setLocale(Locale.CHINA); when(this.validated.value()).thenReturn(new Class[0]); when(this.fitRuntime.resolverOfAnnotations()).thenReturn(this.annotationMetadataResolver); diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index 965f6984d..3c0352841 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -26,6 +26,8 @@ public class LocaleContextMessageInterpolator implements MessageInterpolator { private final MessageInterpolator targetInterpolator; + private Locale locale; + /** * 构造函数。 * @@ -33,6 +35,7 @@ public class LocaleContextMessageInterpolator implements MessageInterpolator { */ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) { this.targetInterpolator = targetInterpolator; + this.locale = Locale.getDefault(); } /** @@ -40,11 +43,45 @@ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator) */ public LocaleContextMessageInterpolator() { this.targetInterpolator = new ParameterMessageInterpolator(); + this.locale = Locale.getDefault(); + } + + /** + * 构造函数。 + * + * @param locale 表示当前设置默认的 {@link Locale}。 + */ + public LocaleContextMessageInterpolator(Locale locale) { + this.targetInterpolator = new ParameterMessageInterpolator(); + this.locale = locale; + } + + /** + * 构造函数。 + * + * @param targetInterpolator 表示目标检验消息处理对象的 {@link MessageInterpolator}。 + * @param locale 表示当前设置默认的 {@link Locale}。 + */ + public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator, Locale locale) { + this.targetInterpolator = targetInterpolator; + this.locale = locale; + } + + /** + * 设置默认的 {@link Locale}。 + * + * @param locale 默认设置的 {@link Locale}。 + */ + public void setLocale(Locale locale) { + this.locale = locale; } @Override public String interpolate(String messageTemplate, Context context) { - return this.targetInterpolator.interpolate(messageTemplate, context, LocaleContextHolder.getLocale()); + if (LocaleContextHolder.getLocale() != null) { + return this.targetInterpolator.interpolate(messageTemplate, context, LocaleContextHolder.getLocale()); + } + return this.targetInterpolator.interpolate(messageTemplate, context, this.locale); } @Override diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java deleted file mode 100644 index 74438d75c..000000000 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleMessageInterpolator.java +++ /dev/null @@ -1,86 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation; - -import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; - -import java.util.Locale; - -import javax.validation.MessageInterpolator; - -/** - * 地区消息插值器。 - *

- * 作为 Jakarta 消息插值器的代理类,提供地区设置能力。 - *

- * - * @author 阮睿 - * @since 2025-08-18 - */ -public class LocaleMessageInterpolator implements MessageInterpolator { - private final MessageInterpolator target; - - private Locale locale; - - /** - * 构造函数,使用指定的目标消息插值器初始化实例。 - * - * @param target 表示目标消息插值器的 {@link MessageInterpolator}。 - */ - public LocaleMessageInterpolator(MessageInterpolator target) { - this.target = target; - this.locale = Locale.getDefault(); - } - - /** - * 构造函数,使用指定的地区初始化实例。 - * - * @param locale 表示指定地区的 {@link Locale}。 - */ - public LocaleMessageInterpolator(Locale locale) { - this.locale = locale; - this.target = new ParameterMessageInterpolator(); - } - - /** - * 构造函数,使用指定的目标消息插值器和地区初始化实例。 - * - * @param target 表示被代理的目标消息插值器的 {@link MessageInterpolator}。 - * @param locale 表示当前消息插值器要使用语言的相关地区的 {@link Locale}。 - */ - public LocaleMessageInterpolator(MessageInterpolator target, Locale locale) { - this.target = target; - this.locale = locale; - } - - /** - * 构造函数,使用默认地区初始化实例。 - */ - public LocaleMessageInterpolator() { - this.locale = Locale.getDefault(); - this.target = new ParameterMessageInterpolator(); - } - - @Override - public String interpolate(String messageTemplate, Context context) { - return this.target.interpolate(messageTemplate, context, this.locale); - } - - @Override - public String interpolate(String messageTemplate, Context context, Locale locale) { - return this.target.interpolate(messageTemplate, context, locale); - } - - /** - * 设置地区。 - * - * @param locale 表示当前消息插值器要使用语言的相关地区的 {@link Locale}。 - */ - public void setLocale(Locale locale) { - this.locale = locale; - } -} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index a4730506d..4b816ee04 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -45,7 +45,7 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; - private MessageInterpolator messageInterpolator; + private LocaleContextMessageInterpolator messageInterpolator; public ValidationHandler() { this.messageInterpolator = new LocaleContextMessageInterpolator(); @@ -63,18 +63,7 @@ public ValidationHandler() { * @param locale 表示校验语言的 {@link Locale}。 */ public void setLocale(Locale locale) { - if (this.messageInterpolator instanceof LocaleMessageInterpolator) { - ((LocaleMessageInterpolator) this.messageInterpolator).setLocale(locale); - } - } - - /** - * 设置校验信息消息插值器。 - * - * @param messageInterpolator 表示校验信息消息插值器的 {@link MessageInterpolator}。 - */ - public void setMessageInterpolator(MessageInterpolator messageInterpolator) { - this.messageInterpolator = messageInterpolator; + this.messageInterpolator.setLocale(locale); } /** diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index ba1d1d1dd..aa2e00175 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -59,8 +59,7 @@ public class ValidationHandlerTest { @BeforeEach void setUp() { - this.handler.setMessageInterpolator(new LocaleMessageInterpolator()); - this.handler.setLocale(Locale.ENGLISH); + this.handler.setLocale(Locale.CHINA); when(this.validated.value()).thenReturn(new Class[0]); when(this.fitRuntime.resolverOfAnnotations()).thenReturn(annotationMetadataResolver); when(this.beanContainer.runtime()).thenReturn(fitRuntime); diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java index 8a1c2dd91..2683a1f4d 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java @@ -42,7 +42,7 @@ public static LocaleContext getLocaleContext() { */ public static Locale getLocale() { LocaleContext context = getLocaleContext(); - return context != null ? context.getLocale() : Locale.getDefault(); + return context != null ? context.getLocale() : null; } /** From f1b5130e46b9cb250c90091e7bed51f461c56a10 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Fri, 5 Sep 2025 17:20:14 +0800 Subject: [PATCH 07/25] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/fit-i18n-registry/pom.xml | 77 +++++++++++++ .../i18n/LocaleResolveFilter.java | 109 ++++++++++++++++++ .../i18n/LocaleResolverEntry.java | 40 +++++++ .../i18n/LocaleResolverRegistry.java | 108 +++++++++++++++++ .../fit/java/fit-builtin/plugins/pom.xml | 1 + .../http/util/i18n/DefualtLocaleResolver.java | 19 ++- .../fit/http/util/i18n/LocaleResolver.java | 10 ++ 7 files changed, 360 insertions(+), 4 deletions(-) create mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/pom.xml create mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverEntry.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/pom.xml new file mode 100644 index 000000000..3fe7c43c7 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + + + org.fitframework.plugin + fit-plugin-parent + 3.6.0-SNAPSHOT + + + fit-i18n-registry + + FIT i18n Registry + + FIT Framework Service provide locale resolver registry. + + https://github.com/ModelEngine-Group/fit-framework + + + + + org.fitframework + fit-api + + + org.fitframework + fit-util + + + + + org.fitframework.service + fit-http-classic + + + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + org.assertj + assertj-core + test + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + package + + + + + + + run + + + + + + + diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java new file mode 100644 index 000000000..0c33a1e62 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java @@ -0,0 +1,109 @@ +package modelengine.fitframework.i18n; + +import modelengine.fit.http.server.DoHttpServerFilterException; +import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.http.server.HttpClassicServerResponse; +import modelengine.fit.http.server.HttpServerFilter; +import modelengine.fit.http.server.HttpServerFilterChain; +import modelengine.fit.http.util.i18n.DefualtLocaleResolver; +import modelengine.fit.http.util.i18n.LocaleResolver; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.annotation.Scope; +import modelengine.fitframework.util.LocaleContext; +import modelengine.fitframework.util.LocaleContextHolder; + +import java.util.List; +import java.util.Locale; + +/** + * 地区解析过滤器。 + * + * @author 阮睿 + * @since 2025-08-01 + */ +@Component +public class LocaleResolveFilter implements HttpServerFilter { + + private LocaleResolver localeResolver = null; + + private List matchPatterns = List.of("/**"); + + private List mismatchPatterns = List.of(); + + private Scope scope = Scope.GLOBAL; + + private LocaleResolverRegistry localeResolverRegistry; + + /** + * 构造函数。 + * + * @param localeResolver 表示地区解析器的 {@link LocaleResolver}。 + */ + public LocaleResolveFilter(LocaleResolver localeResolver, LocaleResolverRegistry localeResolverRegistry) { + localeResolver = localeResolver; + } + + /** + * 构造函数。 + */ + public LocaleResolveFilter(LocaleResolverRegistry localeResolverRegistry) { + this.localeResolver = new DefualtLocaleResolver(); + } + + @Override + public String name() { + return "LocaleResolveFilter"; + } + + @Override + public int priority() { + return 0; + } + + @Override + public List matchPatterns() { + return matchPatterns; + } + + @Override + public List mismatchPatterns() { + return mismatchPatterns; + } + + @Override + public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, + HttpServerFilterChain chain) throws DoHttpServerFilterException { + try { + // 如果参数中带有地区,说明用户想使用新地区执行后续的操作,直接设置地区。 + String paramLocale = request.queries().first("locale").orElse(null); + Locale responseLocale = null; + if (paramLocale != null && !paramLocale.trim().isEmpty()) { + responseLocale = Locale.forLanguageTag(paramLocale); + LocaleContextHolder.setLocaleContext(new LocaleContext(responseLocale)); + } + // 如果参数中不包含地区,则解析请求所带的地区参数。 + else { + // 使用责任链解析locale + Locale locale = this.localeResolverRegistry.resolveLocale(request); + if (locale == null) { + locale = this.localeResolver.resolveLocale(request); // fallback + } + LocaleContextHolder.setLocaleContext(new LocaleContext(locale)); + } + + // 继续执行后续过滤器。 + chain.doFilter(request, response); + + // responseLocale 是用户期望设置的地区,不受 server 端处理的影响。 + localeResolver.setLocale(response, responseLocale); + } finally { + LocaleContextHolder.clear(); + } + + } + + @Override + public Scope scope() { + return scope; + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverEntry.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverEntry.java new file mode 100644 index 000000000..b4e722620 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverEntry.java @@ -0,0 +1,40 @@ +package modelengine.fitframework.i18n; + +import modelengine.fit.http.util.i18n.LocaleResolver; + +import java.util.List; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class LocaleResolverEntry { + private final LocaleResolver resolver; + private final Pattern urlPattern; + private final int priority; + + public LocaleResolverEntry(LocaleResolver resolver, String urlPattern, int priority) { + this.resolver = resolver; + this.priority = priority; + this.urlPattern = this.compilePattern(urlPattern); + } + + private Pattern compilePattern(String pattern) { + // 支持Ant风格的路径匹配: /api/** -> /api/.* + String regex = pattern + .replace("**", ".*") + .replace("*", "[^/]*") + .replace("?", "."); + return Pattern.compile("^" + regex + "$"); + } + + public boolean matches(String requestPath) { + return urlPattern.matcher(requestPath).matches(); + } + + public int getPriority() { + return priority; + } + + public LocaleResolver getResolver() { + return resolver; + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java new file mode 100644 index 000000000..4c3482163 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java @@ -0,0 +1,108 @@ +package modelengine.fitframework.i18n; + +import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.http.server.HttpClassicServerResponse; +import modelengine.fit.http.server.dispatch.MappingTree; +import modelengine.fit.http.server.dispatch.support.DefaultMappingTree; +import modelengine.fit.http.util.i18n.LocaleResolver; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.ioc.BeanContainer; +import modelengine.fitframework.ioc.BeanFactory; +import modelengine.fitframework.plugin.Plugin; +import modelengine.fitframework.plugin.PluginStartedObserver; +import modelengine.fitframework.plugin.PluginStoppingObserver; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import modelengine.fitframework.resource.UrlUtils; +import modelengine.fitframework.util.OptionalUtils; +import modelengine.fitframework.util.wildcard.PathPattern; +import modelengine.fitframework.util.wildcard.Pattern; + +@Component +public class LocaleResolverRegistry implements PluginStartedObserver, PluginStoppingObserver { + private static final char PATH_SEPARATOR = '/'; + + // 参考DefaultHttpDispatcher的三层结构 + private final Map noPathVariableResolvers = new ConcurrentHashMap<>(); + private final MappingTree pathVariableResolvers = new DefaultMappingTree<>(); + private final Map wildcardResolvers = new ConcurrentHashMap<>(); + + + public void register(String pluginName, LocaleResolver resolver, String urlPattern) { + String pathPattern = MappingTree.convertToMatchedPathPattern(urlPattern); + if (pathPattern.contains("**")) { + wildcardResolvers.put(pathPattern, resolver); + } else if (pathPattern.contains("*")) { + pathVariableResolvers.register(pathPattern, resolver); + } else { + noPathVariableResolvers.put(pathPattern, resolver); + } + } + + public void unregister(String pluginName, List urlPatterns) { + for (String pattern : urlPatterns) { + String pathPattern = MappingTree.convertToMatchedPathPattern(pattern); + if (pathPattern.contains("**")) { + wildcardResolvers.remove(pathPattern); + } else if (pathPattern.contains("*")) { + pathVariableResolvers.unregister(pathPattern); + } else { + noPathVariableResolvers.remove(pathPattern); + } + } + } + + public LocaleResolver dispatch(HttpClassicServerRequest request) { + String path = UrlUtils.decodePath(request.path()); + return (LocaleResolver) OptionalUtils.get(() -> selectFromNoPathVariableResolvers(path)) + .orElse(() -> selectFromPathVariableResolvers(path)) + .orElse(() -> selectFromWildcardResolvers(path)) + .orElse(null); + } + + private Optional selectFromNoPathVariableResolvers(String path) { + LocaleResolver resolver = noPathVariableResolvers.get(path); + return Optional.ofNullable(resolver); + } + + private Optional selectFromPathVariableResolvers(String path) { + return pathVariableResolvers.search(path); + } + + private Optional selectFromWildcardResolvers(String path) { + for (Map.Entry entry : wildcardResolvers.entrySet()) { + PathPattern pattern = Pattern.forPath(entry.getKey(), PATH_SEPARATOR); + if (pattern.matches(path)) { + return Optional.of(entry.getValue()); + } + } + return Optional.empty(); + } + + @Override + public void onPluginStarted(Plugin plugin) { + BeanContainer container = plugin.container(); + List localeResolvers = container.all(LocaleResolver.class) + .stream() + .map(BeanFactory::get) + .collect(Collectors.toList()); + for(LocaleResolver localeResolver : localeResolvers) { + this.register(localeResolver.getName(),localeResolver,localeResolver.getUrlPattern(),localeResolver.getPriority()); + } + } + + @Override + public void onPluginStopping(Plugin plugin) { + BeanContainer container = plugin.container(); + List localeResolvers = container.all(LocaleResolver.class) + .stream() + .map(BeanFactory::get) + .collect(Collectors.toList()); + for(LocaleResolver localeResolver : localeResolvers) { + this.unregister(localeResolver.getName()); + } + } +} diff --git a/framework/fit/java/fit-builtin/plugins/pom.xml b/framework/fit/java/fit-builtin/plugins/pom.xml index 0260ff321..c506a613e 100644 --- a/framework/fit/java/fit-builtin/plugins/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/pom.xml @@ -45,6 +45,7 @@ fit-value-fastjson fit-validation-hibernate-jakarta fit-validation-hibernate-javax + fit-i18n-registry diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index c39444b3c..796cff7ff 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -19,10 +19,6 @@ * @since 2025-08-01 */ public class DefualtLocaleResolver implements LocaleResolver { - public static final String DEFAULT_COOKIE_NAME = "locale"; - public static final int DEFAULT_COOKIE_MAX_AGE = 60 * 60 * 24 * 365; - public static final String DEFAULT_COOKIE_DOMAIN = "/"; - public static final String DEFAULT_COOKIE_PATH = "/"; private String cookieName = DEFAULT_COOKIE_NAME; private int cookieMaxAge = DEFAULT_COOKIE_MAX_AGE; private String cookieDomain = DEFAULT_COOKIE_DOMAIN; @@ -65,6 +61,21 @@ public void setLocale(HttpClassicServerResponse response, Locale locale) { } } + @Override + public String getName() { + return "DefualtLocaleResolver"; + } + + @Override + public String getUrlPattern() { + return "/**"; + } + + @Override + public int getPriority() { + return 0; + } + /** * 设置存储地区信息的 Cookie 名称。 * diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java index c105d789e..3eeb50974 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java @@ -18,6 +18,10 @@ * @since 2025-08-01 */ public interface LocaleResolver { + public static final String DEFAULT_COOKIE_NAME = "locale"; + public static final int DEFAULT_COOKIE_MAX_AGE = 60 * 60 * 24 * 365; + public static final String DEFAULT_COOKIE_DOMAIN = "/"; + public static final String DEFAULT_COOKIE_PATH = "/"; /** * 解析用户的地区设置。 @@ -34,4 +38,10 @@ public interface LocaleResolver { * @param locale 表示要设置的地区 {@link Locale}。 */ void setLocale(HttpClassicServerResponse response, Locale locale); + + String getName(); + + String getUrlPattern(); + + int getPriority(); } From dfec108ae5b6a164b150934ecf3ddabd63d03f0f Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Sun, 7 Sep 2025 15:02:01 +0800 Subject: [PATCH 08/25] =?UTF-8?q?=E5=8F=AF=E7=94=A8=E7=9A=84=E5=A4=9A?= =?UTF-8?q?=E6=8F=92=E4=BB=B6=E5=9C=B0=E5=8C=BA=E8=A7=A3=E6=9E=90=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../02-static-plugin/app-assistant/pom.xml | 10 +++ .../controller/AssistantController.java | 5 +- .../fit/example/controller/controller2.java | 15 +++++ .../plugin-default-weather/pom.xml | 5 ++ .../example/DefalutLocaleResolveConfig.java | 39 +++++++++++ .../plugin-other-weather/pom.xml | 5 ++ .../fit/example/OtherLocaleResolveConfig.java | 39 +++++++++++ .../i18n/LocaleResolveFilter.java | 23 ++----- .../i18n/LocaleResolverEntry.java | 40 ------------ .../i18n/LocaleResolverRegistry.java | 65 ++++++++++++------- .../src/main/resources/application.yaml | 4 ++ .../fit-validation-hibernate-jakarta/pom.xml | 6 ++ .../LocaleValidationControllerTest.java | 4 +- .../validation/data/localeResolveConfig.java | 30 --------- .../fit-validation-hibernate-javax/pom.xml | 6 ++ .../LocaleValidationControllerTest.java | 4 +- .../validation/data/localeResolveConfig.java | 30 --------- .../http/util/i18n/DefualtLocaleResolver.java | 12 ++-- .../fit/http/util/i18n/LocaleResolver.java | 4 +- .../i18n/RegisterLocaleResolverException.java | 13 ++++ ...er.java => SimpleLocaleResolveFilter.java} | 8 +-- 21 files changed, 208 insertions(+), 159 deletions(-) create mode 100644 examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/controller2.java create mode 100644 examples/fit-example/02-static-plugin/plugin-default-weather/src/main/java/modelengine/fit/example/DefalutLocaleResolveConfig.java create mode 100644 examples/fit-example/02-static-plugin/plugin-other-weather/src/main/java/modelengine/fit/example/OtherLocaleResolveConfig.java delete mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverEntry.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/resources/application.yaml delete mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java delete mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java create mode 100644 framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java rename framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/{LocaleResolveFilter.java => SimpleLocaleResolveFilter.java} (88%) diff --git a/examples/fit-example/02-static-plugin/app-assistant/pom.xml b/examples/fit-example/02-static-plugin/app-assistant/pom.xml index cf2cba5d0..f38c98a4a 100644 --- a/examples/fit-example/02-static-plugin/app-assistant/pom.xml +++ b/examples/fit-example/02-static-plugin/app-assistant/pom.xml @@ -39,6 +39,16 @@ default-weather-for-static 1.0-SNAPSHOT + + org.fitframework.example + other-weather-for-static + 1.0-SNAPSHOT + + + org.fitframework.plugin + fit-i18n-registry + ${fit.version} + diff --git a/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java b/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java index 7459489f8..0e83c82e9 100644 --- a/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java +++ b/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java @@ -10,6 +10,7 @@ import modelengine.fit.http.annotation.GetMapping; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.util.LocaleContextHolder; /** * 表示控制器。 @@ -30,8 +31,8 @@ public AssistantController(@Fit Weather weather) { * * @return 表示天气信息的 {@link String}。 */ - @GetMapping(path = "/weather") + @GetMapping(path = "/locale") public String getWeather() { - return this.weather.get(); + return LocaleContextHolder.getLocale().getLanguage(); } } diff --git a/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/controller2.java b/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/controller2.java new file mode 100644 index 000000000..80706f0fa --- /dev/null +++ b/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/controller2.java @@ -0,0 +1,15 @@ +package modelengine.fit.example.controller; + +import modelengine.fit.http.annotation.GetMapping; +import modelengine.fit.http.annotation.RequestMapping; +import modelengine.fitframework.annotation.Component; +import modelengine.fitframework.util.LocaleContextHolder; + +@Component +@RequestMapping(path = "/1") +public class controller2 { + @GetMapping(path = "/weather") + public String getWeather() { + return LocaleContextHolder.getLocale().getLanguage(); + } +} diff --git a/examples/fit-example/02-static-plugin/plugin-default-weather/pom.xml b/examples/fit-example/02-static-plugin/plugin-default-weather/pom.xml index 9e4a32576..1d15d875b 100644 --- a/examples/fit-example/02-static-plugin/plugin-default-weather/pom.xml +++ b/examples/fit-example/02-static-plugin/plugin-default-weather/pom.xml @@ -34,6 +34,11 @@ weather-for-static 1.0-SNAPSHOT + + org.fitframework.service + fit-http-classic + ${fit.version} + diff --git a/examples/fit-example/02-static-plugin/plugin-default-weather/src/main/java/modelengine/fit/example/DefalutLocaleResolveConfig.java b/examples/fit-example/02-static-plugin/plugin-default-weather/src/main/java/modelengine/fit/example/DefalutLocaleResolveConfig.java new file mode 100644 index 000000000..ae5c0d078 --- /dev/null +++ b/examples/fit-example/02-static-plugin/plugin-default-weather/src/main/java/modelengine/fit/example/DefalutLocaleResolveConfig.java @@ -0,0 +1,39 @@ +package modelengine.fit.example; + +import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.http.server.HttpClassicServerResponse; +import modelengine.fit.http.util.i18n.DefualtLocaleResolver; +import modelengine.fit.http.util.i18n.LocaleResolver; +import modelengine.fitframework.annotation.Bean; +import modelengine.fitframework.annotation.Component; + +import java.util.Locale; + +@Component +public class DefalutLocaleResolveConfig { + @Bean + public LocaleResolver localeResolver2() { + LocaleResolver localeResolver = new LocaleResolver() { + @Override + public Locale resolveLocale(HttpClassicServerRequest request) { + return Locale.forLanguageTag("en-US"); + } + + @Override + public void setLocale(HttpClassicServerResponse response, Locale locale) { + + } + + @Override + public String getUrlPattern() { + return "/locale"; + } + + @Override + public void setUrlPattern(String urlPattern) { + + } + }; + return localeResolver; + } +} diff --git a/examples/fit-example/02-static-plugin/plugin-other-weather/pom.xml b/examples/fit-example/02-static-plugin/plugin-other-weather/pom.xml index 75d3814a9..719271e44 100644 --- a/examples/fit-example/02-static-plugin/plugin-other-weather/pom.xml +++ b/examples/fit-example/02-static-plugin/plugin-other-weather/pom.xml @@ -34,6 +34,11 @@ weather-for-static 1.0-SNAPSHOT + + org.fitframework.service + fit-http-classic + ${fit.version} + diff --git a/examples/fit-example/02-static-plugin/plugin-other-weather/src/main/java/modelengine/fit/example/OtherLocaleResolveConfig.java b/examples/fit-example/02-static-plugin/plugin-other-weather/src/main/java/modelengine/fit/example/OtherLocaleResolveConfig.java new file mode 100644 index 000000000..c71a51783 --- /dev/null +++ b/examples/fit-example/02-static-plugin/plugin-other-weather/src/main/java/modelengine/fit/example/OtherLocaleResolveConfig.java @@ -0,0 +1,39 @@ +package modelengine.fit.example; + +import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.http.server.HttpClassicServerResponse; +import modelengine.fit.http.util.i18n.DefualtLocaleResolver; +import modelengine.fit.http.util.i18n.LocaleResolver; +import modelengine.fitframework.annotation.Bean; +import modelengine.fitframework.annotation.Component; + +import java.util.Locale; + +@Component +public class OtherLocaleResolveConfig { + @Bean + public LocaleResolver localeResolver1() { + LocaleResolver localeResolver = new LocaleResolver() { + @Override + public Locale resolveLocale(HttpClassicServerRequest request) { + return Locale.forLanguageTag("cn"); + } + + @Override + public void setLocale(HttpClassicServerResponse response, Locale locale) { + + } + + @Override + public String getUrlPattern() { + return "/locale"; + } + + @Override + public void setUrlPattern(String urlPattern) { + + } + }; + return localeResolver; + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java index 0c33a1e62..d28db99f2 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java @@ -5,7 +5,6 @@ import modelengine.fit.http.server.HttpClassicServerResponse; import modelengine.fit.http.server.HttpServerFilter; import modelengine.fit.http.server.HttpServerFilterChain; -import modelengine.fit.http.util.i18n.DefualtLocaleResolver; import modelengine.fit.http.util.i18n.LocaleResolver; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Scope; @@ -23,9 +22,6 @@ */ @Component public class LocaleResolveFilter implements HttpServerFilter { - - private LocaleResolver localeResolver = null; - private List matchPatterns = List.of("/**"); private List mismatchPatterns = List.of(); @@ -37,17 +33,10 @@ public class LocaleResolveFilter implements HttpServerFilter { /** * 构造函数。 * - * @param localeResolver 表示地区解析器的 {@link LocaleResolver}。 - */ - public LocaleResolveFilter(LocaleResolver localeResolver, LocaleResolverRegistry localeResolverRegistry) { - localeResolver = localeResolver; - } - - /** - * 构造函数。 + * @param localeResolverRegistry 表示地区解析器注册中心的 {@link LocaleResolverRegistry}。 */ public LocaleResolveFilter(LocaleResolverRegistry localeResolverRegistry) { - this.localeResolver = new DefualtLocaleResolver(); + this.localeResolverRegistry = localeResolverRegistry; } @Override @@ -77,17 +66,15 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse // 如果参数中带有地区,说明用户想使用新地区执行后续的操作,直接设置地区。 String paramLocale = request.queries().first("locale").orElse(null); Locale responseLocale = null; + // 使用责任链解析 locale + LocaleResolver localeResolver = localeResolverRegistry.dispatch(request); if (paramLocale != null && !paramLocale.trim().isEmpty()) { responseLocale = Locale.forLanguageTag(paramLocale); LocaleContextHolder.setLocaleContext(new LocaleContext(responseLocale)); } // 如果参数中不包含地区,则解析请求所带的地区参数。 else { - // 使用责任链解析locale - Locale locale = this.localeResolverRegistry.resolveLocale(request); - if (locale == null) { - locale = this.localeResolver.resolveLocale(request); // fallback - } + Locale locale = localeResolver.resolveLocale(request); LocaleContextHolder.setLocaleContext(new LocaleContext(locale)); } diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverEntry.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverEntry.java deleted file mode 100644 index b4e722620..000000000 --- a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverEntry.java +++ /dev/null @@ -1,40 +0,0 @@ -package modelengine.fitframework.i18n; - -import modelengine.fit.http.util.i18n.LocaleResolver; - -import java.util.List; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -public class LocaleResolverEntry { - private final LocaleResolver resolver; - private final Pattern urlPattern; - private final int priority; - - public LocaleResolverEntry(LocaleResolver resolver, String urlPattern, int priority) { - this.resolver = resolver; - this.priority = priority; - this.urlPattern = this.compilePattern(urlPattern); - } - - private Pattern compilePattern(String pattern) { - // 支持Ant风格的路径匹配: /api/** -> /api/.* - String regex = pattern - .replace("**", ".*") - .replace("*", "[^/]*") - .replace("?", "."); - return Pattern.compile("^" + regex + "$"); - } - - public boolean matches(String requestPath) { - return urlPattern.matcher(requestPath).matches(); - } - - public int getPriority() { - return priority; - } - - public LocaleResolver getResolver() { - return resolver; - } -} diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java index 4c3482163..f6fdc9796 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java +++ b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java @@ -1,10 +1,14 @@ package modelengine.fitframework.i18n; +import static modelengine.fitframework.inspection.Validation.notBlank; +import static modelengine.fitframework.inspection.Validation.notNull; + import modelengine.fit.http.server.HttpClassicServerRequest; -import modelengine.fit.http.server.HttpClassicServerResponse; import modelengine.fit.http.server.dispatch.MappingTree; import modelengine.fit.http.server.dispatch.support.DefaultMappingTree; +import modelengine.fit.http.util.i18n.DefualtLocaleResolver; import modelengine.fit.http.util.i18n.LocaleResolver; +import modelengine.fit.http.util.i18n.RegisterLocaleResolverException; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.ioc.BeanContainer; import modelengine.fitframework.ioc.BeanFactory; @@ -18,6 +22,7 @@ import java.util.stream.Collectors; import modelengine.fitframework.resource.UrlUtils; import modelengine.fitframework.util.OptionalUtils; +import modelengine.fitframework.util.StringUtils; import modelengine.fitframework.util.wildcard.PathPattern; import modelengine.fitframework.util.wildcard.Pattern; @@ -27,31 +32,48 @@ public class LocaleResolverRegistry implements PluginStartedObserver, PluginStop // 参考DefaultHttpDispatcher的三层结构 private final Map noPathVariableResolvers = new ConcurrentHashMap<>(); - private final MappingTree pathVariableResolvers = new DefaultMappingTree<>(); + private final Map> pathVariableResolvers = new ConcurrentHashMap<>(); private final Map wildcardResolvers = new ConcurrentHashMap<>(); + private final LocaleResolver defaultLocaleResolver = new DefualtLocaleResolver(); + + public LocaleResolverRegistry() { + // 与 DefaultHttpDispatcher 保持一致,使用 ConcurrentHashMap 提供线程安全。 + this.pathVariableResolvers.put(DefaultMappingTree.PATH_SEPARATOR, new DefaultMappingTree<>()); + } - public void register(String pluginName, LocaleResolver resolver, String urlPattern) { - String pathPattern = MappingTree.convertToMatchedPathPattern(urlPattern); + public void register(LocaleResolver resolver) { + notNull(resolver, "The locale resolver cannot be null."); + String pathPattern = MappingTree.convertToMatchedPathPattern(resolver.getUrlPattern()); + notBlank(pathPattern, "The path pattern cannot be blank."); + LocaleResolver preResolver; if (pathPattern.contains("**")) { - wildcardResolvers.put(pathPattern, resolver); + preResolver = wildcardResolvers.put(pathPattern, resolver); } else if (pathPattern.contains("*")) { - pathVariableResolvers.register(pathPattern, resolver); + preResolver = pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR) + .register(pathPattern, resolver) + .orElse(null); + ; } else { - noPathVariableResolvers.put(pathPattern, resolver); + preResolver = noPathVariableResolvers.put(pathPattern, resolver); + } + if (preResolver != null) { + String message = StringUtils.format("Locale resolver has been registered. [pattern={0}]", pathPattern); + throw new RegisterLocaleResolverException(message); } } - public void unregister(String pluginName, List urlPatterns) { - for (String pattern : urlPatterns) { - String pathPattern = MappingTree.convertToMatchedPathPattern(pattern); - if (pathPattern.contains("**")) { - wildcardResolvers.remove(pathPattern); - } else if (pathPattern.contains("*")) { - pathVariableResolvers.unregister(pathPattern); - } else { - noPathVariableResolvers.remove(pathPattern); - } + public void unregister(LocaleResolver resolver) { + notNull(resolver, "The locale resolver cannot be null."); + String pathPattern = MappingTree.convertToMatchedPathPattern(resolver.getUrlPattern()); + notBlank(pathPattern, "The path pattern cannot be blank."); + if (pathPattern.contains("**")) { + wildcardResolvers.remove(pathPattern); + } else if (pathPattern.contains("*")) { + pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR).unregister(pathPattern); + ; + } else { + noPathVariableResolvers.remove(pathPattern); } } @@ -59,8 +81,7 @@ public LocaleResolver dispatch(HttpClassicServerRequest request) { String path = UrlUtils.decodePath(request.path()); return (LocaleResolver) OptionalUtils.get(() -> selectFromNoPathVariableResolvers(path)) .orElse(() -> selectFromPathVariableResolvers(path)) - .orElse(() -> selectFromWildcardResolvers(path)) - .orElse(null); + .orElse(() -> selectFromWildcardResolvers(path)).orDefault(this.defaultLocaleResolver); } private Optional selectFromNoPathVariableResolvers(String path) { @@ -69,7 +90,7 @@ private Optional selectFromNoPathVariableResolvers(String path) } private Optional selectFromPathVariableResolvers(String path) { - return pathVariableResolvers.search(path); + return pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR).search(path); } private Optional selectFromWildcardResolvers(String path) { @@ -90,7 +111,7 @@ public void onPluginStarted(Plugin plugin) { .map(BeanFactory::get) .collect(Collectors.toList()); for(LocaleResolver localeResolver : localeResolvers) { - this.register(localeResolver.getName(),localeResolver,localeResolver.getUrlPattern(),localeResolver.getPriority()); + this.register(localeResolver); } } @@ -102,7 +123,7 @@ public void onPluginStopping(Plugin plugin) { .map(BeanFactory::get) .collect(Collectors.toList()); for(LocaleResolver localeResolver : localeResolvers) { - this.unregister(localeResolver.getName()); + this.unregister(localeResolver); } } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/resources/application.yaml b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/resources/application.yaml new file mode 100644 index 000000000..9b8d7cc1a --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/resources/application.yaml @@ -0,0 +1,4 @@ +fit: + beans: + packages: + - 'modelengine.fitframework.i18n' diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml index 41d45c5c1..fc6a9b9a4 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml @@ -61,6 +61,12 @@ h2 test + + org.fitframework.plugin + fit-i18n-registry + ${project.version} + test + diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 1adae14a1..66a80859f 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -10,6 +10,8 @@ import modelengine.fit.http.entity.Entity; import modelengine.fit.http.entity.ObjectEntity; import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.i18n.LocaleResolveFilter; +import modelengine.fitframework.i18n.LocaleResolverRegistry; import modelengine.fitframework.test.annotation.MvcTest; import modelengine.fitframework.test.domain.mvc.MockMvc; import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; @@ -32,7 +34,7 @@ * @author 阮睿 * @since 2025-08-01 */ -@MvcTest(classes = {LocaleValidationController.class}) +@MvcTest(classes = {LocaleValidationController.class, LocaleResolverRegistry.class, LocaleResolveFilter.class}) @DisplayName("测试地区化验证消息功能") public class LocaleValidationControllerTest { @Fit diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java deleted file mode 100644 index cea6de9b2..000000000 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fit.http.util.i18n.LocaleResolveFilter; -import modelengine.fitframework.annotation.Bean; -import modelengine.fitframework.annotation.Component; - -/** - * 表示 {@link LocaleResolveFilter} 的配置类。 - * - * @author 阮睿 - * @since 2025-08-01 - */ -@Component -public class localeResolveConfig { - /** - * 注册一个 {@link LocaleResolveFilter} 的 bean。 - * - * @return 返回一个 {@link LocaleResolveFilter} 的实例。 - */ - @Bean - public LocaleResolveFilter localeResolveFilter() { - return new LocaleResolveFilter(); - } -} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml index 0d0e43be2..0a19fa35e 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml @@ -61,6 +61,12 @@ h2 test + + org.fitframework.plugin + fit-i18n-registry + ${project.version} + test + diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 1adae14a1..66a80859f 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -10,6 +10,8 @@ import modelengine.fit.http.entity.Entity; import modelengine.fit.http.entity.ObjectEntity; import modelengine.fitframework.annotation.Fit; +import modelengine.fitframework.i18n.LocaleResolveFilter; +import modelengine.fitframework.i18n.LocaleResolverRegistry; import modelengine.fitframework.test.annotation.MvcTest; import modelengine.fitframework.test.domain.mvc.MockMvc; import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; @@ -32,7 +34,7 @@ * @author 阮睿 * @since 2025-08-01 */ -@MvcTest(classes = {LocaleValidationController.class}) +@MvcTest(classes = {LocaleValidationController.class, LocaleResolverRegistry.class, LocaleResolveFilter.class}) @DisplayName("测试地区化验证消息功能") public class LocaleValidationControllerTest { @Fit diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java deleted file mode 100644 index cea6de9b2..000000000 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/localeResolveConfig.java +++ /dev/null @@ -1,30 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.validation.data; - -import modelengine.fit.http.util.i18n.LocaleResolveFilter; -import modelengine.fitframework.annotation.Bean; -import modelengine.fitframework.annotation.Component; - -/** - * 表示 {@link LocaleResolveFilter} 的配置类。 - * - * @author 阮睿 - * @since 2025-08-01 - */ -@Component -public class localeResolveConfig { - /** - * 注册一个 {@link LocaleResolveFilter} 的 bean。 - * - * @return 返回一个 {@link LocaleResolveFilter} 的实例。 - */ - @Bean - public LocaleResolveFilter localeResolveFilter() { - return new LocaleResolveFilter(); - } -} diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index 796cff7ff..1de319726 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -24,6 +24,7 @@ public class DefualtLocaleResolver implements LocaleResolver { private String cookieDomain = DEFAULT_COOKIE_DOMAIN; private String cookiePath = DEFAULT_COOKIE_PATH; private Locale defaultLocale = Locale.getDefault(); + private String urlPattern = "/**"; @Override public Locale resolveLocale(HttpClassicServerRequest request) { @@ -61,19 +62,14 @@ public void setLocale(HttpClassicServerResponse response, Locale locale) { } } - @Override - public String getName() { - return "DefualtLocaleResolver"; - } - @Override public String getUrlPattern() { - return "/**"; + return this.urlPattern; } @Override - public int getPriority() { - return 0; + public void setUrlPattern(String urlPattern) { + this.urlPattern = urlPattern; } /** diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java index 3eeb50974..70de01831 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java @@ -39,9 +39,7 @@ public interface LocaleResolver { */ void setLocale(HttpClassicServerResponse response, Locale locale); - String getName(); - String getUrlPattern(); - int getPriority(); + void setUrlPattern(String urlPattern); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java new file mode 100644 index 000000000..532af27c4 --- /dev/null +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java @@ -0,0 +1,13 @@ +package modelengine.fit.http.util.i18n; + +import modelengine.fit.http.server.HttpServerException; + +public class RegisterLocaleResolverException extends HttpServerException { + public RegisterLocaleResolverException(String message) { + super(message); + } + + public RegisterLocaleResolverException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java similarity index 88% rename from framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java rename to framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java index 86d8ab5f8..fa74441f0 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java @@ -15,12 +15,12 @@ import java.util.Locale; /** - * 地区解析过滤器。 + * 简单地区解析过滤器,只使用一种 {@link LocaleResolver} 进行地区解析,多插件同时配置 {@link SimpleLocaleResolveFilter} 可能会引发不可预知的行为。 * * @author 阮睿 * @since 2025-08-01 */ -public class LocaleResolveFilter implements HttpServerFilter { +public class SimpleLocaleResolveFilter implements HttpServerFilter { private LocaleResolver localeResolver = null; @@ -35,14 +35,14 @@ public class LocaleResolveFilter implements HttpServerFilter { * * @param localeResolver 表示地区解析器的 {@link LocaleResolver}。 */ - public LocaleResolveFilter(LocaleResolver localeResolver) { + public SimpleLocaleResolveFilter(LocaleResolver localeResolver) { localeResolver = localeResolver; } /** * 默认构造函数。 */ - public LocaleResolveFilter() { + public SimpleLocaleResolveFilter() { this.localeResolver = new DefualtLocaleResolver(); } From c7afa6568bd81a7917e4c11b9947dd02fad89741 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Sun, 7 Sep 2025 16:19:35 +0800 Subject: [PATCH 09/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../i18n/LocaleResolveFilter.java | 14 ++- .../i18n/LocaleResolverRegistry.java | 89 ++++++++++++++++--- .../http/util/i18n/DefualtLocaleResolver.java | 12 +-- .../fit/http/util/i18n/LocaleResolver.java | 20 +++-- .../i18n/RegisterLocaleResolverException.java | 23 +++++ .../util/i18n/SimpleLocaleResolveFilter.java | 13 ++- .../fitframework/util/LocaleContext.java | 6 +- .../util/LocaleContextHolder.java | 6 +- 8 files changed, 141 insertions(+), 42 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java index d28db99f2..6d456517a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.i18n; import modelengine.fit.http.server.DoHttpServerFilterException; @@ -51,12 +57,12 @@ public int priority() { @Override public List matchPatterns() { - return matchPatterns; + return this.matchPatterns; } @Override public List mismatchPatterns() { - return mismatchPatterns; + return this.mismatchPatterns; } @Override @@ -67,7 +73,7 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse String paramLocale = request.queries().first("locale").orElse(null); Locale responseLocale = null; // 使用责任链解析 locale - LocaleResolver localeResolver = localeResolverRegistry.dispatch(request); + LocaleResolver localeResolver = this.localeResolverRegistry.dispatch(request); if (paramLocale != null && !paramLocale.trim().isEmpty()) { responseLocale = Locale.forLanguageTag(paramLocale); LocaleContextHolder.setLocaleContext(new LocaleContext(responseLocale)); @@ -91,6 +97,6 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse @Override public Scope scope() { - return scope; + return this.scope; } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java index f6fdc9796..db63a4d02 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java +++ b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java @@ -1,3 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.i18n; import static modelengine.fitframework.inspection.Validation.notBlank; @@ -15,47 +21,62 @@ import modelengine.fitframework.plugin.Plugin; import modelengine.fitframework.plugin.PluginStartedObserver; import modelengine.fitframework.plugin.PluginStoppingObserver; + import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; + import modelengine.fitframework.resource.UrlUtils; import modelengine.fitframework.util.OptionalUtils; import modelengine.fitframework.util.StringUtils; import modelengine.fitframework.util.wildcard.PathPattern; import modelengine.fitframework.util.wildcard.Pattern; +/** + * 地区解析器注册中心 + * + * @author 阮睿 + * @since 2025-09-07 + */ @Component public class LocaleResolverRegistry implements PluginStartedObserver, PluginStoppingObserver { private static final char PATH_SEPARATOR = '/'; - // 参考DefaultHttpDispatcher的三层结构 + // 参考 DefaultHttpDispatcher 的三层结构 private final Map noPathVariableResolvers = new ConcurrentHashMap<>(); private final Map> pathVariableResolvers = new ConcurrentHashMap<>(); private final Map wildcardResolvers = new ConcurrentHashMap<>(); private final LocaleResolver defaultLocaleResolver = new DefualtLocaleResolver(); + /** + * 构造函数。 + */ public LocaleResolverRegistry() { // 与 DefaultHttpDispatcher 保持一致,使用 ConcurrentHashMap 提供线程安全。 this.pathVariableResolvers.put(DefaultMappingTree.PATH_SEPARATOR, new DefaultMappingTree<>()); } + /** + * 注册地区解析器。 + * + * @param resolver 表示将要被注册地区解析器的 {@link LocaleResolver}。 + */ public void register(LocaleResolver resolver) { notNull(resolver, "The locale resolver cannot be null."); String pathPattern = MappingTree.convertToMatchedPathPattern(resolver.getUrlPattern()); notBlank(pathPattern, "The path pattern cannot be blank."); LocaleResolver preResolver; if (pathPattern.contains("**")) { - preResolver = wildcardResolvers.put(pathPattern, resolver); + preResolver = this.wildcardResolvers.put(pathPattern, resolver); } else if (pathPattern.contains("*")) { - preResolver = pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR) + preResolver = this.pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR) .register(pathPattern, resolver) .orElse(null); - ; } else { - preResolver = noPathVariableResolvers.put(pathPattern, resolver); + preResolver = this.noPathVariableResolvers.put(pathPattern, resolver); } if (preResolver != null) { String message = StringUtils.format("Locale resolver has been registered. [pattern={0}]", pathPattern); @@ -63,38 +84,68 @@ public void register(LocaleResolver resolver) { } } + /** + * 取消注册地区解析器。 + * + * @param resolver 表示待取消注册地区解析器的 {@link LocaleResolver}。 + */ public void unregister(LocaleResolver resolver) { notNull(resolver, "The locale resolver cannot be null."); String pathPattern = MappingTree.convertToMatchedPathPattern(resolver.getUrlPattern()); notBlank(pathPattern, "The path pattern cannot be blank."); if (pathPattern.contains("**")) { - wildcardResolvers.remove(pathPattern); + this.wildcardResolvers.remove(pathPattern); } else if (pathPattern.contains("*")) { - pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR).unregister(pathPattern); + this.pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR).unregister(pathPattern); ; } else { - noPathVariableResolvers.remove(pathPattern); + this.noPathVariableResolvers.remove(pathPattern); } } + /** + * 分派地区解析器。 + * + * @param request 表示用于查找对应 {@link LocaleResolver} 请求的 {@link HttpClassicServerRequest}。 + * @return 返回匹配的 {@link LocaleResolver}。 + */ public LocaleResolver dispatch(HttpClassicServerRequest request) { String path = UrlUtils.decodePath(request.path()); return (LocaleResolver) OptionalUtils.get(() -> selectFromNoPathVariableResolvers(path)) .orElse(() -> selectFromPathVariableResolvers(path)) - .orElse(() -> selectFromWildcardResolvers(path)).orDefault(this.defaultLocaleResolver); + .orElse(() -> selectFromWildcardResolvers(path)) + .orDefault(this.defaultLocaleResolver); } + /** + * 从无路径参数的解析器中查找匹配的解析器。 + * + * @param path 表示待匹配路径的 {@link String}。 + * @return 表示匹配对应路径解析器的 {@link Optional}{@code <}{@link LocaleResolver}{@code >}。。 + */ private Optional selectFromNoPathVariableResolvers(String path) { - LocaleResolver resolver = noPathVariableResolvers.get(path); + LocaleResolver resolver = this.noPathVariableResolvers.get(path); return Optional.ofNullable(resolver); } + /** + * 从路径参数的解析器中查找匹配的解析器。 + * + * @param path 待匹配路径的 {@link String}。 + * @return 匹配对应路径解析器的 {@link Optional}{@code <}{@link LocaleResolver}{@code >}。 + */ private Optional selectFromPathVariableResolvers(String path) { - return pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR).search(path); + return this.pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR).search(path); } + /** + * 从通配符的解析器中查找匹配的解析器。 + * + * @param path 待匹配路径的 {@link String}。 + * @return 匹配对应路径解析器的 {@link Optional}{@code <}{@link LocaleResolver}{@code >}。 + */ private Optional selectFromWildcardResolvers(String path) { - for (Map.Entry entry : wildcardResolvers.entrySet()) { + for (Map.Entry entry : this.wildcardResolvers.entrySet()) { PathPattern pattern = Pattern.forPath(entry.getKey(), PATH_SEPARATOR); if (pattern.matches(path)) { return Optional.of(entry.getValue()); @@ -103,6 +154,11 @@ private Optional selectFromWildcardResolvers(String path) { return Optional.empty(); } + /** + * 当插件启动时,注册插件中的地区解析器。 + * + * @param plugin 待注册插件的 {@link Plugin}。 + */ @Override public void onPluginStarted(Plugin plugin) { BeanContainer container = plugin.container(); @@ -110,11 +166,16 @@ public void onPluginStarted(Plugin plugin) { .stream() .map(BeanFactory::get) .collect(Collectors.toList()); - for(LocaleResolver localeResolver : localeResolvers) { + for (LocaleResolver localeResolver : localeResolvers) { this.register(localeResolver); } } + /** + * 当插件停止时,取消注册插件中的地区解析器。 + * + * @param plugin 待取消注册插件的 {@link Plugin}。 + */ @Override public void onPluginStopping(Plugin plugin) { BeanContainer container = plugin.container(); @@ -122,7 +183,7 @@ public void onPluginStopping(Plugin plugin) { .stream() .map(BeanFactory::get) .collect(Collectors.toList()); - for(LocaleResolver localeResolver : localeResolvers) { + for (LocaleResolver localeResolver : localeResolvers) { this.unregister(localeResolver); } } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index 1de319726..ad85676ab 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -51,14 +51,14 @@ public void setLocale(HttpClassicServerResponse response, Locale locale) { if (locale != null) { response.cookies() .add(Cookie.builder() - .name(cookieName) + .name(this.cookieName) .value(locale.toLanguageTag()) - .maxAge(cookieMaxAge) - .domain(cookieDomain) - .path(cookiePath) + .maxAge(this.cookieMaxAge) + .domain(this.cookieDomain) + .path(this.cookiePath) .build()); } else { - response.cookies().add(Cookie.builder().name(cookieName).maxAge(0).build()); + response.cookies().add(Cookie.builder().name(this.cookieName).maxAge(0).build()); } } @@ -75,7 +75,7 @@ public void setUrlPattern(String urlPattern) { /** * 设置存储地区信息的 Cookie 名称。 * - * @param cookieName 表示将要设置的 Cookie 名称 {@link String}。 + * @param cookieName 表示将要设置 Cookie 名称的 {@link String}。 */ public void setCookieName(String cookieName) { this.cookieName = cookieName; diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java index 70de01831..dba6a1781 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java @@ -12,7 +12,7 @@ import java.util.Locale; /** - * 地区解析器接口,用于从HTTP请求中解析用户的地区设置。 + * 地区解析器接口,用于从 HTTP 请求中解析用户的地区设置。 * * @author 阮睿 * @since 2025-08-01 @@ -26,20 +26,30 @@ public interface LocaleResolver { /** * 解析用户的地区设置。 * - * @param request 表示待解析的HTTP请求 {@link HttpClassicServerRequest}。 - * @return 表示解析出来的地区信息 {@link Locale}。 + * @param request 表示待解析 HTTP 请求的 {@link HttpClassicServerRequest}。 + * @return 表示解析出来地区信息的 {@link Locale}。 */ Locale resolveLocale(HttpClassicServerRequest request); /** * 设置地区到返回响应中。 * - * @param response 表示将要设置地区的HTTP响应 {@link HttpClassicServerResponse}。 - * @param locale 表示要设置的地区 {@link Locale}。 + * @param response 表示将要设置地区 HTTP 响应的 {@link HttpClassicServerResponse}。 + * @param locale 表示要设置地区的 {@link Locale}。 */ void setLocale(HttpClassicServerResponse response, Locale locale); + /** + * 获取地区解析器的 URL 模式。 + * + * @return 获取地区解析器 URL 模式的 {@link String}。 + */ String getUrlPattern(); + /** + * 设置地区解析器的 URL 模式。 + * + * @param urlPattern 表示待设置 URL 模式的 {@link String}。 + */ void setUrlPattern(String urlPattern); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java index 532af27c4..6d06fb7d2 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java @@ -1,12 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fit.http.util.i18n; import modelengine.fit.http.server.HttpServerException; +/** + * 表示注册 {@link LocaleResolver} 时出现的异常。 + * + * @author 阮睿 + * @since 2025-09-07 + */ public class RegisterLocaleResolverException extends HttpServerException { + /** + * 通过异常消息来实例化 {@link RegisterLocaleResolverException}。 + * + * @param message 表示异常消息的 {@link String}。 + */ public RegisterLocaleResolverException(String message) { super(message); } + /** + * 通过异常消息和异常原因来实例化 {@link RegisterLocaleResolverException}。 + * + * @param message 表示异常消息的 {@link String}。 + * @param cause 表示异常原因的 {@link Throwable}。 + */ public RegisterLocaleResolverException(String message, Throwable cause) { super(message, cause); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java index fa74441f0..ce37dd34e 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java @@ -21,7 +21,6 @@ * @since 2025-08-01 */ public class SimpleLocaleResolveFilter implements HttpServerFilter { - private LocaleResolver localeResolver = null; private List matchPatterns = List.of("/**"); @@ -36,7 +35,7 @@ public class SimpleLocaleResolveFilter implements HttpServerFilter { * @param localeResolver 表示地区解析器的 {@link LocaleResolver}。 */ public SimpleLocaleResolveFilter(LocaleResolver localeResolver) { - localeResolver = localeResolver; + this.localeResolver = localeResolver; } /** @@ -58,12 +57,12 @@ public int priority() { @Override public List matchPatterns() { - return matchPatterns; + return this.matchPatterns; } @Override public List mismatchPatterns() { - return mismatchPatterns; + return this.mismatchPatterns; } @Override @@ -79,7 +78,7 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse } // 如果参数中不包含地区,则解析请求所带的地区参数。 else { - Locale locale = localeResolver.resolveLocale(request); + Locale locale = this.localeResolver.resolveLocale(request); LocaleContextHolder.setLocaleContext(new LocaleContext(locale)); } @@ -87,7 +86,7 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse chain.doFilter(request, response); // responseLocale 是用户期望设置的地区,不受 server 端处理的影响。 - localeResolver.setLocale(response, responseLocale); + this.localeResolver.setLocale(response, responseLocale); } finally { LocaleContextHolder.clear(); } @@ -96,6 +95,6 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse @Override public Scope scope() { - return scope; + return this.scope; } } diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java index 647ae1b48..719471225 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java @@ -20,7 +20,7 @@ public class LocaleContext { /** * 构造函数。 * - * @param locale 地区信息 {@link Locale}。 + * @param locale 表示要设置地区信息的 {@link Locale}。 */ public LocaleContext(Locale locale) { this.locale = locale; @@ -29,9 +29,9 @@ public LocaleContext(Locale locale) { /** * 获取上下文中的地区信息。 * - * @return 当前上下文中存储的地区信息 {@link Locale}。 + * @return 表示当前上下文中存储的地区信息的 {@link Locale}。 */ public Locale getLocale() { - return locale; + return this.locale; } } \ No newline at end of file diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java index 2683a1f4d..2217b232e 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java @@ -20,7 +20,7 @@ public class LocaleContextHolder { /** * 设置当前线程的地区上下文。 * - * @param localeContext 表示将要存储在当前线程的地区上下文 {@link LocaleContext}。 + * @param localeContext 表示将要存储在当前线程地区上下文的 {@link LocaleContext}。 */ public static void setLocaleContext(LocaleContext localeContext) { LOCALE_CONTEXT_HOLDER.set(localeContext); @@ -29,7 +29,7 @@ public static void setLocaleContext(LocaleContext localeContext) { /** * 获取当前线程的地区上下文。 * - * @return 表示当前线程的地区上下文 {@link LocaleContext}。 + * @return 表示当前线程地区上下文的 {@link LocaleContext}。 */ public static LocaleContext getLocaleContext() { return LOCALE_CONTEXT_HOLDER.get(); @@ -38,7 +38,7 @@ public static LocaleContext getLocaleContext() { /** * 获取当前线程的地区。 * - * @return 表示当前线程上下文存储的地区信息 {@link Locale}。 + * @return 表示当前线程上下文存储地区信息的 {@link Locale}。 */ public static Locale getLocale() { LocaleContext context = getLocaleContext(); From c82354c2bfe46be00f52aa6605c63fa7690f6d41 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Sun, 7 Sep 2025 17:40:36 +0800 Subject: [PATCH 10/25] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E6=A0=B7=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../02-static-plugin/app-assistant/pom.xml | 10 ----- .../controller/AssistantController.java | 5 +-- .../fit/example/controller/controller2.java | 15 ------- .../plugin-default-weather/pom.xml | 5 --- .../example/DefalutLocaleResolveConfig.java | 39 ------------------- .../plugin-other-weather/pom.xml | 5 --- .../fit/example/OtherLocaleResolveConfig.java | 39 ------------------- 7 files changed, 2 insertions(+), 116 deletions(-) delete mode 100644 examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/controller2.java delete mode 100644 examples/fit-example/02-static-plugin/plugin-default-weather/src/main/java/modelengine/fit/example/DefalutLocaleResolveConfig.java delete mode 100644 examples/fit-example/02-static-plugin/plugin-other-weather/src/main/java/modelengine/fit/example/OtherLocaleResolveConfig.java diff --git a/examples/fit-example/02-static-plugin/app-assistant/pom.xml b/examples/fit-example/02-static-plugin/app-assistant/pom.xml index f38c98a4a..cf2cba5d0 100644 --- a/examples/fit-example/02-static-plugin/app-assistant/pom.xml +++ b/examples/fit-example/02-static-plugin/app-assistant/pom.xml @@ -39,16 +39,6 @@ default-weather-for-static 1.0-SNAPSHOT - - org.fitframework.example - other-weather-for-static - 1.0-SNAPSHOT - - - org.fitframework.plugin - fit-i18n-registry - ${fit.version} - diff --git a/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java b/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java index 0e83c82e9..7459489f8 100644 --- a/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java +++ b/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/AssistantController.java @@ -10,7 +10,6 @@ import modelengine.fit.http.annotation.GetMapping; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.annotation.Fit; -import modelengine.fitframework.util.LocaleContextHolder; /** * 表示控制器。 @@ -31,8 +30,8 @@ public AssistantController(@Fit Weather weather) { * * @return 表示天气信息的 {@link String}。 */ - @GetMapping(path = "/locale") + @GetMapping(path = "/weather") public String getWeather() { - return LocaleContextHolder.getLocale().getLanguage(); + return this.weather.get(); } } diff --git a/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/controller2.java b/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/controller2.java deleted file mode 100644 index 80706f0fa..000000000 --- a/examples/fit-example/02-static-plugin/app-assistant/src/main/java/modelengine/fit/example/controller/controller2.java +++ /dev/null @@ -1,15 +0,0 @@ -package modelengine.fit.example.controller; - -import modelengine.fit.http.annotation.GetMapping; -import modelengine.fit.http.annotation.RequestMapping; -import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.util.LocaleContextHolder; - -@Component -@RequestMapping(path = "/1") -public class controller2 { - @GetMapping(path = "/weather") - public String getWeather() { - return LocaleContextHolder.getLocale().getLanguage(); - } -} diff --git a/examples/fit-example/02-static-plugin/plugin-default-weather/pom.xml b/examples/fit-example/02-static-plugin/plugin-default-weather/pom.xml index 1d15d875b..9e4a32576 100644 --- a/examples/fit-example/02-static-plugin/plugin-default-weather/pom.xml +++ b/examples/fit-example/02-static-plugin/plugin-default-weather/pom.xml @@ -34,11 +34,6 @@ weather-for-static 1.0-SNAPSHOT - - org.fitframework.service - fit-http-classic - ${fit.version} - diff --git a/examples/fit-example/02-static-plugin/plugin-default-weather/src/main/java/modelengine/fit/example/DefalutLocaleResolveConfig.java b/examples/fit-example/02-static-plugin/plugin-default-weather/src/main/java/modelengine/fit/example/DefalutLocaleResolveConfig.java deleted file mode 100644 index ae5c0d078..000000000 --- a/examples/fit-example/02-static-plugin/plugin-default-weather/src/main/java/modelengine/fit/example/DefalutLocaleResolveConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -package modelengine.fit.example; - -import modelengine.fit.http.server.HttpClassicServerRequest; -import modelengine.fit.http.server.HttpClassicServerResponse; -import modelengine.fit.http.util.i18n.DefualtLocaleResolver; -import modelengine.fit.http.util.i18n.LocaleResolver; -import modelengine.fitframework.annotation.Bean; -import modelengine.fitframework.annotation.Component; - -import java.util.Locale; - -@Component -public class DefalutLocaleResolveConfig { - @Bean - public LocaleResolver localeResolver2() { - LocaleResolver localeResolver = new LocaleResolver() { - @Override - public Locale resolveLocale(HttpClassicServerRequest request) { - return Locale.forLanguageTag("en-US"); - } - - @Override - public void setLocale(HttpClassicServerResponse response, Locale locale) { - - } - - @Override - public String getUrlPattern() { - return "/locale"; - } - - @Override - public void setUrlPattern(String urlPattern) { - - } - }; - return localeResolver; - } -} diff --git a/examples/fit-example/02-static-plugin/plugin-other-weather/pom.xml b/examples/fit-example/02-static-plugin/plugin-other-weather/pom.xml index 719271e44..75d3814a9 100644 --- a/examples/fit-example/02-static-plugin/plugin-other-weather/pom.xml +++ b/examples/fit-example/02-static-plugin/plugin-other-weather/pom.xml @@ -34,11 +34,6 @@ weather-for-static 1.0-SNAPSHOT - - org.fitframework.service - fit-http-classic - ${fit.version} - diff --git a/examples/fit-example/02-static-plugin/plugin-other-weather/src/main/java/modelengine/fit/example/OtherLocaleResolveConfig.java b/examples/fit-example/02-static-plugin/plugin-other-weather/src/main/java/modelengine/fit/example/OtherLocaleResolveConfig.java deleted file mode 100644 index c71a51783..000000000 --- a/examples/fit-example/02-static-plugin/plugin-other-weather/src/main/java/modelengine/fit/example/OtherLocaleResolveConfig.java +++ /dev/null @@ -1,39 +0,0 @@ -package modelengine.fit.example; - -import modelengine.fit.http.server.HttpClassicServerRequest; -import modelengine.fit.http.server.HttpClassicServerResponse; -import modelengine.fit.http.util.i18n.DefualtLocaleResolver; -import modelengine.fit.http.util.i18n.LocaleResolver; -import modelengine.fitframework.annotation.Bean; -import modelengine.fitframework.annotation.Component; - -import java.util.Locale; - -@Component -public class OtherLocaleResolveConfig { - @Bean - public LocaleResolver localeResolver1() { - LocaleResolver localeResolver = new LocaleResolver() { - @Override - public Locale resolveLocale(HttpClassicServerRequest request) { - return Locale.forLanguageTag("cn"); - } - - @Override - public void setLocale(HttpClassicServerResponse response, Locale locale) { - - } - - @Override - public String getUrlPattern() { - return "/locale"; - } - - @Override - public void setUrlPattern(String urlPattern) { - - } - }; - return localeResolver; - } -} From 956948e09359db48e99c170449b0a0ef65424fc5 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 9 Sep 2025 11:09:38 +0800 Subject: [PATCH 11/25] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/fit-i18n-registry/pom.xml | 77 ------- .../i18n/LocaleResolveFilter.java | 102 ---------- .../i18n/LocaleResolverRegistry.java | 190 ------------------ .../src/main/resources/application.yaml | 4 - .../LocaleContextMessageInterpolator.java | 2 +- .../LocaleValidationControllerTest.java | 4 +- .../data/LocaleResolveFilterConfig.java | 13 ++ .../LocaleContextMessageInterpolator.java | 2 +- .../LocaleValidationControllerTest.java | 4 +- .../data/LocaleResolveFilterConfig.java | 13 ++ .../fit/java/fit-builtin/plugins/pom.xml | 1 - .../http/util/i18n/DefualtLocaleResolver.java | 12 -- ...veFilter.java => LocaleResolveFilter.java} | 12 +- .../fit/http/util/i18n/LocaleResolver.java | 14 -- .../i18n/RegisterLocaleResolverException.java | 36 ---- .../util/{ => i18n}/LocaleContext.java | 2 +- .../util/{ => i18n}/LocaleContextHolder.java | 2 +- 17 files changed, 38 insertions(+), 452 deletions(-) delete mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/pom.xml delete mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java delete mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java delete mode 100644 framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/resources/application.yaml create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java create mode 100644 framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java rename framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/{SimpleLocaleResolveFilter.java => LocaleResolveFilter.java} (87%) delete mode 100644 framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java rename framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/{ => i18n}/LocaleContext.java (95%) rename framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/{ => i18n}/LocaleContextHolder.java (97%) diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/pom.xml deleted file mode 100644 index 3fe7c43c7..000000000 --- a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/pom.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - 4.0.0 - - - org.fitframework.plugin - fit-plugin-parent - 3.6.0-SNAPSHOT - - - fit-i18n-registry - - FIT i18n Registry - - FIT Framework Service provide locale resolver registry. - - https://github.com/ModelEngine-Group/fit-framework - - - - - org.fitframework - fit-api - - - org.fitframework - fit-util - - - - - org.fitframework.service - fit-http-classic - - - - - org.junit.jupiter - junit-jupiter - test - - - org.mockito - mockito-core - test - - - org.assertj - assertj-core - test - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - - - package - - - - - - - run - - - - - - - diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java deleted file mode 100644 index 6d456517a..000000000 --- a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolveFilter.java +++ /dev/null @@ -1,102 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.i18n; - -import modelengine.fit.http.server.DoHttpServerFilterException; -import modelengine.fit.http.server.HttpClassicServerRequest; -import modelengine.fit.http.server.HttpClassicServerResponse; -import modelengine.fit.http.server.HttpServerFilter; -import modelengine.fit.http.server.HttpServerFilterChain; -import modelengine.fit.http.util.i18n.LocaleResolver; -import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.annotation.Scope; -import modelengine.fitframework.util.LocaleContext; -import modelengine.fitframework.util.LocaleContextHolder; - -import java.util.List; -import java.util.Locale; - -/** - * 地区解析过滤器。 - * - * @author 阮睿 - * @since 2025-08-01 - */ -@Component -public class LocaleResolveFilter implements HttpServerFilter { - private List matchPatterns = List.of("/**"); - - private List mismatchPatterns = List.of(); - - private Scope scope = Scope.GLOBAL; - - private LocaleResolverRegistry localeResolverRegistry; - - /** - * 构造函数。 - * - * @param localeResolverRegistry 表示地区解析器注册中心的 {@link LocaleResolverRegistry}。 - */ - public LocaleResolveFilter(LocaleResolverRegistry localeResolverRegistry) { - this.localeResolverRegistry = localeResolverRegistry; - } - - @Override - public String name() { - return "LocaleResolveFilter"; - } - - @Override - public int priority() { - return 0; - } - - @Override - public List matchPatterns() { - return this.matchPatterns; - } - - @Override - public List mismatchPatterns() { - return this.mismatchPatterns; - } - - @Override - public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, - HttpServerFilterChain chain) throws DoHttpServerFilterException { - try { - // 如果参数中带有地区,说明用户想使用新地区执行后续的操作,直接设置地区。 - String paramLocale = request.queries().first("locale").orElse(null); - Locale responseLocale = null; - // 使用责任链解析 locale - LocaleResolver localeResolver = this.localeResolverRegistry.dispatch(request); - if (paramLocale != null && !paramLocale.trim().isEmpty()) { - responseLocale = Locale.forLanguageTag(paramLocale); - LocaleContextHolder.setLocaleContext(new LocaleContext(responseLocale)); - } - // 如果参数中不包含地区,则解析请求所带的地区参数。 - else { - Locale locale = localeResolver.resolveLocale(request); - LocaleContextHolder.setLocaleContext(new LocaleContext(locale)); - } - - // 继续执行后续过滤器。 - chain.doFilter(request, response); - - // responseLocale 是用户期望设置的地区,不受 server 端处理的影响。 - localeResolver.setLocale(response, responseLocale); - } finally { - LocaleContextHolder.clear(); - } - - } - - @Override - public Scope scope() { - return this.scope; - } -} diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java deleted file mode 100644 index db63a4d02..000000000 --- a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/java/modelengine/fitframework/i18n/LocaleResolverRegistry.java +++ /dev/null @@ -1,190 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.i18n; - -import static modelengine.fitframework.inspection.Validation.notBlank; -import static modelengine.fitframework.inspection.Validation.notNull; - -import modelengine.fit.http.server.HttpClassicServerRequest; -import modelengine.fit.http.server.dispatch.MappingTree; -import modelengine.fit.http.server.dispatch.support.DefaultMappingTree; -import modelengine.fit.http.util.i18n.DefualtLocaleResolver; -import modelengine.fit.http.util.i18n.LocaleResolver; -import modelengine.fit.http.util.i18n.RegisterLocaleResolverException; -import modelengine.fitframework.annotation.Component; -import modelengine.fitframework.ioc.BeanContainer; -import modelengine.fitframework.ioc.BeanFactory; -import modelengine.fitframework.plugin.Plugin; -import modelengine.fitframework.plugin.PluginStartedObserver; -import modelengine.fitframework.plugin.PluginStoppingObserver; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - -import modelengine.fitframework.resource.UrlUtils; -import modelengine.fitframework.util.OptionalUtils; -import modelengine.fitframework.util.StringUtils; -import modelengine.fitframework.util.wildcard.PathPattern; -import modelengine.fitframework.util.wildcard.Pattern; - -/** - * 地区解析器注册中心 - * - * @author 阮睿 - * @since 2025-09-07 - */ -@Component -public class LocaleResolverRegistry implements PluginStartedObserver, PluginStoppingObserver { - private static final char PATH_SEPARATOR = '/'; - - // 参考 DefaultHttpDispatcher 的三层结构 - private final Map noPathVariableResolvers = new ConcurrentHashMap<>(); - private final Map> pathVariableResolvers = new ConcurrentHashMap<>(); - private final Map wildcardResolvers = new ConcurrentHashMap<>(); - - private final LocaleResolver defaultLocaleResolver = new DefualtLocaleResolver(); - - /** - * 构造函数。 - */ - public LocaleResolverRegistry() { - // 与 DefaultHttpDispatcher 保持一致,使用 ConcurrentHashMap 提供线程安全。 - this.pathVariableResolvers.put(DefaultMappingTree.PATH_SEPARATOR, new DefaultMappingTree<>()); - } - - /** - * 注册地区解析器。 - * - * @param resolver 表示将要被注册地区解析器的 {@link LocaleResolver}。 - */ - public void register(LocaleResolver resolver) { - notNull(resolver, "The locale resolver cannot be null."); - String pathPattern = MappingTree.convertToMatchedPathPattern(resolver.getUrlPattern()); - notBlank(pathPattern, "The path pattern cannot be blank."); - LocaleResolver preResolver; - if (pathPattern.contains("**")) { - preResolver = this.wildcardResolvers.put(pathPattern, resolver); - } else if (pathPattern.contains("*")) { - preResolver = this.pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR) - .register(pathPattern, resolver) - .orElse(null); - } else { - preResolver = this.noPathVariableResolvers.put(pathPattern, resolver); - } - if (preResolver != null) { - String message = StringUtils.format("Locale resolver has been registered. [pattern={0}]", pathPattern); - throw new RegisterLocaleResolverException(message); - } - } - - /** - * 取消注册地区解析器。 - * - * @param resolver 表示待取消注册地区解析器的 {@link LocaleResolver}。 - */ - public void unregister(LocaleResolver resolver) { - notNull(resolver, "The locale resolver cannot be null."); - String pathPattern = MappingTree.convertToMatchedPathPattern(resolver.getUrlPattern()); - notBlank(pathPattern, "The path pattern cannot be blank."); - if (pathPattern.contains("**")) { - this.wildcardResolvers.remove(pathPattern); - } else if (pathPattern.contains("*")) { - this.pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR).unregister(pathPattern); - ; - } else { - this.noPathVariableResolvers.remove(pathPattern); - } - } - - /** - * 分派地区解析器。 - * - * @param request 表示用于查找对应 {@link LocaleResolver} 请求的 {@link HttpClassicServerRequest}。 - * @return 返回匹配的 {@link LocaleResolver}。 - */ - public LocaleResolver dispatch(HttpClassicServerRequest request) { - String path = UrlUtils.decodePath(request.path()); - return (LocaleResolver) OptionalUtils.get(() -> selectFromNoPathVariableResolvers(path)) - .orElse(() -> selectFromPathVariableResolvers(path)) - .orElse(() -> selectFromWildcardResolvers(path)) - .orDefault(this.defaultLocaleResolver); - } - - /** - * 从无路径参数的解析器中查找匹配的解析器。 - * - * @param path 表示待匹配路径的 {@link String}。 - * @return 表示匹配对应路径解析器的 {@link Optional}{@code <}{@link LocaleResolver}{@code >}。。 - */ - private Optional selectFromNoPathVariableResolvers(String path) { - LocaleResolver resolver = this.noPathVariableResolvers.get(path); - return Optional.ofNullable(resolver); - } - - /** - * 从路径参数的解析器中查找匹配的解析器。 - * - * @param path 待匹配路径的 {@link String}。 - * @return 匹配对应路径解析器的 {@link Optional}{@code <}{@link LocaleResolver}{@code >}。 - */ - private Optional selectFromPathVariableResolvers(String path) { - return this.pathVariableResolvers.get(DefaultMappingTree.PATH_SEPARATOR).search(path); - } - - /** - * 从通配符的解析器中查找匹配的解析器。 - * - * @param path 待匹配路径的 {@link String}。 - * @return 匹配对应路径解析器的 {@link Optional}{@code <}{@link LocaleResolver}{@code >}。 - */ - private Optional selectFromWildcardResolvers(String path) { - for (Map.Entry entry : this.wildcardResolvers.entrySet()) { - PathPattern pattern = Pattern.forPath(entry.getKey(), PATH_SEPARATOR); - if (pattern.matches(path)) { - return Optional.of(entry.getValue()); - } - } - return Optional.empty(); - } - - /** - * 当插件启动时,注册插件中的地区解析器。 - * - * @param plugin 待注册插件的 {@link Plugin}。 - */ - @Override - public void onPluginStarted(Plugin plugin) { - BeanContainer container = plugin.container(); - List localeResolvers = container.all(LocaleResolver.class) - .stream() - .map(BeanFactory::get) - .collect(Collectors.toList()); - for (LocaleResolver localeResolver : localeResolvers) { - this.register(localeResolver); - } - } - - /** - * 当插件停止时,取消注册插件中的地区解析器。 - * - * @param plugin 待取消注册插件的 {@link Plugin}。 - */ - @Override - public void onPluginStopping(Plugin plugin) { - BeanContainer container = plugin.container(); - List localeResolvers = container.all(LocaleResolver.class) - .stream() - .map(BeanFactory::get) - .collect(Collectors.toList()); - for (LocaleResolver localeResolver : localeResolvers) { - this.unregister(localeResolver); - } - } -} diff --git a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/resources/application.yaml b/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/resources/application.yaml deleted file mode 100644 index 9b8d7cc1a..000000000 --- a/framework/fit/java/fit-builtin/plugins/fit-i18n-registry/src/main/resources/application.yaml +++ /dev/null @@ -1,4 +0,0 @@ -fit: - beans: - packages: - - 'modelengine.fitframework.i18n' diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index a6c1c8e0c..783cb02e9 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -6,7 +6,7 @@ package modelengine.fitframework.validation; -import modelengine.fitframework.util.LocaleContextHolder; +import modelengine.fitframework.util.i18n.LocaleContextHolder; import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 66a80859f..1adae14a1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -10,8 +10,6 @@ import modelengine.fit.http.entity.Entity; import modelengine.fit.http.entity.ObjectEntity; import modelengine.fitframework.annotation.Fit; -import modelengine.fitframework.i18n.LocaleResolveFilter; -import modelengine.fitframework.i18n.LocaleResolverRegistry; import modelengine.fitframework.test.annotation.MvcTest; import modelengine.fitframework.test.domain.mvc.MockMvc; import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; @@ -34,7 +32,7 @@ * @author 阮睿 * @since 2025-08-01 */ -@MvcTest(classes = {LocaleValidationController.class, LocaleResolverRegistry.class, LocaleResolveFilter.class}) +@MvcTest(classes = {LocaleValidationController.class}) @DisplayName("测试地区化验证消息功能") public class LocaleValidationControllerTest { @Fit diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java new file mode 100644 index 000000000..ad5665302 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java @@ -0,0 +1,13 @@ +package modelengine.fitframework.validation.data; + +import modelengine.fit.http.util.i18n.LocaleResolveFilter; +import modelengine.fitframework.annotation.Bean; +import modelengine.fitframework.annotation.Component; + +@Component +public class LocaleResolveFilterConfig { + @Bean + public LocaleResolveFilter localeResolveFilter() { + return new LocaleResolveFilter(); + } +} diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index 3c0352841..3ddb37a57 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -6,7 +6,7 @@ package modelengine.fitframework.validation; -import modelengine.fitframework.util.LocaleContextHolder; +import modelengine.fitframework.util.i18n.LocaleContextHolder; import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 66a80859f..1adae14a1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -10,8 +10,6 @@ import modelengine.fit.http.entity.Entity; import modelengine.fit.http.entity.ObjectEntity; import modelengine.fitframework.annotation.Fit; -import modelengine.fitframework.i18n.LocaleResolveFilter; -import modelengine.fitframework.i18n.LocaleResolverRegistry; import modelengine.fitframework.test.annotation.MvcTest; import modelengine.fitframework.test.domain.mvc.MockMvc; import modelengine.fitframework.test.domain.mvc.request.MockMvcRequestBuilders; @@ -34,7 +32,7 @@ * @author 阮睿 * @since 2025-08-01 */ -@MvcTest(classes = {LocaleValidationController.class, LocaleResolverRegistry.class, LocaleResolveFilter.class}) +@MvcTest(classes = {LocaleValidationController.class}) @DisplayName("测试地区化验证消息功能") public class LocaleValidationControllerTest { @Fit diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java new file mode 100644 index 000000000..ad5665302 --- /dev/null +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java @@ -0,0 +1,13 @@ +package modelengine.fitframework.validation.data; + +import modelengine.fit.http.util.i18n.LocaleResolveFilter; +import modelengine.fitframework.annotation.Bean; +import modelengine.fitframework.annotation.Component; + +@Component +public class LocaleResolveFilterConfig { + @Bean + public LocaleResolveFilter localeResolveFilter() { + return new LocaleResolveFilter(); + } +} diff --git a/framework/fit/java/fit-builtin/plugins/pom.xml b/framework/fit/java/fit-builtin/plugins/pom.xml index c506a613e..0260ff321 100644 --- a/framework/fit/java/fit-builtin/plugins/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/pom.xml @@ -45,7 +45,6 @@ fit-value-fastjson fit-validation-hibernate-jakarta fit-validation-hibernate-javax - fit-i18n-registry diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index ad85676ab..47ced51cc 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -24,7 +24,6 @@ public class DefualtLocaleResolver implements LocaleResolver { private String cookieDomain = DEFAULT_COOKIE_DOMAIN; private String cookiePath = DEFAULT_COOKIE_PATH; private Locale defaultLocale = Locale.getDefault(); - private String urlPattern = "/**"; @Override public Locale resolveLocale(HttpClassicServerRequest request) { @@ -62,16 +61,6 @@ public void setLocale(HttpClassicServerResponse response, Locale locale) { } } - @Override - public String getUrlPattern() { - return this.urlPattern; - } - - @Override - public void setUrlPattern(String urlPattern) { - this.urlPattern = urlPattern; - } - /** * 设置存储地区信息的 Cookie 名称。 * @@ -116,5 +105,4 @@ public void setCookiePath(String cookiePath) { public void setDefaultLocale(Locale defaultLocale) { this.defaultLocale = defaultLocale; } - } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java similarity index 87% rename from framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java rename to framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index ce37dd34e..a79bad681 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/SimpleLocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -8,19 +8,19 @@ import modelengine.fit.http.server.*; import modelengine.fitframework.annotation.Scope; -import modelengine.fitframework.util.LocaleContext; -import modelengine.fitframework.util.LocaleContextHolder; +import modelengine.fitframework.util.i18n.LocaleContext; +import modelengine.fitframework.util.i18n.LocaleContextHolder; import java.util.List; import java.util.Locale; /** - * 简单地区解析过滤器,只使用一种 {@link LocaleResolver} 进行地区解析,多插件同时配置 {@link SimpleLocaleResolveFilter} 可能会引发不可预知的行为。 + * 简单地区解析过滤器,只使用一种 {@link LocaleResolver} 进行地区解析,多插件同时配置 {@link LocaleResolveFilter} 可能会引发不可预知的行为。 * * @author 阮睿 * @since 2025-08-01 */ -public class SimpleLocaleResolveFilter implements HttpServerFilter { +public class LocaleResolveFilter implements HttpServerFilter { private LocaleResolver localeResolver = null; private List matchPatterns = List.of("/**"); @@ -34,14 +34,14 @@ public class SimpleLocaleResolveFilter implements HttpServerFilter { * * @param localeResolver 表示地区解析器的 {@link LocaleResolver}。 */ - public SimpleLocaleResolveFilter(LocaleResolver localeResolver) { + public LocaleResolveFilter(LocaleResolver localeResolver) { this.localeResolver = localeResolver; } /** * 默认构造函数。 */ - public SimpleLocaleResolveFilter() { + public LocaleResolveFilter() { this.localeResolver = new DefualtLocaleResolver(); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java index dba6a1781..4ce98be61 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java @@ -38,18 +38,4 @@ public interface LocaleResolver { * @param locale 表示要设置地区的 {@link Locale}。 */ void setLocale(HttpClassicServerResponse response, Locale locale); - - /** - * 获取地区解析器的 URL 模式。 - * - * @return 获取地区解析器 URL 模式的 {@link String}。 - */ - String getUrlPattern(); - - /** - * 设置地区解析器的 URL 模式。 - * - * @param urlPattern 表示待设置 URL 模式的 {@link String}。 - */ - void setUrlPattern(String urlPattern); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java deleted file mode 100644 index 6d06fb7d2..000000000 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/RegisterLocaleResolverException.java +++ /dev/null @@ -1,36 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fit.http.util.i18n; - -import modelengine.fit.http.server.HttpServerException; - -/** - * 表示注册 {@link LocaleResolver} 时出现的异常。 - * - * @author 阮睿 - * @since 2025-09-07 - */ -public class RegisterLocaleResolverException extends HttpServerException { - /** - * 通过异常消息来实例化 {@link RegisterLocaleResolverException}。 - * - * @param message 表示异常消息的 {@link String}。 - */ - public RegisterLocaleResolverException(String message) { - super(message); - } - - /** - * 通过异常消息和异常原因来实例化 {@link RegisterLocaleResolverException}。 - * - * @param message 表示异常消息的 {@link String}。 - * @param cause 表示异常原因的 {@link Throwable}。 - */ - public RegisterLocaleResolverException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContext.java similarity index 95% rename from framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java rename to framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContext.java index 719471225..9b9ac2db8 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContext.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContext.java @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelengine.fitframework.util; +package modelengine.fitframework.util.i18n; import java.util.Locale; diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java similarity index 97% rename from framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java rename to framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java index 2217b232e..12a76d46e 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/LocaleContextHolder.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -package modelengine.fitframework.util; +package modelengine.fitframework.util.i18n; import java.util.Locale; From 1ea4da268779b9a97ab07ef23ae769b3f423a92b Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 9 Sep 2025 14:36:30 +0800 Subject: [PATCH 12/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fit/http/util/i18n/DefualtLocaleResolver.java | 4 ++-- .../fit/http/util/i18n/LocaleResolveFilter.java | 4 ++-- .../fit/http/util/i18n/LocaleResolver.java | 12 ++++++++++++ .../fitframework/util/i18n/LocaleContextHolder.java | 4 +++- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index 47ced51cc..a73d4674c 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -27,7 +27,7 @@ public class DefualtLocaleResolver implements LocaleResolver { @Override public Locale resolveLocale(HttpClassicServerRequest request) { - // 先解析 Cookie,如果没有则解析 Accept-Language 头 + // 先解析 Cookie,如果没有则解析 Accept-Language 头。 String newLocale = request.cookies().get(this.cookieName).map(Cookie::value).orElse(null); if (newLocale != null) { return Locale.forLanguageTag(newLocale); @@ -42,7 +42,7 @@ public Locale resolveLocale(HttpClassicServerRequest request) { return Locale.forLanguageTag(acceptLanguage); } - return defaultLocale; + return this.defaultLocale; } @Override diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index a79bad681..411814599 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -15,7 +15,7 @@ import java.util.Locale; /** - * 简单地区解析过滤器,只使用一种 {@link LocaleResolver} 进行地区解析,多插件同时配置 {@link LocaleResolveFilter} 可能会引发不可预知的行为。 + * 地区解析过滤器,使用 {@link LocaleResolver} 进行地区解析。 * * @author 阮睿 * @since 2025-08-01 @@ -27,7 +27,7 @@ public class LocaleResolveFilter implements HttpServerFilter { private List mismatchPatterns = List.of(); - private Scope scope = Scope.GLOBAL; + private Scope scope = Scope.PLUGIN; /** * 构造函数。 diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java index 4ce98be61..706fea0fb 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java @@ -18,9 +18,21 @@ * @since 2025-08-01 */ public interface LocaleResolver { + /** + * 表示要设置 cookie 的名称。 + */ public static final String DEFAULT_COOKIE_NAME = "locale"; + /** + * 表示要设置 cookie 的自动过期时间。 + */ public static final int DEFAULT_COOKIE_MAX_AGE = 60 * 60 * 24 * 365; + /** + * 表示要设置 Cookie 的可见域。 + */ public static final String DEFAULT_COOKIE_DOMAIN = "/"; + /** + * 表示要设置 Cookie 的可见 URL 路径。 + */ public static final String DEFAULT_COOKIE_PATH = "/"; /** diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java index 12a76d46e..52d3f1770 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java @@ -23,7 +23,9 @@ public class LocaleContextHolder { * @param localeContext 表示将要存储在当前线程地区上下文的 {@link LocaleContext}。 */ public static void setLocaleContext(LocaleContext localeContext) { - LOCALE_CONTEXT_HOLDER.set(localeContext); + if (localeContext != null) { + LOCALE_CONTEXT_HOLDER.set(localeContext); + } } /** From ffe6777bc2d2dda1c530ac0e7bce46b6e4dfd990 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 9 Sep 2025 14:47:13 +0800 Subject: [PATCH 13/25] =?UTF-8?q?=E5=88=A0=E9=99=A4pom=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E6=97=A7=E5=AE=9E=E7=8E=B0=E6=AE=8B=E7=95=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugins/fit-validation-hibernate-jakarta/pom.xml | 6 ------ .../plugins/fit-validation-hibernate-javax/pom.xml | 6 ------ 2 files changed, 12 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml index fc6a9b9a4..41d45c5c1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/pom.xml @@ -61,12 +61,6 @@ h2 test - - org.fitframework.plugin - fit-i18n-registry - ${project.version} - test - diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml index 0a19fa35e..0d0e43be2 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/pom.xml @@ -61,12 +61,6 @@ h2 test - - org.fitframework.plugin - fit-i18n-registry - ${project.version} - test - From 88ce487ddb26135d98d9552f20d698c28647b481 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 9 Sep 2025 23:17:32 +0800 Subject: [PATCH 14/25] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E5=90=8D=EF=BC=8C=E4=B8=BA=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB=E6=8F=90=E4=BE=9B=E6=B5=8B=E8=AF=95=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LocaleValidationControllerTest.java | 2 +- .../LocaleValidationControllerTest.java | 2 +- .../util/i18n/LocaleContextHolderTest.java | 102 ++++++++++++++++++ .../util/i18n/LocaleContextTest.java | 53 +++++++++ 4 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java create mode 100644 framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 1adae14a1..e7ea9a4f1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -49,7 +49,7 @@ void teardown() throws IOException { @Test @DisplayName("测试法文地区的验证消息") - void shouldReturnChineseValidationMessage() { + void shouldReturnFrenchValidationMessage() { Company invalidCompany = new Company(null); MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/locale/simple") diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 1adae14a1..e7ea9a4f1 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -49,7 +49,7 @@ void teardown() throws IOException { @Test @DisplayName("测试法文地区的验证消息") - void shouldReturnChineseValidationMessage() { + void shouldReturnFrenchValidationMessage() { Company invalidCompany = new Company(null); MockRequestBuilder requestBuilder = MockMvcRequestBuilders.post("/validation/locale/simple") diff --git a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java new file mode 100644 index 000000000..e6058cd35 --- /dev/null +++ b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java @@ -0,0 +1,102 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.util.i18n; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Locale; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +/** + * {@link LocaleContextHolder} 的单元测试。 + * + * @author 阮睿 + * @since 2025-09-09 + */ +@DisplayName("测试 LocaleContextHolder") +public class LocaleContextHolderTest { + @AfterEach + void tearDown() { + LocaleContextHolder.clear(); + } + + @Nested + @DisplayName("Test method: setLocaleContext and getLocaleContext") + class TestSetAndGetLocaleContext { + + @Test + @DisplayName("Given locale context with zh_CN then return the same locale context") + void givenLocaleContextWithZhCNThenReturnSameLocaleContext() { + LocaleContext localeContext = new LocaleContext(Locale.SIMPLIFIED_CHINESE); + LocaleContextHolder.setLocaleContext(localeContext); + assertThat(LocaleContextHolder.getLocaleContext()).isEqualTo(localeContext); + } + + @Test + @DisplayName("Given locale context with en_US then return the same locale context") + void givenLocaleContextWithEnUSThenReturnSameLocaleContext() { + LocaleContext localeContext = new LocaleContext(Locale.US); + LocaleContextHolder.setLocaleContext(localeContext); + assertThat(LocaleContextHolder.getLocaleContext()).isEqualTo(localeContext); + } + + @Test + @DisplayName("Given null locale context then not set and return null") + void givenNullLocaleContextThenReturnNull() { + LocaleContextHolder.setLocaleContext(null); + assertThat(LocaleContextHolder.getLocaleContext()).isNull(); + } + } + + @Nested + @DisplayName("Test method: getLocale") + class TestGetLocale { + + @Test + @DisplayName("Given locale context with zh_CN then return zh_CN locale") + void givenLocaleContextWithZhCNThenReturnZhCNLocale() { + LocaleContext localeContext = new LocaleContext(Locale.SIMPLIFIED_CHINESE); + LocaleContextHolder.setLocaleContext(localeContext); + assertThat(LocaleContextHolder.getLocale()).isEqualTo(Locale.SIMPLIFIED_CHINESE); + } + + @Test + @DisplayName("Given locale context with en_US then return en_US locale") + void givenLocaleContextWithEnUSThenReturnEnUSLocale() { + LocaleContext localeContext = new LocaleContext(Locale.US); + LocaleContextHolder.setLocaleContext(localeContext); + assertThat(LocaleContextHolder.getLocale()).isEqualTo(Locale.US); + } + + @Test + @DisplayName("Given no locale context then return null") + void givenNoLocaleContextThenReturnNull() { + LocaleContextHolder.clear(); + assertThat(LocaleContextHolder.getLocale()).isNull(); + } + } + + @Nested + @DisplayName("Test method: clear") + class TestClear { + + @Test + @DisplayName("Given existing locale context then clear it") + void givenExistingLocaleContextThenClearIt() { + LocaleContext localeContext = new LocaleContext(Locale.SIMPLIFIED_CHINESE); + LocaleContextHolder.setLocaleContext(localeContext); + assertThat(LocaleContextHolder.getLocaleContext()).isNotNull(); + + LocaleContextHolder.clear(); + assertThat(LocaleContextHolder.getLocaleContext()).isNull(); + } + } +} diff --git a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java new file mode 100644 index 000000000..20d92540d --- /dev/null +++ b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java @@ -0,0 +1,53 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +package modelengine.fitframework.util.i18n; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Locale; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +/** + * {@link LocaleContext} 的单元测试。 + * + * @author 阮睿 + * @since 2025-09-09 + */ +@DisplayName("测试 LocaleContext") +public class LocaleContextTest { + @Nested + @DisplayName("Test method: constructor and getLocale()") + class TestConstructorAndGetLocale { + + @Test + @DisplayName("Given locale is zh_CN then return the same locale") + void givenZhCNThenReturnSameLocale() { + Locale locale = Locale.SIMPLIFIED_CHINESE; + LocaleContext localeContext = new LocaleContext(locale); + assertThat(localeContext.getLocale()).isEqualTo(locale); + } + + @Test + @DisplayName("Given locale is en_US then return the same locale") + void givenEnUSThenReturnSameLocale() { + Locale locale = Locale.US; + LocaleContext localeContext = new LocaleContext(locale); + assertThat(localeContext.getLocale()).isEqualTo(locale); + } + + @Test + @DisplayName("Given locale is null then return null") + void givenNullThenReturnNull() { + LocaleContext localeContext = new LocaleContext(null); + assertThat(localeContext.getLocale()).isNull(); + } + } +} + From 90ff96b205977628a19795cbb3b37e71d399ab83 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Tue, 9 Sep 2025 23:50:07 +0800 Subject: [PATCH 15/25] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fitframework/util/i18n/LocaleContextHolderTest.java | 2 +- .../modelengine/fitframework/util/i18n/LocaleContextTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java index e6058cd35..7bd78a08b 100644 --- a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java +++ b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java @@ -99,4 +99,4 @@ void givenExistingLocaleContextThenClearIt() { assertThat(LocaleContextHolder.getLocaleContext()).isNull(); } } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java index 20d92540d..32ffd8d06 100644 --- a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java +++ b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java @@ -49,5 +49,4 @@ void givenNullThenReturnNull() { assertThat(localeContext.getLocale()).isNull(); } } -} - +} \ No newline at end of file From dac1a2429cb2bb1ffc14d03c296d560becbbdb4c Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Wed, 10 Sep 2025 12:11:23 +0800 Subject: [PATCH 16/25] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fitframework/util/i18n/LocaleContextHolderTest.java | 3 --- .../modelengine/fitframework/util/i18n/LocaleContextTest.java | 1 - 2 files changed, 4 deletions(-) diff --git a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java index 7bd78a08b..f2af013a1 100644 --- a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java +++ b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java @@ -31,7 +31,6 @@ void tearDown() { @Nested @DisplayName("Test method: setLocaleContext and getLocaleContext") class TestSetAndGetLocaleContext { - @Test @DisplayName("Given locale context with zh_CN then return the same locale context") void givenLocaleContextWithZhCNThenReturnSameLocaleContext() { @@ -59,7 +58,6 @@ void givenNullLocaleContextThenReturnNull() { @Nested @DisplayName("Test method: getLocale") class TestGetLocale { - @Test @DisplayName("Given locale context with zh_CN then return zh_CN locale") void givenLocaleContextWithZhCNThenReturnZhCNLocale() { @@ -87,7 +85,6 @@ void givenNoLocaleContextThenReturnNull() { @Nested @DisplayName("Test method: clear") class TestClear { - @Test @DisplayName("Given existing locale context then clear it") void givenExistingLocaleContextThenClearIt() { diff --git a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java index 32ffd8d06..462b68ada 100644 --- a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java +++ b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java @@ -25,7 +25,6 @@ public class LocaleContextTest { @Nested @DisplayName("Test method: constructor and getLocale()") class TestConstructorAndGetLocale { - @Test @DisplayName("Given locale is zh_CN then return the same locale") void givenZhCNThenReturnSameLocale() { From 0493ec8a9863ed898e1a0c00cf7d7077142ac7d8 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Wed, 10 Sep 2025 15:55:21 +0800 Subject: [PATCH 17/25] =?UTF-8?q?=E5=88=A0=E9=99=A4localecontext?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/util/i18n/LocaleResolveFilter.java | 5 +- .../fitframework/util/i18n/LocaleContext.java | 37 ------------ .../util/i18n/LocaleContextHolder.java | 24 +++----- .../util/i18n/LocaleContextHolderTest.java | 59 +++++-------------- .../util/i18n/LocaleContextTest.java | 51 ---------------- 5 files changed, 25 insertions(+), 151 deletions(-) delete mode 100644 framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContext.java delete mode 100644 framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index 411814599..2a09c1249 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -8,7 +8,6 @@ import modelengine.fit.http.server.*; import modelengine.fitframework.annotation.Scope; -import modelengine.fitframework.util.i18n.LocaleContext; import modelengine.fitframework.util.i18n.LocaleContextHolder; import java.util.List; @@ -74,12 +73,12 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse Locale responseLocale = null; if (paramLocale != null && !paramLocale.trim().isEmpty()) { responseLocale = Locale.forLanguageTag(paramLocale); - LocaleContextHolder.setLocaleContext(new LocaleContext(responseLocale)); + LocaleContextHolder.setLocale(responseLocale); } // 如果参数中不包含地区,则解析请求所带的地区参数。 else { Locale locale = this.localeResolver.resolveLocale(request); - LocaleContextHolder.setLocaleContext(new LocaleContext(locale)); + LocaleContextHolder.setLocale(locale); } // 继续执行后续过滤器。 diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContext.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContext.java deleted file mode 100644 index 9b9ac2db8..000000000 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContext.java +++ /dev/null @@ -1,37 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.util.i18n; - -import java.util.Locale; - -/** - * 表示存储地区信息的上下文。 - * - * @author 阮睿 - * @since 2025-08-01 - */ -public class LocaleContext { - private final Locale locale; - - /** - * 构造函数。 - * - * @param locale 表示要设置地区信息的 {@link Locale}。 - */ - public LocaleContext(Locale locale) { - this.locale = locale; - } - - /** - * 获取上下文中的地区信息。 - * - * @return 表示当前上下文中存储的地区信息的 {@link Locale}。 - */ - public Locale getLocale() { - return this.locale; - } -} \ No newline at end of file diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java index 52d3f1770..fa529eefa 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java @@ -9,42 +9,32 @@ import java.util.Locale; /** - * 表示存储地区上下文的线程上下文。 + * 表示存储地区的线程上下文。 * * @author 阮睿 * @since 2025-08-01 */ public class LocaleContextHolder { - private static final ThreadLocal LOCALE_CONTEXT_HOLDER = new ThreadLocal<>(); + private static final ThreadLocal LOCALE_CONTEXT_HOLDER = new ThreadLocal<>(); /** * 设置当前线程的地区上下文。 * - * @param localeContext 表示将要存储在当前线程地区上下文的 {@link LocaleContext}。 + * @param locale 表示将要存储在当前线程地区上下文的 {@link Locale}。 */ - public static void setLocaleContext(LocaleContext localeContext) { - if (localeContext != null) { - LOCALE_CONTEXT_HOLDER.set(localeContext); + public static void setLocale(Locale locale) { + if (locale != null) { + LOCALE_CONTEXT_HOLDER.set(locale); } } - /** - * 获取当前线程的地区上下文。 - * - * @return 表示当前线程地区上下文的 {@link LocaleContext}。 - */ - public static LocaleContext getLocaleContext() { - return LOCALE_CONTEXT_HOLDER.get(); - } - /** * 获取当前线程的地区。 * * @return 表示当前线程上下文存储地区信息的 {@link Locale}。 */ public static Locale getLocale() { - LocaleContext context = getLocaleContext(); - return context != null ? context.getLocale() : null; + return LOCALE_CONTEXT_HOLDER.get(); } /** diff --git a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java index f2af013a1..6c398ae38 100644 --- a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java +++ b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextHolderTest.java @@ -29,55 +29,28 @@ void tearDown() { } @Nested - @DisplayName("Test method: setLocaleContext and getLocaleContext") + @DisplayName("Test method: setLocale and getLocale") class TestSetAndGetLocaleContext { @Test - @DisplayName("Given locale context with zh_CN then return the same locale context") + @DisplayName("Given locale with zh_CN then return the same locale") void givenLocaleContextWithZhCNThenReturnSameLocaleContext() { - LocaleContext localeContext = new LocaleContext(Locale.SIMPLIFIED_CHINESE); - LocaleContextHolder.setLocaleContext(localeContext); - assertThat(LocaleContextHolder.getLocaleContext()).isEqualTo(localeContext); + Locale locale = Locale.SIMPLIFIED_CHINESE; + LocaleContextHolder.setLocale(locale); + assertThat(LocaleContextHolder.getLocale()).isEqualTo(locale); } @Test - @DisplayName("Given locale context with en_US then return the same locale context") + @DisplayName("Given locale with en_US then return the same locale") void givenLocaleContextWithEnUSThenReturnSameLocaleContext() { - LocaleContext localeContext = new LocaleContext(Locale.US); - LocaleContextHolder.setLocaleContext(localeContext); - assertThat(LocaleContextHolder.getLocaleContext()).isEqualTo(localeContext); + Locale locale = Locale.US; + LocaleContextHolder.setLocale(locale); + assertThat(LocaleContextHolder.getLocale()).isEqualTo(locale); } @Test - @DisplayName("Given null locale context then not set and return null") + @DisplayName("Given null locale then not set and return null") void givenNullLocaleContextThenReturnNull() { - LocaleContextHolder.setLocaleContext(null); - assertThat(LocaleContextHolder.getLocaleContext()).isNull(); - } - } - - @Nested - @DisplayName("Test method: getLocale") - class TestGetLocale { - @Test - @DisplayName("Given locale context with zh_CN then return zh_CN locale") - void givenLocaleContextWithZhCNThenReturnZhCNLocale() { - LocaleContext localeContext = new LocaleContext(Locale.SIMPLIFIED_CHINESE); - LocaleContextHolder.setLocaleContext(localeContext); - assertThat(LocaleContextHolder.getLocale()).isEqualTo(Locale.SIMPLIFIED_CHINESE); - } - - @Test - @DisplayName("Given locale context with en_US then return en_US locale") - void givenLocaleContextWithEnUSThenReturnEnUSLocale() { - LocaleContext localeContext = new LocaleContext(Locale.US); - LocaleContextHolder.setLocaleContext(localeContext); - assertThat(LocaleContextHolder.getLocale()).isEqualTo(Locale.US); - } - - @Test - @DisplayName("Given no locale context then return null") - void givenNoLocaleContextThenReturnNull() { - LocaleContextHolder.clear(); + LocaleContextHolder.setLocale(null); assertThat(LocaleContextHolder.getLocale()).isNull(); } } @@ -86,14 +59,14 @@ void givenNoLocaleContextThenReturnNull() { @DisplayName("Test method: clear") class TestClear { @Test - @DisplayName("Given existing locale context then clear it") + @DisplayName("Given existing locale then clear it") void givenExistingLocaleContextThenClearIt() { - LocaleContext localeContext = new LocaleContext(Locale.SIMPLIFIED_CHINESE); - LocaleContextHolder.setLocaleContext(localeContext); - assertThat(LocaleContextHolder.getLocaleContext()).isNotNull(); + Locale locale = Locale.SIMPLIFIED_CHINESE; + LocaleContextHolder.setLocale(locale); + assertThat(LocaleContextHolder.getLocale()).isNotNull(); LocaleContextHolder.clear(); - assertThat(LocaleContextHolder.getLocaleContext()).isNull(); + assertThat(LocaleContextHolder.getLocale()).isNull(); } } } \ No newline at end of file diff --git a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java b/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java deleted file mode 100644 index 462b68ada..000000000 --- a/framework/fit/java/fit-util/src/test/java/modelengine/fitframework/util/i18n/LocaleContextTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. - * This file is a part of the ModelEngine Project. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -package modelengine.fitframework.util.i18n; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.Locale; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -/** - * {@link LocaleContext} 的单元测试。 - * - * @author 阮睿 - * @since 2025-09-09 - */ -@DisplayName("测试 LocaleContext") -public class LocaleContextTest { - @Nested - @DisplayName("Test method: constructor and getLocale()") - class TestConstructorAndGetLocale { - @Test - @DisplayName("Given locale is zh_CN then return the same locale") - void givenZhCNThenReturnSameLocale() { - Locale locale = Locale.SIMPLIFIED_CHINESE; - LocaleContext localeContext = new LocaleContext(locale); - assertThat(localeContext.getLocale()).isEqualTo(locale); - } - - @Test - @DisplayName("Given locale is en_US then return the same locale") - void givenEnUSThenReturnSameLocale() { - Locale locale = Locale.US; - LocaleContext localeContext = new LocaleContext(locale); - assertThat(localeContext.getLocale()).isEqualTo(locale); - } - - @Test - @DisplayName("Given locale is null then return null") - void givenNullThenReturnNull() { - LocaleContext localeContext = new LocaleContext(null); - assertThat(localeContext.getLocale()).isNull(); - } - } -} \ No newline at end of file From f849028f8330a5c0ad30ecb52c19b409f11c8e3b Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Thu, 11 Sep 2025 22:42:51 +0800 Subject: [PATCH 18/25] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E9=94=99=E8=AF=AF=EF=BC=8C=E5=AE=8C=E5=96=84=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LocaleValidationControllerTest.java | 9 +------ .../data/LocaleResolveFilterConfig.java | 19 +++++++++++++- .../LocaleValidationControllerTest.java | 9 +------ .../data/LocaleResolveFilterConfig.java | 19 +++++++++++++- .../http/util/i18n/DefualtLocaleResolver.java | 26 ++++++++++++------- .../http/util/i18n/LocaleResolveFilter.java | 26 +++++++++++-------- .../fit/http/util/i18n/LocaleResolver.java | 17 +++++++----- .../util/i18n/LocaleContextHolder.java | 4 +-- 8 files changed, 81 insertions(+), 48 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index e7ea9a4f1..651b06b0e 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -145,11 +145,4 @@ void shouldUseLocaleFromUrlParam() { assertThat(this.response.cookies().get("locale").get().value()).isEqualTo("en-US"); assertThat(this.response.statusCode()).isEqualTo(500); } -} - - - - - - - +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java index ad5665302..e0df5f8aa 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java @@ -1,13 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.validation.data; import modelengine.fit.http.util.i18n.LocaleResolveFilter; import modelengine.fitframework.annotation.Bean; import modelengine.fitframework.annotation.Component; +/** + * 表示地区解析过滤器的配置类。 + * + * @author 阮睿 + * @since 2025-09-11 + */ @Component public class LocaleResolveFilterConfig { + /** + * 创建地区解析过滤器 bean 对象。 + * + * @return 表示作为 bean 的地区解析过滤器对象的 {@link LocaleResolveFilter}。 + */ @Bean public LocaleResolveFilter localeResolveFilter() { return new LocaleResolveFilter(); } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index e7ea9a4f1..651b06b0e 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -145,11 +145,4 @@ void shouldUseLocaleFromUrlParam() { assertThat(this.response.cookies().get("locale").get().value()).isEqualTo("en-US"); assertThat(this.response.statusCode()).isEqualTo(500); } -} - - - - - - - +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java index ad5665302..e0df5f8aa 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleResolveFilterConfig.java @@ -1,13 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved. + * This file is a part of the ModelEngine Project. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + package modelengine.fitframework.validation.data; import modelengine.fit.http.util.i18n.LocaleResolveFilter; import modelengine.fitframework.annotation.Bean; import modelengine.fitframework.annotation.Component; +/** + * 表示地区解析过滤器的配置类。 + * + * @author 阮睿 + * @since 2025-09-11 + */ @Component public class LocaleResolveFilterConfig { + /** + * 创建地区解析过滤器 bean 对象。 + * + * @return 表示作为 bean 的地区解析过滤器对象的 {@link LocaleResolveFilter}。 + */ @Bean public LocaleResolveFilter localeResolveFilter() { return new LocaleResolveFilter(); } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index a73d4674c..01aca03aa 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -9,7 +9,9 @@ import modelengine.fit.http.Cookie; import modelengine.fit.http.server.HttpClassicServerRequest; import modelengine.fit.http.server.HttpClassicServerResponse; +import modelengine.fitframework.util.StringUtils; +import java.util.List; import java.util.Locale; /** @@ -29,16 +31,20 @@ public class DefualtLocaleResolver implements LocaleResolver { public Locale resolveLocale(HttpClassicServerRequest request) { // 先解析 Cookie,如果没有则解析 Accept-Language 头。 String newLocale = request.cookies().get(this.cookieName).map(Cookie::value).orElse(null); - if (newLocale != null) { + if (newLocale != null && StringUtils.isNotBlank(newLocale.trim())) { return Locale.forLanguageTag(newLocale); } - String acceptLanguage; - try { - acceptLanguage = request.headers().require("Accept-Language"); - } catch (Exception e) { - acceptLanguage = null; + String acceptLanguage = null; + List acceptLanguages = request.headers().all("Accept-Language"); + + for (String language : acceptLanguages) { + if (language != null && StringUtils.isNotBlank(language.trim())) { + acceptLanguage = language; + break; + } } - if (acceptLanguage != null && !acceptLanguage.trim().isEmpty()) { + + if (acceptLanguage != null && StringUtils.isNotBlank(acceptLanguage.trim())) { return Locale.forLanguageTag(acceptLanguage); } @@ -64,7 +70,7 @@ public void setLocale(HttpClassicServerResponse response, Locale locale) { /** * 设置存储地区信息的 Cookie 名称。 * - * @param cookieName 表示将要设置 Cookie 名称的 {@link String}。 + * @param cookieName 表示待设置 Cookie 名称的 {@link String}。 */ public void setCookieName(String cookieName) { this.cookieName = cookieName; @@ -73,7 +79,7 @@ public void setCookieName(String cookieName) { /** * 设置存储地区信息的 Cookie 的最大有效期。 * - * @param cookieMaxAge 表示将要设置的 Cookie 最大有效期的 {@code int}。 + * @param cookieMaxAge 表示待设置的 Cookie 最大有效期的 {@code int}。 */ public void setCookieMaxAge(int cookieMaxAge) { this.cookieMaxAge = cookieMaxAge; @@ -105,4 +111,4 @@ public void setCookiePath(String cookiePath) { public void setDefaultLocale(Locale defaultLocale) { this.defaultLocale = defaultLocale; } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index 2a09c1249..683a09231 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -8,6 +8,7 @@ import modelengine.fit.http.server.*; import modelengine.fitframework.annotation.Scope; +import modelengine.fitframework.util.StringUtils; import modelengine.fitframework.util.i18n.LocaleContextHolder; import java.util.List; @@ -21,11 +22,8 @@ */ public class LocaleResolveFilter implements HttpServerFilter { private LocaleResolver localeResolver = null; - private List matchPatterns = List.of("/**"); - private List mismatchPatterns = List.of(); - private Scope scope = Scope.PLUGIN; /** @@ -68,11 +66,16 @@ public List mismatchPatterns() { public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, HttpServerFilterChain chain) throws DoHttpServerFilterException { try { - // 如果参数中带有地区,说明用户想使用新地区执行后续的操作,直接设置地区。 - String paramLocale = request.queries().first("locale").orElse(null); + List paramLocales = request.queries().all("locale"); Locale responseLocale = null; - if (paramLocale != null && !paramLocale.trim().isEmpty()) { - responseLocale = Locale.forLanguageTag(paramLocale); + for (String paramLocale : paramLocales) { + if (paramLocale != null && StringUtils.isNotBlank(paramLocale.trim())) { + responseLocale = Locale.forLanguageTag(paramLocale); + break; + } + } + // 如果参数中带有地区,说明用户想使用新地区执行后续的操作,直接设置地区。 + if (responseLocale != null) { LocaleContextHolder.setLocale(responseLocale); } // 如果参数中不包含地区,则解析请求所带的地区参数。 @@ -84,16 +87,17 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse // 继续执行后续过滤器。 chain.doFilter(request, response); - // responseLocale 是用户期望设置的地区,不受 server 端处理的影响。 - this.localeResolver.setLocale(response, responseLocale); + if (!response.isCommitted()) { + // responseLocale 是用户期望设置的地区,不受 server 端处理的影响。 + this.localeResolver.setLocale(response, responseLocale); + } } finally { LocaleContextHolder.clear(); } - } @Override public Scope scope() { return this.scope; } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java index 706fea0fb..b4e636e42 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolver.java @@ -19,19 +19,22 @@ */ public interface LocaleResolver { /** - * 表示要设置 cookie 的名称。 + * 表示待设置 cookie 的名称。 */ public static final String DEFAULT_COOKIE_NAME = "locale"; + /** - * 表示要设置 cookie 的自动过期时间。 + * 表示待设置 cookie 的自动过期时间。 */ public static final int DEFAULT_COOKIE_MAX_AGE = 60 * 60 * 24 * 365; + /** - * 表示要设置 Cookie 的可见域。 + * 表示待设置 Cookie 的可见域。 */ public static final String DEFAULT_COOKIE_DOMAIN = "/"; + /** - * 表示要设置 Cookie 的可见 URL 路径。 + * 表示待设置 Cookie 的可见 URL 路径。 */ public static final String DEFAULT_COOKIE_PATH = "/"; @@ -46,8 +49,8 @@ public interface LocaleResolver { /** * 设置地区到返回响应中。 * - * @param response 表示将要设置地区 HTTP 响应的 {@link HttpClassicServerResponse}。 - * @param locale 表示要设置地区的 {@link Locale}。 + * @param response 表示待设置地区的 HTTP 响应的 {@link HttpClassicServerResponse}。 + * @param locale 表示待设置地区的 {@link Locale}。 */ void setLocale(HttpClassicServerResponse response, Locale locale); -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java index fa529eefa..4ae67f9cc 100644 --- a/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java +++ b/framework/fit/java/fit-util/src/main/java/modelengine/fitframework/util/i18n/LocaleContextHolder.java @@ -20,7 +20,7 @@ public class LocaleContextHolder { /** * 设置当前线程的地区上下文。 * - * @param locale 表示将要存储在当前线程地区上下文的 {@link Locale}。 + * @param locale 表示待存储在当前线程地区上下文的 {@link Locale}。 */ public static void setLocale(Locale locale) { if (locale != null) { @@ -43,4 +43,4 @@ public static Locale getLocale() { public static void clear() { LOCALE_CONTEXT_HOLDER.remove(); } -} +} \ No newline at end of file From f530625a0832091953743ed2760336a135686631 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Thu, 11 Sep 2025 22:56:46 +0800 Subject: [PATCH 19/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modelengine/fit/http/util/i18n/LocaleResolveFilter.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index 683a09231..dd6056bde 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -77,9 +77,8 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse // 如果参数中带有地区,说明用户想使用新地区执行后续的操作,直接设置地区。 if (responseLocale != null) { LocaleContextHolder.setLocale(responseLocale); - } - // 如果参数中不包含地区,则解析请求所带的地区参数。 - else { + } else { + // 如果参数中不包含地区,则解析请求所带的地区参数。 Locale locale = this.localeResolver.resolveLocale(request); LocaleContextHolder.setLocale(locale); } From ecb2134b9f193ac8a2f56a09615f33dee74906f5 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Fri, 12 Sep 2025 10:51:36 +0800 Subject: [PATCH 20/25] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fit/http/util/i18n/DefualtLocaleResolver.java | 6 +++--- .../modelengine/fit/http/util/i18n/LocaleResolveFilter.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index 01aca03aa..0edf7f035 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -31,20 +31,20 @@ public class DefualtLocaleResolver implements LocaleResolver { public Locale resolveLocale(HttpClassicServerRequest request) { // 先解析 Cookie,如果没有则解析 Accept-Language 头。 String newLocale = request.cookies().get(this.cookieName).map(Cookie::value).orElse(null); - if (newLocale != null && StringUtils.isNotBlank(newLocale.trim())) { + if (StringUtils.isNotBlank(newLocale.trim())) { return Locale.forLanguageTag(newLocale); } String acceptLanguage = null; List acceptLanguages = request.headers().all("Accept-Language"); for (String language : acceptLanguages) { - if (language != null && StringUtils.isNotBlank(language.trim())) { + if (StringUtils.isNotBlank(language.trim())) { acceptLanguage = language; break; } } - if (acceptLanguage != null && StringUtils.isNotBlank(acceptLanguage.trim())) { + if (StringUtils.isNotBlank(acceptLanguage.trim())) { return Locale.forLanguageTag(acceptLanguage); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index dd6056bde..872e711a4 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -69,7 +69,7 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse List paramLocales = request.queries().all("locale"); Locale responseLocale = null; for (String paramLocale : paramLocales) { - if (paramLocale != null && StringUtils.isNotBlank(paramLocale.trim())) { + if (StringUtils.isNotBlank(paramLocale.trim())) { responseLocale = Locale.forLanguageTag(paramLocale); break; } From 53a6a7a0c544edbf968e20fe19c2df3bc2ed48bc Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Fri, 12 Sep 2025 17:02:56 +0800 Subject: [PATCH 21/25] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LocaleContextMessageInterpolator.java | 10 +++++----- .../validation/ValidationHandler.java | 4 ++-- .../validation/ValidationHandlerTest.java | 2 +- .../LocaleContextMessageInterpolator.java | 10 +++++----- .../validation/ValidationHandler.java | 4 ++-- .../http/util/i18n/DefualtLocaleResolver.java | 10 +--------- .../http/util/i18n/LocaleResolveFilter.java | 18 +++++++++--------- 7 files changed, 25 insertions(+), 33 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index 783cb02e9..653ea7ce8 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -6,6 +6,7 @@ package modelengine.fitframework.validation; +import modelengine.fitframework.util.ObjectUtils; import modelengine.fitframework.util.i18n.LocaleContextHolder; import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; @@ -25,7 +26,6 @@ */ public class LocaleContextMessageInterpolator implements MessageInterpolator { private final MessageInterpolator targetInterpolator; - private Locale locale; /** @@ -53,7 +53,7 @@ public LocaleContextMessageInterpolator() { */ public LocaleContextMessageInterpolator(Locale locale) { this.targetInterpolator = new ParameterMessageInterpolator(); - this.locale = locale; + this.locale = ObjectUtils.getIfNull(locale, Locale::getDefault); } /** @@ -64,7 +64,7 @@ public LocaleContextMessageInterpolator(Locale locale) { */ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator, Locale locale) { this.targetInterpolator = targetInterpolator; - this.locale = locale; + this.locale = ObjectUtils.getIfNull(locale, Locale::getDefault); } /** @@ -73,7 +73,7 @@ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator, * @param locale 默认设置的 {@link Locale}。 */ public void setLocale(Locale locale) { - this.locale = locale; + this.locale = ObjectUtils.getIfNull(locale, Locale::getDefault); } @Override @@ -88,4 +88,4 @@ public String interpolate(String messageTemplate, Context context) { public String interpolate(String messageTemplate, Context context, Locale locale) { return this.targetInterpolator.interpolate(messageTemplate, context, locale); } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index f997285ca..3f71554d0 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -43,7 +43,7 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; - private LocaleContextMessageInterpolator messageInterpolator; + private final LocaleContextMessageInterpolator messageInterpolator; public ValidationHandler() { this.messageInterpolator = new LocaleContextMessageInterpolator(); @@ -163,4 +163,4 @@ private boolean isJakartaConstraintAnnotation(Annotation annotation) { return "jakarta.validation".equals(packageName) && "Constraint".equals(className); }); } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 2b5d9def0..6414efc25 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -755,4 +755,4 @@ void testRangeBigDecimalValidation() { ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("5.5")}); assertThat(exception.getMessage()).contains("需要在10和100之间"); } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index 3ddb37a57..da0e82ded 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -6,6 +6,7 @@ package modelengine.fitframework.validation; +import modelengine.fitframework.util.ObjectUtils; import modelengine.fitframework.util.i18n.LocaleContextHolder; import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; @@ -25,7 +26,6 @@ */ public class LocaleContextMessageInterpolator implements MessageInterpolator { private final MessageInterpolator targetInterpolator; - private Locale locale; /** @@ -53,7 +53,7 @@ public LocaleContextMessageInterpolator() { */ public LocaleContextMessageInterpolator(Locale locale) { this.targetInterpolator = new ParameterMessageInterpolator(); - this.locale = locale; + this.locale = ObjectUtils.getIfNull(locale, Locale::getDefault); } /** @@ -64,7 +64,7 @@ public LocaleContextMessageInterpolator(Locale locale) { */ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator, Locale locale) { this.targetInterpolator = targetInterpolator; - this.locale = locale; + this.locale = ObjectUtils.getIfNull(locale, Locale::getDefault); } /** @@ -73,7 +73,7 @@ public LocaleContextMessageInterpolator(MessageInterpolator targetInterpolator, * @param locale 默认设置的 {@link Locale}。 */ public void setLocale(Locale locale) { - this.locale = locale; + this.locale = ObjectUtils.getIfNull(locale, Locale::getDefault); } @Override @@ -88,4 +88,4 @@ public String interpolate(String messageTemplate, Context context) { public String interpolate(String messageTemplate, Context context, Locale locale) { return this.targetInterpolator.interpolate(messageTemplate, context, locale); } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 4b816ee04..81a99fd33 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -45,7 +45,7 @@ public class ValidationHandler implements AutoCloseable { private final ValidatorFactory validatorFactory; private final Validator validator; - private LocaleContextMessageInterpolator messageInterpolator; + private final LocaleContextMessageInterpolator messageInterpolator; public ValidationHandler() { this.messageInterpolator = new LocaleContextMessageInterpolator(); @@ -165,4 +165,4 @@ private boolean isJavaxConstraintAnnotation(Annotation annotation) { return "javax.validation".equals(packageName) && "Constraint".equals(className); }); } -} +} \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index 0edf7f035..092a9f330 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -34,16 +34,8 @@ public Locale resolveLocale(HttpClassicServerRequest request) { if (StringUtils.isNotBlank(newLocale.trim())) { return Locale.forLanguageTag(newLocale); } - String acceptLanguage = null; - List acceptLanguages = request.headers().all("Accept-Language"); - - for (String language : acceptLanguages) { - if (StringUtils.isNotBlank(language.trim())) { - acceptLanguage = language; - break; - } - } + String acceptLanguage = request.headers().first("Accept-Language").orElse(null); if (StringUtils.isNotBlank(acceptLanguage.trim())) { return Locale.forLanguageTag(acceptLanguage); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index 872e711a4..974988627 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -8,11 +8,13 @@ import modelengine.fit.http.server.*; import modelengine.fitframework.annotation.Scope; +import modelengine.fitframework.inspection.Validation; import modelengine.fitframework.util.StringUtils; import modelengine.fitframework.util.i18n.LocaleContextHolder; import java.util.List; import java.util.Locale; +import java.util.Optional; /** * 地区解析过滤器,使用 {@link LocaleResolver} 进行地区解析。 @@ -32,7 +34,7 @@ public class LocaleResolveFilter implements HttpServerFilter { * @param localeResolver 表示地区解析器的 {@link LocaleResolver}。 */ public LocaleResolveFilter(LocaleResolver localeResolver) { - this.localeResolver = localeResolver; + this.localeResolver = Validation.notNull(localeResolver, "The locale resolver cannot be null."); } /** @@ -66,14 +68,7 @@ public List mismatchPatterns() { public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, HttpServerFilterChain chain) throws DoHttpServerFilterException { try { - List paramLocales = request.queries().all("locale"); - Locale responseLocale = null; - for (String paramLocale : paramLocales) { - if (StringUtils.isNotBlank(paramLocale.trim())) { - responseLocale = Locale.forLanguageTag(paramLocale); - break; - } - } + Locale responseLocale = Locale.forLanguageTag(this.resolveLocaleFromParam(request)); // 如果参数中带有地区,说明用户想使用新地区执行后续的操作,直接设置地区。 if (responseLocale != null) { LocaleContextHolder.setLocale(responseLocale); @@ -99,4 +94,9 @@ public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse public Scope scope() { return this.scope; } + + private String resolveLocaleFromParam(HttpClassicServerRequest request) { + Optional paramLocale = request.queries().first("locale"); + return paramLocale.orElse(null); + } } \ No newline at end of file From 9b695ca19517ee50ff5b1d4104ae73c2138c8a1b Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Sat, 13 Sep 2025 12:54:23 +0800 Subject: [PATCH 22/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/ValidationHandlerTest.java | 17 +++++++++++++++++ .../validation/ValidationHandlerTest.java | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 6414efc25..1494d59a4 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -755,4 +755,21 @@ void testRangeBigDecimalValidation() { ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("5.5")}); assertThat(exception.getMessage()).contains("需要在10和100之间"); } + + @Nested + @DisplayName("测试 Locale 默认值为 null 时的情况") + public class ValidationHandlerNullTest { + @BeforeEach + void setUp() { + ValidationHandlerTest.this.handler.setLocale(null); + } + + @Test + @DisplayName("测试@Null注解") + void testNullValidation() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNull", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"not null"}); + assertThat(exception.getMessage()).isNotNull(); + } + } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index aa2e00175..08e311889 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -757,4 +757,21 @@ void testRangeBigDecimalValidation() { ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {new BigDecimal("5.5")}); assertThat(exception.getMessage()).contains("需要在10和100之间"); } + + @Nested + @DisplayName("测试 Locale 默认值为 null 时的情况") + public class ValidationHandlerNullTest { + @BeforeEach + void setUp() { + ValidationHandlerTest.this.handler.setLocale(null); + } + + @Test + @DisplayName("测试@Null注解") + void testNullValidation() { + Method method = ReflectionUtils.getDeclaredMethod(ValidateService.class, "testNull", String.class); + ConstraintViolationException exception = invokeHandleMethod(method, new Object[] {"not null"}); + assertThat(exception.getMessage()).isNotNull(); + } + } } From c8a6d1643d218b8767809c27619f3f80190cdfce Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Sat, 13 Sep 2025 13:56:38 +0800 Subject: [PATCH 23/25] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fit/http/util/i18n/DefualtLocaleResolver.java | 4 ++-- .../fit/http/util/i18n/LocaleResolveFilter.java | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index 092a9f330..7072ea48d 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -31,12 +31,12 @@ public class DefualtLocaleResolver implements LocaleResolver { public Locale resolveLocale(HttpClassicServerRequest request) { // 先解析 Cookie,如果没有则解析 Accept-Language 头。 String newLocale = request.cookies().get(this.cookieName).map(Cookie::value).orElse(null); - if (StringUtils.isNotBlank(newLocale.trim())) { + if (StringUtils.isNotBlank(newLocale)) { return Locale.forLanguageTag(newLocale); } String acceptLanguage = request.headers().first("Accept-Language").orElse(null); - if (StringUtils.isNotBlank(acceptLanguage.trim())) { + if (StringUtils.isNotBlank(acceptLanguage)) { return Locale.forLanguageTag(acceptLanguage); } diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index 974988627..b6aaa913b 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -68,7 +68,7 @@ public List mismatchPatterns() { public void doFilter(HttpClassicServerRequest request, HttpClassicServerResponse response, HttpServerFilterChain chain) throws DoHttpServerFilterException { try { - Locale responseLocale = Locale.forLanguageTag(this.resolveLocaleFromParam(request)); + Locale responseLocale = this.resolveLocaleFromParam(request); // 如果参数中带有地区,说明用户想使用新地区执行后续的操作,直接设置地区。 if (responseLocale != null) { LocaleContextHolder.setLocale(responseLocale); @@ -95,8 +95,12 @@ public Scope scope() { return this.scope; } - private String resolveLocaleFromParam(HttpClassicServerRequest request) { + private Locale resolveLocaleFromParam(HttpClassicServerRequest request) { Optional paramLocale = request.queries().first("locale"); - return paramLocale.orElse(null); + String localeString = paramLocale.orElse(null); + if (StringUtils.isNotBlank(localeString)) { + return Locale.forLanguageTag(localeString); + } + return null; } } \ No newline at end of file From 57ac0b1dc068eed2603c23d0e743bb0b176e88d1 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Mon, 15 Sep 2025 09:36:10 +0800 Subject: [PATCH 24/25] =?UTF-8?q?=E4=B8=BA=E6=8F=92=E5=80=BC=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E6=8F=90=E4=BE=9Bnull=E5=80=BC=E4=BF=9D=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/LocaleContextMessageInterpolator.java | 3 +++ .../validation/LocaleContextMessageInterpolator.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index 653ea7ce8..06386f134 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -86,6 +86,9 @@ public String interpolate(String messageTemplate, Context context) { @Override public String interpolate(String messageTemplate, Context context, Locale locale) { + if (locale == null) { + throw new IllegalArgumentException("locale must not be null"); + } return this.targetInterpolator.interpolate(messageTemplate, context, locale); } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index da0e82ded..ff9db4ba6 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -86,6 +86,9 @@ public String interpolate(String messageTemplate, Context context) { @Override public String interpolate(String messageTemplate, Context context, Locale locale) { + if (locale == null) { + throw new IllegalArgumentException("locale must not be null"); + } return this.targetInterpolator.interpolate(messageTemplate, context, locale); } } \ No newline at end of file From 49766054fc2024cbc8ae77ea3586cc3a8f600858 Mon Sep 17 00:00:00 2001 From: RR <331382125@qq.com> Date: Mon, 15 Sep 2025 09:55:05 +0800 Subject: [PATCH 25/25] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E4=BB=A5=E5=8F=8A=E4=BC=98=E5=8C=96null=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/LocaleContextMessageInterpolator.java | 8 +++----- .../validation/LocaleValidationControllerTest.java | 4 ++-- .../validation/ValidationHandlerTest.java | 3 ++- .../validation/data/GroupValidateService.java | 12 ++++++------ .../validation/data/LocaleValidationController.java | 4 +--- .../validation/LocaleContextMessageInterpolator.java | 9 ++++----- .../fitframework/validation/ValidationHandler.java | 1 - .../validation/LocaleValidationControllerTest.java | 4 ++-- .../validation/data/GroupValidateService.java | 12 ++++++------ .../validation/data/LocaleValidationController.java | 11 +++++------ .../fit/http/util/i18n/DefualtLocaleResolver.java | 1 - .../fit/http/util/i18n/LocaleResolveFilter.java | 6 +++++- 12 files changed, 36 insertions(+), 39 deletions(-) diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index 06386f134..36aa928e2 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -6,13 +6,13 @@ package modelengine.fitframework.validation; +import jakarta.validation.MessageInterpolator; +import modelengine.fitframework.inspection.Validation; import modelengine.fitframework.util.ObjectUtils; import modelengine.fitframework.util.i18n.LocaleContextHolder; import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; -import jakarta.validation.MessageInterpolator; - import java.util.Locale; /** @@ -86,9 +86,7 @@ public String interpolate(String messageTemplate, Context context) { @Override public String interpolate(String messageTemplate, Context context, Locale locale) { - if (locale == null) { - throw new IllegalArgumentException("locale must not be null"); - } + Validation.notNull(locale, "Locale cannot be null."); return this.targetInterpolator.interpolate(messageTemplate, context, locale); } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 651b06b0e..1a1fa4a31 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -6,6 +6,8 @@ package modelengine.fitframework.validation; +import static org.assertj.core.api.Assertions.assertThat; + import modelengine.fit.http.client.HttpClassicClientResponse; import modelengine.fit.http.entity.Entity; import modelengine.fit.http.entity.ObjectEntity; @@ -24,8 +26,6 @@ import java.io.IOException; import java.util.Map; -import static org.assertj.core.api.Assertions.assertThat; - /** * 表示评估国际化校验的测试类。 * diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java index 1494d59a4..084a3b360 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/ValidationHandlerTest.java @@ -341,7 +341,8 @@ class StudentGroupValidationTests { public void givenParametersThenGroupValidateHappened() { // 测试学生年龄验证 - 现在会抛出异常,因为使用了学生分组 Method method = ReflectionUtils.getDeclaredMethod(GroupValidateService.StudentValidateService.class, - "validateStudentAge", int.class); + "validateStudentAge", + int.class); Method handleValidatedMethod = ReflectionUtils.getDeclaredMethod(ValidationHandler.class, "handle", JoinPoint.class, diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index bba16b88b..bc45d868f 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -32,9 +32,9 @@ public static class StudentValidateService { * @param age 表示年龄的 {@code int}。 */ public void validateStudentAge( - @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( - value = 20, message = "范围要在7~20之内", - groups = ValidationTestData.StudentGroup.class) int age) { + @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) + @Max(value = 20, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) + int age) { LOG.debug("Validating student age: {}", age); } } @@ -48,9 +48,9 @@ public static class TeacherValidateService { * @param age 表示年龄的 {@code int}。 */ public void validateTeacherAge( - @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( - value = 65, message = "范围要在22~65之内", - groups = ValidationTestData.TeacherGroup.class) int age) { + @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) + @Max(value = 65, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) + int age) { LOG.debug("Validating teacher age: {}", age); } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java index a202fc28e..872e72659 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-jakarta/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java @@ -6,6 +6,7 @@ package modelengine.fitframework.validation.data; +import jakarta.validation.Valid; import modelengine.fit.http.annotation.PostMapping; import modelengine.fit.http.annotation.RequestBody; import modelengine.fit.http.annotation.RequestMapping; @@ -13,9 +14,6 @@ import modelengine.fitframework.validation.LocaleContextMessageInterpolator; import modelengine.fitframework.validation.Validated; import modelengine.fitframework.validation.ValidationHandler; -import modelengine.fitframework.validation.data.Company; - -import jakarta.validation.Valid; /** * 用于测试 {@link ValidationHandler} 与 {@link LocaleContextMessageInterpolator} 的集成地区验证控制器。 diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java index ff9db4ba6..ef9be86f3 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/LocaleContextMessageInterpolator.java @@ -6,15 +6,16 @@ package modelengine.fitframework.validation; +import modelengine.fitframework.inspection.Validation; import modelengine.fitframework.util.ObjectUtils; import modelengine.fitframework.util.i18n.LocaleContextHolder; import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; -import javax.validation.MessageInterpolator; - import java.util.Locale; +import javax.validation.MessageInterpolator; + /** * 检验消息处理的代理类。 *

@@ -86,9 +87,7 @@ public String interpolate(String messageTemplate, Context context) { @Override public String interpolate(String messageTemplate, Context context, Locale locale) { - if (locale == null) { - throw new IllegalArgumentException("locale must not be null"); - } + Validation.notNull(locale, "Locale cannot be null."); return this.targetInterpolator.interpolate(messageTemplate, context, locale); } } \ No newline at end of file diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java index 81a99fd33..195d773a4 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/main/java/modelengine/fitframework/validation/ValidationHandler.java @@ -25,7 +25,6 @@ import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; -import javax.validation.MessageInterpolator; import javax.validation.Validation; import javax.validation.Validator; import javax.validation.ValidatorFactory; diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java index 651b06b0e..1a1fa4a31 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/LocaleValidationControllerTest.java @@ -6,6 +6,8 @@ package modelengine.fitframework.validation; +import static org.assertj.core.api.Assertions.assertThat; + import modelengine.fit.http.client.HttpClassicClientResponse; import modelengine.fit.http.entity.Entity; import modelengine.fit.http.entity.ObjectEntity; @@ -24,8 +26,6 @@ import java.io.IOException; import java.util.Map; -import static org.assertj.core.api.Assertions.assertThat; - /** * 表示评估国际化校验的测试类。 * diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java index d299bdfd5..ee3dad196 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/GroupValidateService.java @@ -33,9 +33,9 @@ public static class StudentValidateService { * @param age 表示年龄的 {@code int}。 */ public void validateStudentAge( - @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) @Max( - value = 20, message = "范围要在7~20之内", - groups = ValidationTestData.StudentGroup.class) int age) { + @Min(value = 7, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) + @Max(value = 20, message = "范围要在7~20之内", groups = ValidationTestData.StudentGroup.class) + int age) { LOG.debug("Validating student age: {}", age); } } @@ -49,9 +49,9 @@ public static class TeacherValidateService { * @param age 表示年龄的 {@code int}。 */ public void validateTeacherAge( - @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) @Max( - value = 65, message = "范围要在22~65之内", - groups = ValidationTestData.TeacherGroup.class) int age) { + @Min(value = 22, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) + @Max(value = 65, message = "范围要在22~65之内", groups = ValidationTestData.TeacherGroup.class) + int age) { LOG.debug("Validating teacher age: {}", age); } } diff --git a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java index 728a07601..41572320a 100644 --- a/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java +++ b/framework/fit/java/fit-builtin/plugins/fit-validation-hibernate-javax/src/test/java/modelengine/fitframework/validation/data/LocaleValidationController.java @@ -6,16 +6,15 @@ package modelengine.fitframework.validation.data; -import javax.validation.Valid; - +import modelengine.fit.http.annotation.PostMapping; +import modelengine.fit.http.annotation.RequestBody; +import modelengine.fit.http.annotation.RequestMapping; import modelengine.fitframework.annotation.Component; import modelengine.fitframework.validation.LocaleContextMessageInterpolator; import modelengine.fitframework.validation.Validated; import modelengine.fitframework.validation.ValidationHandler; -import modelengine.fitframework.validation.data.Company; -import modelengine.fit.http.annotation.PostMapping; -import modelengine.fit.http.annotation.RequestBody; -import modelengine.fit.http.annotation.RequestMapping; + +import javax.validation.Valid; /** * 用于测试 {@link ValidationHandler} 与 {@link LocaleContextMessageInterpolator} 的集成地区验证控制器。 diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java index 7072ea48d..f6c703d21 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/DefualtLocaleResolver.java @@ -11,7 +11,6 @@ import modelengine.fit.http.server.HttpClassicServerResponse; import modelengine.fitframework.util.StringUtils; -import java.util.List; import java.util.Locale; /** diff --git a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java index b6aaa913b..e629cfcd5 100644 --- a/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java +++ b/framework/fit/java/fit-builtin/services/fit-http-classic/definition/src/main/java/modelengine/fit/http/util/i18n/LocaleResolveFilter.java @@ -6,7 +6,11 @@ package modelengine.fit.http.util.i18n; -import modelengine.fit.http.server.*; +import modelengine.fit.http.server.DoHttpServerFilterException; +import modelengine.fit.http.server.HttpClassicServerRequest; +import modelengine.fit.http.server.HttpClassicServerResponse; +import modelengine.fit.http.server.HttpServerFilter; +import modelengine.fit.http.server.HttpServerFilterChain; import modelengine.fitframework.annotation.Scope; import modelengine.fitframework.inspection.Validation; import modelengine.fitframework.util.StringUtils;