Commit c65cebeb authored by 楊慶堂's avatar 楊慶堂

增加 annotation 處理多國語系

parent 7fe8b7f6
Pipeline #17 failed with stages
...@@ -64,6 +64,12 @@ ...@@ -64,6 +64,12 @@
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId> <artifactId>spring-aspects</artifactId>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
...@@ -75,7 +81,7 @@ ...@@ -75,7 +81,7 @@
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId> <artifactId>aspectj-maven-plugin</artifactId>
<version>1.6</version> <version>1.11</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
......
package org.ylhealth.ym.springtest.controller;
import javax.inject.Inject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.ylhealth.ym.springtest.entity.CrmSystemL1basic;
import org.ylhealth.ym.springtest.repo.CrmSystemL1basicRepo;
@RestController
public class I18NTestController {
@Inject CrmSystemL1basicRepo dao;
@GetMapping("/i18n/Test1")
public CrmSystemL1basic test1() {
return dao.findOne("01");
}
}
...@@ -15,7 +15,7 @@ public class TestController { ...@@ -15,7 +15,7 @@ public class TestController {
@GetMapping("/Test1") @GetMapping("/Test1")
public UserInfo test1() { public UserInfo test1() {
return userInfoService.findUserInfo("aaa1"); return userInfoService.findUserInfo("aaa");
} }
@GetMapping("/create") @GetMapping("/create")
......
package org.ylhealth.ym.springtest.entity;
// Generated Jul 20, 2016 5:22:20 PM by Hibernate Tools 3.2.2.GA
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Nationalized;
import org.ylhealth.ym.springtest.hibernate.I18NTranslate;
import com.fasterxml.jackson.annotation.JsonIgnore;
/** CrmSystemL1basic generated by hbm2java */
@Entity
@Table(name = "CRM_SystemL1Basic")
public class CrmSystemL1basic implements java.io.Serializable {
private String groupCode;
private String func;
@I18NTranslate(column="groupName", id="groupCode", table = "CRM_SystemL1Basic_translation")
private String groupName;
private Character codeStatus;
private String status;
@JsonIgnore private String modifiedId;
@JsonIgnore private Date modifiedTime;
private Integer listSeq;
public CrmSystemL1basic() {}
public CrmSystemL1basic(
String groupCode,
String func,
String groupName,
String status,
String modifiedId,
Date modifiedTime) {
this.groupCode = groupCode;
this.func = func;
this.groupName = groupName;
this.status = status;
this.modifiedId = modifiedId;
this.modifiedTime = modifiedTime;
}
public CrmSystemL1basic(
String groupCode,
String func,
String groupName,
Character codeStatus,
String status,
String modifiedId,
Date modifiedTime,
Integer listSeq) {
this.groupCode = groupCode;
this.func = func;
this.groupName = groupName;
this.codeStatus = codeStatus;
this.status = status;
this.modifiedId = modifiedId;
this.modifiedTime = modifiedTime;
this.listSeq = listSeq;
}
@Id
@GenericGenerator(name = "increment", strategy = "uuid2")
@GeneratedValue(generator = "increment")
@Column(name = "GroupCode", unique = true, nullable = false, length = 20)
public String getGroupCode() {
return this.groupCode;
}
public void setGroupCode(String groupCode) {
this.groupCode = groupCode;
}
@Column(name = "Func", nullable = false, length = 20)
public String getFunc() {
return this.func;
}
public void setFunc(String func) {
this.func = func;
}
@Nationalized
@Column(name = "GroupName", nullable = false, length = 50)
public String getGroupName() {
return this.groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
@Column(name = "CodeStatus", length = 1)
public Character getCodeStatus() {
return this.codeStatus;
}
public void setCodeStatus(Character codeStatus) {
this.codeStatus = codeStatus;
}
@Column(name = "Status", nullable = false, length = 1)
public String getStatus() {
return this.status;
}
public void setStatus(String status) {
this.status = status;
}
@Column(name = "ModifiedId", nullable = false, length = 20)
public String getModifiedId() {
return this.modifiedId;
}
public void setModifiedId(String modifiedId) {
this.modifiedId = modifiedId;
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "ModifiedTime", nullable = false, length = 23)
public Date getModifiedTime() {
return this.modifiedTime;
}
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
@Column(name = "ListSeq")
public Integer getListSeq() {
return this.listSeq;
}
public void setListSeq(Integer listSeq) {
this.listSeq = listSeq;
}
}
package org.ylhealth.ym.springtest.hibernate;
import org.hibernate.boot.Metadata;
import org.hibernate.cfg.beanvalidation.DuplicationStrategyImpl;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 運用 org.hibernate.integrator.spi.Integrator 處理多國語系基本檔
* 參考:
* https://github.com/deathman92/localized
*/
public class I18NInterceptor implements Integrator {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
logger.debug("integrate...");
final EventListenerRegistry eventListenerRegistry =
serviceRegistry.getService(EventListenerRegistry.class);
eventListenerRegistry.addDuplicationStrategy(DuplicationStrategyImpl.INSTANCE);
eventListenerRegistry.appendListeners(
EventType.POST_LOAD, new I18NReadEventListener(sessionFactory));
}
@Override
public void disintegrate(
SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
logger.debug("disintegrate...");
}
}
package org.ylhealth.ym.springtest.hibernate;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.persistence.Id;
import org.hibernate.SQLQuery;
import org.hibernate.StatelessSession;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PostLoadEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
/** */
public class I18NReadEventListener implements PostLoadEventListener {
/**
*
*/
private static final long serialVersionUID = -7374424944903271183L;
private Logger logger = LoggerFactory.getLogger(getClass());
private SessionFactoryImplementor sessionFactory;
@SuppressWarnings("rawtypes")
private Cache<String, List> cache =
CacheBuilder.newBuilder().expireAfterAccess(30, TimeUnit.MINUTES).build();
public I18NReadEventListener(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
}
@SuppressWarnings("rawtypes")
@Override
public void onPostLoad(PostLoadEvent event) {
Object entity = event.getEntity();
Class clazz = entity.getClass();
Collection<Field> fields = getLocalizedFields(clazz);
if (!fields.isEmpty())
try (StatelessSession session =
sessionFactory.openStatelessSession(event.getSession().connection())) {
Object id = getPKValue(clazz, entity);
String language = LocaleContextHolder.getLocale().toString();
for (Field field : fields) {
List result = getTranslate(session, id, field, language);
if (!result.isEmpty()) field.set(entity, result.get(0));
}
} catch (Exception e) {
logger.error("ReadEventListener error", e);
throw new IllegalStateException();
}
}
private List getTranslate(StatelessSession session, Object id, Field field, String language) {
String key = field + "_" + id + "_" + language;
List result = cache.getIfPresent(key);
if (result == null) {
I18NTranslate localized = field.getAnnotation(I18NTranslate.class);
String sql =
String.format(
"select %s from %s where %s = ? and languageCode = ?",
localized.column(), localized.table(), localized.id());
SQLQuery query = session.createSQLQuery(sql);
query.setParameter(0, id);
query.setParameter(1, language);
result = query.list();
logger.info("SQL: {}: {}", sql, result);
cache.put(key, result);
}
return result;
}
public static Object getPKValue(Class<?> clazz, Object entity)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Collection<Field> fields = getAllDeclaredFields(clazz);
for (Field field : fields) {
if (field.getAnnotation(Id.class) != null) {
field.setAccessible(true);
return field.get(entity);
}
}
for (Method method : clazz.getDeclaredMethods()) {
if (method.getAnnotation(Id.class) != null) {
return method.invoke(entity, null);
}
}
return null;
}
/**
* Returns the entity's @{@link I18NTranslate} fields.
*
* <p>These fields are made accessible.
*/
private static Collection<Field> getLocalizedFields(Class<?> clazz) {
Collection<Field> fields = getAllDeclaredFields(clazz);
List<Field> localizedFields = new ArrayList<>();
fields
.stream()
.filter(field -> field.getAnnotation(I18NTranslate.class) != null)
.forEach(
field -> {
field.setAccessible(true);
localizedFields.add(field);
});
return localizedFields;
}
private static Collection<Field> getAllDeclaredFields(Class<?> clazz) {
List<Field> fields = new ArrayList<>();
Collections.addAll(fields, clazz.getDeclaredFields());
if (clazz.getSuperclass() != null) {
fields.addAll(getAllDeclaredFields(clazz.getSuperclass()));
}
return fields;
}
}
package org.ylhealth.ym.springtest.hibernate;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 利用 annotation 處理多國語系轉換
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface I18NTranslate {
/**
* 對應的欄位
* @return
*/
String column() default "";
/**
* 對應的 id
* @return
*/
String id() default "";
/**
* 翻譯的表格
* @return
*/
String table() default "";
}
package org.ylhealth.ym.springtest.hibernate;
import java.sql.Types;
import org.hibernate.dialect.SQLServer2012Dialect;
public class SqlServerDialectWithNvarchar extends SQLServer2012Dialect {
public SqlServerDialectWithNvarchar() {
registerHibernateType(Types.NVARCHAR, 4000, "string");
}
}
package org.ylhealth.ym.springtest.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import org.ylhealth.ym.springtest.entity.CrmSystemL1basic;
public interface CrmSystemL1basicRepo extends JpaRepository<CrmSystemL1basic, String> {}
org.ylhealth.ym.springtest.hibernate.I18NInterceptor
\ No newline at end of file
...@@ -19,7 +19,7 @@ spring: ...@@ -19,7 +19,7 @@ spring:
hibernate: hibernate:
show_sql: true show_sql: true
format_sql: false format_sql: false
dialect: org.hibernate.dialect.SQLServer2012Dialect dialect: org.ylhealth.ym.springtest.hibernate.SqlServerDialectWithNvarchar
globally_quoted_identifiers: true globally_quoted_identifiers: true
temp: temp:
use_jdbc_metadata_defaults: false use_jdbc_metadata_defaults: false
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment