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

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值