Commit 338e8e39 authored by 楊慶堂's avatar 楊慶堂

加上 cache 及加速

parent c65cebeb
......@@ -70,6 +70,23 @@
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<!--Ehcache-core 包 -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!--添加Hibernate-Ehcache包 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
......
package org.ylhealth.ym.springtest.controller;
import java.util.List;
import java.util.Locale;
import javax.inject.Inject;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.ylhealth.ym.springtest.entity.CrmSystemL1basic;
......@@ -10,8 +13,27 @@ import org.ylhealth.ym.springtest.repo.CrmSystemL1basicRepo;
public class I18NTestController {
@Inject CrmSystemL1basicRepo dao;
@GetMapping("/i18n/Test1")
public CrmSystemL1basic test1() {
@GetMapping("/i18n/Test11")
public CrmSystemL1basic test11() {
return dao.findOne("01");
}
@GetMapping("/i18n/Test12")
public CrmSystemL1basic test12() {
return dao.findByGroupCode("01");
}
@GetMapping("/i18n/Test13")
public List<CrmSystemL1basic> test13() {
return dao.findAll();
}
@GetMapping("/i18n/Test21")
public CrmSystemL1basic test21() {
LocaleContextHolder.setLocale(Locale.SIMPLIFIED_CHINESE);
return dao.findOne("01");
}
@GetMapping("/i18n/Test22")
public CrmSystemL1basic test22() {
LocaleContextHolder.setLocale(Locale.SIMPLIFIED_CHINESE);
return dao.findByGroupCode("01");
}
}
......@@ -2,6 +2,7 @@ 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.Cacheable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
......@@ -9,20 +10,27 @@ import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Nationalized;
import org.ylhealth.ym.springtest.hibernate.I18NTranslate;
import org.ylhealth.ym.springtest.hibernate.I18NTranslates;
import com.fasterxml.jackson.annotation.JsonIgnore;
/** CrmSystemL1basic generated by hbm2java */
@Entity
@Cacheable
@Table(name = "CRM_SystemL1Basic")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@I18NTranslates(
id = "groupCode",
table = "CRM_SystemL1Basic_translation",
mapping = {@I18NTranslate(column = "groupName", field = "groupName")})
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;
......
......@@ -6,7 +6,9 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.persistence.Id;
import org.hibernate.SQLQuery;
......@@ -14,6 +16,7 @@ import org.hibernate.StatelessSession;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PostLoadEventListener;
import org.hibernate.transform.Transformers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;
......@@ -22,17 +25,16 @@ 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();
private Cache<String, Map> cache =
CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.MINUTES).build();
public I18NReadEventListener(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
......@@ -43,45 +45,83 @@ public class I18NReadEventListener implements PostLoadEventListener {
public void onPostLoad(PostLoadEvent event) {
Object entity = event.getEntity();
Class clazz = entity.getClass();
Collection<Field> fields = getLocalizedFields(clazz);
if (!fields.isEmpty())
I18NTranslates i18n = entity.getClass().getAnnotation(I18NTranslates.class);
if (i18n != null) {
try (StatelessSession session =
sessionFactory.openStatelessSession(event.getSession().connection())) {
Object id = getPKValue(clazz, entity);
String language = LocaleContextHolder.getLocale().toString();
Map<String, String> translate = getTranslate(session, i18n, entity, clazz);
if (translate != null && !translate.isEmpty()) {
Field[] fields = clazz.getDeclaredFields();
for (I18NTranslate i18nTranslate : i18n.mapping()) {
for (Field field : fields) {
List result = getTranslate(session, id, field, language);
if (!result.isEmpty()) field.set(entity, result.get(0));
if (field.getName().equals(i18nTranslate.field())) {
field.setAccessible(true);
field.set(entity, translate.get(i18nTranslate.column()));
break;
}
}
}
}
} catch (Exception e) {
logger.error("ReadEventListener error", e);
throw new IllegalStateException();
}
}
}
/**
* @param i18n
* @param entity
* @param clazz
* @return
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
private Map<String, String> getTranslate(
StatelessSession session, I18NTranslates i18n, Object entity, Class clazz)
throws IllegalAccessException, InvocationTargetException {
Object id = getPKValue(clazz, entity);
String language = LocaleContextHolder.getLocale().toString();
String table = i18n.table();
String idColumn = i18n.id();
Map<String, Map<String, String>> translateTable =
translateTable(session, table, language, i18n.mapping(), idColumn);
return translateTable.get(id);
}
private List getTranslate(StatelessSession session, Object id, Field field, String language) {
String key = field + "_" + id + "_" + language;
List result = cache.getIfPresent(key);
private Map<String, Map<String, String>> translateTable(
StatelessSession session,
String table,
String language,
I18NTranslate[] mapping,
String idColumn) {
String key = "Table:" + table + "_" + language;
Map<String, Map<String, String>> 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);
logger.trace("translate query, table: {}", table);
String sql = String.format("select * from %s where languageCode = ?", table);
SQLQuery query1 = session.createSQLQuery(sql);
query1.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
query1.addScalar(idColumn);
for (I18NTranslate i18nTranslate : mapping) {
query1.addScalar(i18nTranslate.column());
}
query1.setParameter(0, language);
List<Map<String, String>> result1 = query1.list();
result = new HashMap<>();
for (Map<String, String> map : result1) {
result.put(map.get(idColumn), map);
}
cache.put(key, result);
}
return result;
}
public static Object getPKValue(Class<?> clazz, Object entity)
private Object getPKValue(Class<?> clazz, Object entity)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Collection<Field> fields = getAllDeclaredFields(clazz);
for (Field field : fields) {
......
......@@ -9,26 +9,17 @@ import java.lang.annotation.Target;
* 利用 annotation 處理多國語系轉換
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Target({ElementType.TYPE})
public @interface I18NTranslate {
/**
* 對應的欄位
* Entity class 的欄位(注意大小寫)
* @return
*/
String column() default "";
String field();
/**
* 對應的 id
* 翻譯表格對應的欄位
* @return
*/
String id() default "";
/**
* 翻譯的表格
* @return
*/
String table() default "";
String column();
}
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;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface I18NTranslates {
/**
* 翻譯表格對應的資料 id 欄位
*
* @return
*/
String id();
/**
* 翻譯的表格
*
* @return
*/
String table();
/**
* 要翻譯的資料欄位對應
*/
I18NTranslate[] mapping();
}
package org.ylhealth.ym.springtest.repo;
import javax.persistence.QueryHint;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.QueryHints;
import org.ylhealth.ym.springtest.entity.CrmSystemL1basic;
public interface CrmSystemL1basicRepo extends JpaRepository<CrmSystemL1basic, String> {}
public interface CrmSystemL1basicRepo extends JpaRepository<CrmSystemL1basic, String> {
@QueryHints({ @QueryHint(name = "org.hibernate.cacheable", value ="true") })
CrmSystemL1basic findByGroupCode(String groupCode);
}
......@@ -21,6 +21,10 @@ spring:
format_sql: false
dialect: org.ylhealth.ym.springtest.hibernate.SqlServerDialectWithNvarchar
globally_quoted_identifiers: true
cache.use_second_level_cache: true
cache.use_query_cache: true
cache.region.factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
generate_statistics: true
temp:
use_jdbc_metadata_defaults: false
......
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
monitoring="autodetect" dynamicConfig="true">
<diskStore path="java.io.tmpdir/ehcache" />
<defaultCache maxEntriesLocalHeap="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"
maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU" statistics="true">
<persistence strategy="localTempSwap" />
</defaultCache>
<cache name="org.ylhealth.ym.springtest.entity.CrmSystemL1basic" maxEntriesLocalHeap="10000" eternal="false"
timeToIdleSeconds="5" timeToLiveSeconds="10">
<persistence strategy="localTempSwap" />
</cache>
<cache name="org.hibernate.cache.internal.StandardQueryCache"
maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="120">
<persistence strategy="localTempSwap" />
</cache>
<cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
maxEntriesLocalHeap="5000" eternal="true">
<persistence strategy="localTempSwap" />
</cache>
</ehcache>
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