springmvc +mybatis 動態國際化(使用數據庫保存國際化配置)

springMVC的動態國際化,是使用數據庫保存國際化對應的value值,系統啓動後加載所有國際化配置到緩存(也可以直接讀取數據庫,效率低,不推薦),修改數據庫中對應的國際化value值後刷新。自定義國際化的解析類,從緩存中取得對應的value值

1.定義國際化對應的實體類,以及對應的mybatis mapper類

//entry
public class SysMessageResource implement Serializable {
	
	private static final long serialVersionUID = 1L;
	private String code;		// 鍵值
	private String lang;		// 國家區域
	private String label;		// 顯示的標籤
	
	//....
	
}

// mapper
public class SysMessageResourceMapper {

    List<SysMessageResource> findList(SysMessageResource resource);
    // insert
    // update
    // delete
}

2.定義SpringContextHolder:

可以根據class直接獲取對應的spring容器管理的對象,(因爲我是在Utils的static塊中加載的國際化資源,不能使用@autowried注入,當然也可以不用該方法,可以將Utils標爲spring對象,繼承InitializingBean,在afterPropertiesSet方法中加載國際化資源)

@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {

	private static ApplicationContext applicationContext = null;

	private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);

	/**
	 * 取得存儲在靜態變量中的ApplicationContext.
	 */
	public static ApplicationContext getApplicationContext() {
		assertContextInjected();
		return applicationContext;
	}

	/**
	 * 從靜態變量applicationContext中取得Bean, 自動轉型爲所賦值對象的類型.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		assertContextInjected();
		return (T) applicationContext.getBean(name);
	}

	/**
	 * 從靜態變量applicationContext中取得Bean, 自動轉型爲所賦值對象的類型.
	 */
	public static <T> T getBean(Class<T> requiredType) {
		assertContextInjected();
		return applicationContext.getBean(requiredType);
	}

	/**
	 * 清除SpringContextHolder中的ApplicationContext爲Null.
	 */
	public static void clearHolder() {
		if (logger.isDebugEnabled()){
			logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
		}
		applicationContext = null;
	}

	/**
	 * 實現ApplicationContextAware接口, 注入Context到靜態變量中.
	 */
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) {
		SpringContextHolder.applicationContext = applicationContext;
	}

	public static  String getStatic(){
		return SpringContextHolder.getApplicationContext().getApplicationName()+ "/static";
	}
	/**
	 * 實現DisposableBean接口, 在Context關閉時清理靜態變量.
	 */
	@Override
	public void destroy() throws Exception {
		SpringContextHolder.clearHolder();
	}

	/**
	 * 檢查ApplicationContext不爲空.
	 */
	private static void assertContextInjected() {
		Validate.validState(applicationContext != null, "applicaitonContext屬性未注入, 請在applicationContext.xml中定義SpringContextHolder.");
	}
}

 

3.定義ResourceUtils類,用來加載國際化資源到緩存,或者更新緩存,要在對應的mapper執行插入,更新,刪除後執行該utils對應的方法更新緩存,或者reload

public class MessageResourceUtils {
	private static Logger logger = LoggerFactory.getLogger(MessageResourceUtils.class);
//可以使用別的方式,查詢數據庫
	private static SysMessageResourceMapper sysMessageResourceMapper = SpringContextHolder.getBean(SysMessageResourceMapper.class);
        public static final String MESSAGE_SOURCE_KEY = "message.source.key";
	static {
		reloadCache();
	}
	
	/**
	 * 根據local獲取bundle
	 * @param locale
	 * @return
	 */
	public static Properties getResourceProperties(Locale locale){
		return getResourceMap().get(locale);
	}
	
	/**
	 * get resource map of all locale
	 * @return
	 */
	public static Map<Locale, Properties> getResourceMap() {
		Map<Locale, Properties> localeMap = (Map<Locale, Properties>) CacheUtils.get(MESSAGE_SOURCE_KEY);
		if (localeMap == null) {
			localeMap = generateLocaleProperties();
			CacheUtils.put(MESSAGE_SOURCE_KEY, localeMap);
		}
		return localeMap;
	}
	
	/**
	 * reload message resource
	 */
	public static void reloadCache() {
// 可以使用別的緩存方式,可以選擇多種方式,在此不提供緩存實現
		CacheUtils.put(MESSAGE_SOURCE_KEY, generateLocaleProperties());
	}
	/**
	 * 清除Message緩存
	 * @param user
	 */
	public static void clearCache(){
		CacheUtils.remove(MESSAGE_SOURCE_KEY);
	}
	
	/**
	 * reload message 
	 * @param locale locale
	 */
	public static void reloadLocaleMessage(Locale locale) {
		if (locale == null) {
			return;
		}
		Map<Locale, Properties> localeMap = getResourceMap();
		SysMessageResource search = new SysMessageResource();
		search.setLang(locale.toString());
		List<SysMessageResource> resourcesList = sysMessageResourceMapper.findList(search);
		Properties prop = new Properties();
		for (SysMessageResource messageResource : resourcesList) {
			if (StringUtils.isBlank(messageResource.getLang()) || StringUtils.isBlank(messageResource.getCode())) {
				continue;
			}
			prop.put(messageResource.getCode(), StringUtils.defaultString(messageResource.getLabel()));
		}
		
		localeMap.put(locale, prop);
		
	}
	
	/**
	 * insert message
	 * @param resource
	 */
	public static void insertMessageResource(SysMessageResource resource) {
		if (StringUtils.isBlank(resource.getLang()) || StringUtils.isBlank(resource.getCode())) {
			return;
		}
		Locale locale = org.springframework.util.StringUtils.parseLocaleString(resource.getLang());
		
		if (locale != null) {
			Properties prop = getResourceProperties(locale);
			if (prop == null) {
				prop = new Properties();
				getResourceMap().put(locale, prop);
			}
			prop.put(resource.getCode(), resource.getLabel());
		}
	}
	
	/**
	 * update message
	 * @param resource
	 */
	public static void updateMessageResource(SysMessageResource resource) {
		insertMessageResource(resource);
	}
	
	/**
	 * delete message
	 * @param resource
	 */
	public static void deleteMessageResource(SysMessageResource resource) {
		if (StringUtils.isBlank(resource.getLang()) || StringUtils.isBlank(resource.getCode())) {
			return;
		}
		Locale locale = org.springframework.util.StringUtils.parseLocaleString(resource.getLang());
		
		if (locale != null) {
			Properties prop = getResourceProperties(locale);
			if (prop != null) {
				prop.remove(resource.getCode());
			}
		}
	}
	/**
	 * load all message
	 * @return
	 */
	private static Map<Locale, Properties> generateLocaleProperties() {
		Map<Locale, Properties> localPropertiesMap = new HashMap<>();
		List<SysMessageResource> resourcesList = Collections.emptyList();
		
		try {
			resourcesList = sysMessageResourceMapper.findList(new SysMessageResource());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.warn("Query messageResource from database error");
		}
		
		for (SysMessageResource messageResource : resourcesList) {
			if (StringUtils.isBlank(messageResource.getLang()) || StringUtils.isBlank(messageResource.getCode())) {
				continue;
			}
			Locale locale = org.springframework.util.StringUtils.parseLocaleString(messageResource.getLang());
			
			if (locale != null) {
				Properties prop = localPropertiesMap.get(locale);
				if (prop == null) {
					prop = new Properties();
					localPropertiesMap.put(locale, prop);
				}
				prop.put(messageResource.getCode(), StringUtils.defaultString(messageResource.getLabel()));
			}
		}
		
		return localPropertiesMap;
	}
}

4.定義message解析類,繼承自spring的AbstractMessageSource :

public class ResourceBundleMessageSource extends AbstractMessageSource {


	public ResourceBundleMessageSource() {
		super();

	}

	@Override
	protected MessageFormat resolveCode(String code, Locale locale) {
		
		Properties prop = MessageResourceUtils.getResourceProperties(locale);
		
		if (prop != null) {
			String label = prop.getProperty(code);
			if (label != null) {
				return createMessageFormat(label, locale);
			}
		}
		return null;
	}
}

5. spring-mvc.xml 配置對應的messageSource,以及攔截器

<!-- 攔截器配置,攔截順序:先執行後定義的,排在第一位的最後執行。-->
	<mvc:interceptors>
		<!-- 國際化操作攔截器 如果採用基於(請求/Session/Cookie)則必需配置 --> 
	    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />  
	</mvc:interceptors>
	
	<!-- 支持Shiro對Controller的方法級AOP安全控制 begin-->
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
		<property name="proxyTargetClass" value="true" />
	</bean>
	
	<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
		<property name="exceptionMappings">
			<props>
				<prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop>
				<prop key="java.lang.Throwable">error/500</prop>
			</props>
			</property>
	</bean>
	<!-- 支持Shiro對Controller的方法級AOP安全控制 end -->

	
	
		<!-- 國際化 -->
	<bean id="baseMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
	    <!-- 國際化信息所在的文件名 -->                     
<!-- 	    <property name="basename" value="messages" /> -->
	</bean>
	
	<bean id="messageSource" class="com.wenbo.common.bundle.ResourceBundleMessageSource">
	    <!-- 如果在國際化資源文件中找不到對應代碼的信息,就用這個代碼作爲名稱  -->  
	    <property name="parentMessageSource" ref="baseMessageSource" />             
		<property name="useCodeAsDefaultMessage" value="true" />           
	</bean>
	
<!-- session 方式 -->
	<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver" >
		<property name="defaultLocale" value="en_US" />
	</bean>

     <!-- cookie 方式 
    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" />
-->

使用方式和使用properties國際化一樣,可以參考:

https://blog.csdn.net/D939030515/article/details/64906101

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章