zoukankan      html  css  js  c++  java
  • [Spring MVC]

    Spring MVC中使用MessageSource默认是写在properties文件当中,以支持国际化。

    但很多时候我们需要把数据写到数据库当中,而不是在properties文件当中,以方便日常维护。

    1、先看Spring配置

        <!-- 默认的注解映射的支持 -->
        <mvc:annotation-driven validator="validator" conversion-service="conversionService" />
    
        <!-- 资源文件 -->
        <bean id="propertiesMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
            <property name="basenames">
                <list>
                    <value>resource</value>
                    <value>validation</value>
                </list>
            </property>
        </bean>
        <bean id="databaseMessageSource" class="com.obs2.util.MessageResource">
            <property name="parentMessageSource" ref="propertiesMessageSource"/>
        </bean>
        <bean id="messageInterpolator" class="com.obs2.util.MessageResourceInterpolator">
            <property name="messageResource" ref="databaseMessageSource"/>
        </bean>
        <!-- 验证器 -->
        <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
            <property name="messageInterpolator" ref="messageInterpolator"/>
        </bean>

    这里定义了一个propertiesMessageSource,一个databaseMessageSourcer,和一个messageInterpolator。

    propertiesMessageSource用于读取properties文件

    databaseMessageSourcer用于读取数据库的数据配置,其中,有一个属性设置它的父MessageSource为propertiesMessageSource。意思是如果数据库找不到对应的数据,到properties文件当中查找。

    messageInterpolator是个拦截器。

    2、数据库的POJO定义:

    package com.obs2.dao.impl.bean;
    
    import java.io.Serializable;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Entity
    @SuppressWarnings("serial")
    @Table(name="resource")
    public class Resource implements Serializable {
        
        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name="resource_id")
        private long resourceId;
        
        @Column(name="name", length=50, nullable=false)
        private String name;
        
        @Column(name="text", length=1000, nullable=false)
        private String text;
        
        @Column(name="language", length=5, nullable=false)
        private String language;
        
        public long getResourceId() {
            return resourceId;
        }
        public void setResourceId(long resourceId) {
            this.resourceId = resourceId;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getText() {
            return text;
        }
        public void setText(String text) {
            this.text = text;
        }
        public String getLanguage() {
            return language;
        }
        public void setLanguage(String language) {
            this.language = language;
        }
    
    }

    定义了一张表[resource],字段有:[resource_id]、[name]、[text]、[language]

    具体的DAO、Service操作方法这里忽略不写了。

    3、读取数据库的MessageResource类

    package com.obs2.util;
    
    import java.text.MessageFormat;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Locale;
    import java.util.Map;
    
    import javax.annotation.Resource;
    
    import org.springframework.context.ResourceLoaderAware;
    import org.springframework.context.support.AbstractMessageSource;
    import org.springframework.core.io.DefaultResourceLoader;
    import org.springframework.core.io.ResourceLoader;
    
    import com.obs2.service.ResourceService;
    
    /**
     * 取得资源数据
     * @author Robin
     *
     */
    public class MessageResource extends AbstractMessageSource implements ResourceLoaderAware {
    
        @SuppressWarnings("unused")
        private ResourceLoader resourceLoader;
        
        @Resource
        private ResourceService resourceService;
        
        /**
         * Map切分字符
         */
        protected final String MAP_SPLIT_CODE = "|";
        
        protected final String DB_SPLIT_CODE = "_";
        
        private final Map<String, String> properties = new HashMap<String, String>();
        
        public MessageResource() {
    //        reload();
        }
        
        public void reload() {
            properties.clear();
            properties.putAll(loadTexts());
        }
    
        protected Map<String, String> loadTexts() {
            Map<String, String> mapResource = new HashMap<String, String>();
            List<com.obs2.service.bean.Resource> resources = resourceService.findAll();
            for (com.obs2.service.bean.Resource item : resources) {
                String code = item.getName() + MAP_SPLIT_CODE + item.getLanguage();
                mapResource.put(code, item.getText());
            }
            return mapResource;
        }
        
        private String getText(String code, Locale locale) {
            String localeCode = locale.getLanguage() + DB_SPLIT_CODE + locale.getCountry();
            String key = code + MAP_SPLIT_CODE + localeCode;
            String localeText = properties.get(key);
            String resourceText = code;
            
            if(localeText != null) {
                resourceText = localeText;
            }
            else {
                localeCode = Locale.ENGLISH.getLanguage();
                key = code + MAP_SPLIT_CODE + localeCode;
                localeText = properties.get(key);
                if(localeText != null) {
                    resourceText = localeText;
                }
                else {
                    try {
                        if(getParentMessageSource() != null) {
                            resourceText = getParentMessageSource().getMessage(code, null, locale);
                        }
                    } catch (Exception e) {
                        logger.error("Cannot find message with code: " + code);
                    }
                }
            }
            return resourceText;
        }
        
        @Override
        public void setResourceLoader(ResourceLoader resourceLoader) {
            this.resourceLoader = (resourceLoader != null ? resourceLoader : new DefaultResourceLoader());
        }
    
        @Override
        protected MessageFormat resolveCode(String code, Locale locale) {
            String msg = getText(code, locale);
            MessageFormat result = createMessageFormat(msg, locale);
            return result;
        }
        
        @Override
        protected String resolveCodeWithoutArguments(String code, Locale locale) {
            String result = getText(code, locale);
            return result;
        }
    
    }

    主要是重载AbstractMessageSource和ResourceLoaderAware,以实现Spring MVC的MessageSource国际化调用。

    类中的reload()方法,我把它写到了一个ServletListener当中,让项目启动时,自动加载数据到static的map中。

    4、这是Listener:

    package com.obs2.util;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextAttributeEvent;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.http.HttpSessionEvent;
    
    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    
    /**
     * 系统启动监听
     * @author Robin
     *
     */
    public class SystemListener implements ServletContextListener {
        
        /**
         * context初始化时激发
         */
        @Override
        public void contextInitialized(ServletContextEvent e) {
            //------------------------------------------------------------
            // 取得ServletContext
            //------------------------------------------------------------
            ServletContext context = e.getServletContext();
            WebApplicationContext applicationContext  = WebApplicationContextUtils .getWebApplicationContext(context);
            
            //------------------------------------------------------------
            // 设置国际化多语言
            //------------------------------------------------------------
            MessageResource messageSource = applicationContext.getBean(MessageResource.class);
            messageSource.reload();
        }
    
        /**
         * context删除时激发
         */
        @Override
        public void contextDestroyed(ServletContextEvent e) {
        }
        
        /**
         * 创建一个 session时激发
         * @param e
         */
        public void sessionCreated(HttpSessionEvent e) {
        }
        
        /**
         * 当一个 session失效时激发
         * @param e
         */
        public void sessionDestroyed(HttpSessionEvent e) {
        }
        
        /**
         * 设置 context的属性,它将激发attributeReplaced或attributeAdded方法
         * @param e
         */
        public void setContext(HttpSessionEvent e) {
        }
        
        /**
         * 增加一个新的属性时激发
         * @param e
         */
        public void attributeAdded(ServletContextAttributeEvent e) {
        }
        
        /**
         * 删除一个新的属性时激发
         * @param e
         */
        public void attributeRemoved(ServletContextAttributeEvent e) {
        }
        
        /**
         * 属性被替代时激发
         * @param e
         */
        public void attributeReplaced(ServletContextAttributeEvent e) {
        }
    
    }

    当然了,Listener需要加入到web.xml当中:

        <!-- 系统启动监听 -->
        <listener>
            <listener-class>com.obs2.util.SystemListener</listener-class>
        </listener>

    4、Interceptor拦截器

    package com.obs2.util;
    
    import java.text.MessageFormat;
    import java.util.Iterator;
    import java.util.Locale;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import javax.annotation.Resource;
    import javax.validation.MessageInterpolator;
    
    import org.springframework.binding.message.MessageBuilder;
    
    /**
     * 拦截Annotation验证信息
     * @author Robin
     *
     */
    public class MessageResourceInterpolator implements MessageInterpolator {
        
        @Resource
        private MessageResource messageResource;
        public void setMessageResource(MessageResource messageResource) {
            this.messageResource = messageResource;
        }
    
        @Override
        public String interpolate(String messageTemplate, Context context) {
            
            String messageTemp = null;
            if(messageTemplate.startsWith("{") && messageTemplate.endsWith("}")) {
                messageTemp = messageTemplate.substring(1, messageTemplate.length() - 1);
            }
            else {
                return messageTemplate;
            }
            
            String[] params = (String[]) context.getConstraintDescriptor().getAttributes().get("params");
             
            MessageBuilder builder = new MessageBuilder().code(messageTemp);
            if (params != null) {
                for (String param : params) {
                    builder = builder.arg(param);
                }
            }
     
            String result = builder.build().resolveMessage(messageResource, Locale.ENGLISH).getText();
            return result;
        }
    
        @Override
        public String interpolate(String messageTemplate, Context context, Locale locale) {
            
            String messageTemp = null;
            if(messageTemplate.startsWith("{") && messageTemplate.endsWith("}")) {
                messageTemp = messageTemplate.substring(1, messageTemplate.length() - 1);
            }
            else {
                return messageTemplate;
            }
            
            String[] params = (String[]) context.getConstraintDescriptor().getAttributes().get("params");
             
            MessageBuilder builder = new MessageBuilder().code(messageTemp);
            if (params != null) {
                builder = builder.args(params);
            }
            
            String result = builder.build().resolveMessage(messageResource, locale).getText();
            return result;
        }
    
    }

    事实上,不使用拦截器,上面的数据库MessageSource类已经可以工作了。但在使用hibernate的Annotation的validator时,不加入拦截器,是不行的,它不会触发。

    这类里调用了一个jar包:spring-binding-2.3.1.RELEASE.jar

    自行上网搜搜下载。

    一切完成,测试下,写一个domain entity:

    package com.obs2.controller.bean;
    
    import javax.validation.constraints.Min;
    
    import org.hibernate.validator.constraints.NotEmpty;
    
    import com.obs2.controller.validator.UserName;
    
    public class Account {
        
        @UserName(format="^[\w_]+$", message="{valid.userName}", min=6, max=30)
        private String userName;
        @NotEmpty(message="{valid.required}")
        private String password;
        @Min(value=18, message="{valid.ageMin}")
        private int age;
        
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    
    }

    写一个简单的view(这里使用的是freemarker)

    <#assign c=JspTaglibs["http://java.sun.com/jsp/jstl/core"] />
    <#assign fmt=JspTaglibs["http://java.sun.com/jsp/jstl/fmt"] />
    <#assign fn=JspTaglibs["http://java.sun.com/jsp/jstl/functions"] />
    <#assign st=JspTaglibs["http://www.springframework.org/tags"] />
    <#assign form=JspTaglibs["http://www.springframework.org/tags/form"] />
    <head>
        <title>Login</title>
    </head>
    
    <body>
        <@form.form action="${request.contextPath}/passport/login" method="post" modelAttribute="account">
        User name:<@form.input path="userName"/><@form.errors path="userName"/><br/>
        Password:<@form.password path="password"/><@form.errors path="password" /><br/>
        Age:<@form.input path="age"/><@form.errors path="age" /><br/>
        <input type="submit" value="Login" />
        </@form.form>
    </body>

    将看到:

    这种方法还有一个小BUG,就是在使用annotation validator时,如果使用了替换符,似乎不起作用。暂时没研究出来,谁搞出来了,麻烦留个言提示下。so thx.

    代码中直接调用,可以这样写:

    resource.getMessage("valid.ageMin", new Object[]{"age",18}, request.getLocale())
  • 相关阅读:
    flask+Gunicorn+nginx部署
    配置Django实现数据库读写分离
    mysql分库分表
    python的反射
    flask-restful的使用
    spring源码(4)
    spring源码(3)
    spring源码(2)
    spring源码(1)
    tomcat8.5 配置数据源
  • 原文地址:https://www.cnblogs.com/HD/p/4167331.html
Copyright © 2011-2022 走看看