我的问题与本地化有关,我有JPA实体,其中包含fieldnameEN,fieldnameFR,fieldnameRU
等字段。我想写一些getter方法,它自动检测当前的语言环境并返回适当的字段。我正在使用facelets,这样的getter将帮助我调用getter并将本地化问题委托给后端。已存储在会话中并且获取它的区域设置不是问题。我知道如何手动执行此类方法,例如
getProperty(){
locale = takeFromSession();
if(locale=en) return getPropertyEN();
if(locale=fr) return getPropertyFR();
}
但我想在AspectJ或某些拦截器的帮助下保持DRY原则。
关于实现的当前想法 - 在每个getter调用determine running method name中,将Object状态传递给某个拦截器并在拦截器中执行区域设置检查,返回已经传递给拦截器的字段的适当值。
有没有解决此类问题的工作示例?
如何将对象状态传递给拦截器?
有没有更好的方法来解决我的问题?
更新
Kriegaex建议使用捆绑包。实际上,我们使用bundle来标记(标题和标题),但我们还需要本地化存储在数据库中的实体。捆绑包需要使用'哈希标记'作为.property文件中的键,但我不想将实体值存储为哈希标记。捆绑包将强制用户将业务值填充为“哈希标记”,我不喜欢这样做)
即使使用英语值作为键或某些哈希值,如果实体具有100个属性,我们需要进行100次查询。是的,我的意思是100个DB查询,因为存储在RAM中的AFAIK包可能不足以存储翻译,这就是为什么在我们的案例中捆绑应该在键值DB中。
关于重新编译 - 很可能我们只有3种语言,并且不需要按此方向进行扩展。
如果有人知道我的主题问题的答案,请分享一些小例子)
答案 0 :(得分:1)
AspectJ不打算用于修补错误的应用程序设计。我可以很容易地告诉你如何使用反射编写一些廉价的方面代码,以便为当前语言调用正确的getter,但是
也许您应该考虑使用资源包等标准方法作为您的属性名称。这样,您可以更改文本常量甚至添加新语言,而无需重新编译代码。因为国际化是一个贯穿各领域的问题,所以如果你想让它们远离核心代码,你仍然可以使用AspectJ来通过ITD(类型间定义)或其他方式为你的翻译声明访问方法。这样,您的核心代码可能完全与语言无关。
<强>更新强>
无论如何,如果你想要这么多,这里有一个样本,向你展示你可以用AOP做什么,即使用AspectJ。用户 gknicker 提出的解决方案类似,但它仅适用于一个类。我在一个方面保持代码分离,并可以同时将它应用于许多类。
计划是使用标记注释手动注释包含多语言字段标题的每个实体类。我编造了一个叫@Entity
的人。或者,您也可以通过其超类或类或包名称模式来确定目标类,AspectJ在这方面非常强大。正如我所说,这只是一个例子。
在下一步中,我们将定义执行以下操作的方面:
LocalisedCaption
。@Entity
类实现该接口,从而继承其方法。最后,但并非最不重要的是,我们将在示例应用程序中使用新方法。
package de.scrum_master.app;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Entity {}
package de.scrum_master.app;
@Entity
public class Person {
public static final String firstNameEN = "first name";
public static final String firstNameFR = "prénom";
public static final String firstNameRU = "и́мя";
public static final String lastNameEN = "last name";
public static final String lastNameFR = "nom de famille";
public static final String lastNameRU = "фами́лия";
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return "Person [firstName=" + firstName + ", lastName=" + lastName + "]";
}
}
package de.scrum_master.aspect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import de.scrum_master.app.Application;
import de.scrum_master.app.Entity;
public aspect EntityCaptionLocaliser {
public interface LocalisedCaption {
String getCaption(String attributeName);
}
declare parents :
@Entity * implements LocalisedCaption;
public String LocalisedCaption.getCaption(String attributeName)
throws ReflectiveOperationException
{
String fieldName = attributeName + Application.locale;
Field field = getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return (String) field.get(this);
}
public Map<String, String> LocalisedCaption.getAllCaptions()
throws ReflectiveOperationException
{
Map<String, String> captions = new HashMap<>();
for (Field field : getClass().getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers()))
continue;
String attributeName = field.getName();
captions.put(attributeName, getCaption(attributeName));
}
return captions;
}
public Map<String, Object> LocalisedCaption.getCaptionValuePairs()
throws ReflectiveOperationException
{
Map<String, Object> captions = new HashMap<>();
for (Field field : getClass().getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers()))
continue;
field.setAccessible(true);
String attributeName = field.getName();
captions.put(getCaption(attributeName), field.get(this));
}
return captions;
}
}
package de.scrum_master.app;
public class Application {
public static String locale = "EN";
public static void main(String[] args) throws Exception {
Person albert = new Person("Albert", "Einstein");
System.out.println("Showing localised captions for " + albert + ":");
locale = "EN";
System.out.println(albert.getAllCaptions());
System.out.println(albert.getCaptionValuePairs());
locale = "FR";
System.out.println(albert.getAllCaptions());
System.out.println(albert.getCaptionValuePairs());
locale = "RU";
System.out.println(albert.getAllCaptions());
System.out.println(albert.getCaptionValuePairs());
}
}
Application.main
的控制台输出:
Showing localised captions for Person [firstName=Albert, lastName=Einstein]:
{lastName=last name, firstName=first name}
{first name=Albert, last name=Einstein}
{lastName=nom de famille, firstName=prénom}
{nom de famille=Einstein, prénom=Albert}
{lastName=фами́лия, firstName=и́мя}
{фами́лия=Einstein, и́мя=Albert}
答案 1 :(得分:0)
最好使用标准Java i18n。
但是,如果你坚持追求当前的设计,这里有一个使用反射的例子。
public class Scratch
{
public static void main(String[] args)
{
System.out.println(new Scratch().getProperty());
}
String propertyEN = "want";
String propertyFR = "voulez";
public String getProperty()
{
return (String)getForLocale("property");
}
private Object getForLocale(String attributeName)
{
String fieldName = attributeName + getLocale();
try {
Field field = getClass().getDeclaredField(fieldName);
return field.get(this);
} catch (ReflectiveOperationException e) {
return e.getMessage();
}
}
private String getLocale()
{
return "EN"; // takeFromSession();
}
}