如何通過properties文件配置web.xml中的參數
前言
因為公司項目需要,目前有本地環境、測試環境、開發環境。每次在將項目打包成war包的時候,都需要修改多處的配置,而使用maven的profile打包項目的時候,可以根據執行打包命令時所帶的參數來進行自動修改。
但是這種方式隻對properties文件生效,即可以自動修改properties中的參數,但是公司的項目有一個web.xml中的配置參數也需要修改,這時候就要考慮如何通過properties文件動態修改web.xml中的參數瞭。
實現思路
web.xml中需要修改的部分
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="true"> <!--用maven創建的web-app需要修改servlet的版本為3.1 --> <welcome-file-list> <welcome-file>/index.jsp</welcome-file> </welcome-file-list> <!--配置DispatcherServlet --> <servlet> <servlet-name>mypage-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置SpringMVC 需要配置的文件 spring-dao.xml,spring-service.xml,spring-web.xml Mybites -> spring -> springMvc --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-*.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mypage-dispatcher</servlet-name> <!--默認匹配所有請求 --> <url-pattern>/</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> <filter> <filter-name>testFilter</filter-name> <filter-class>com.solr.filter.StringFilter</filter-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value> com.sgm.tac.tid.common.action; </param-value> </init-param> </filter> <filter-mapping> <filter-name>testFilter</filter-name> <url-pattern>*.*</url-pattern> </filter-mapping> </web-app>
這裡需要改動的是45行,這是過濾器的初始化參數。不同的環境這裡的參數是不一樣的,開始的思路是能否像application.xml中加載的properties文件一樣,通過${username}這種方式獲取properties中username對應的value。但是後來發現在web.xml中貌似是不好實現的。
在這樣的需求下,web.xml就需要以編碼的方式來實現配置。spring4.0以上的版本支持web.xml的編碼配置。實現AbstractAnnotationConfigDispatcherServletInitializer接口,在servlet3.0中web.xml啟動時會檢測該接口實現類,從能夠在實現類中去配置filter。
需要註意的是以上的實現,依賴servlet-api-3.0.jar和spring-webmvc-4.0以上版本jar包。
配置web.xml的類
package com.solr.filter; import java.util.EnumSet; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterRegistration; import javax.servlet.FilterRegistration.Dynamic; import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; import com.solr.util.PropUtils; public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { // TODO Auto-generated method stub return null; } @Override protected Class<?>[] getServletConfigClasses() { // TODO Auto-generated method stub return null; } @Override protected String[] getServletMappings() { // TODO Auto-generated method stub return null; } @Override public void onStartup(ServletContext servletContext) throws ServletException { // 系統啟動時註冊filter FilterRegistration testFilter = servletContext.addFilter("testFilter", StringFilter.class); // 設置init param, param可以從properties文件中讀取或其他方式獲取,提供一個想法 testFilter.setInitParameter("jersey.config.server.provider.packages", PropUtils.getValueByKey("FILTER.NAME")); testFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "*.*"); super.onStartup(servletContext); } @Override protected Dynamic registerServletFilter(ServletContext servletContext, Filter filter) { // TODO Auto-generated method stub return super.registerServletFilter(servletContext, filter); } }
在繼承AbstractAnnotationConfigDispatcherServletInitializer的時候onStartup和registerServletFilter兩個方法沒有自動添加進來,需要自己手動override。
其中onStartup在服務器啟動的時候會根據配置修改web.xml,此處通過addFilter添加瞭一個叫做testFilter的過濾器,通過setInitParameter向過濾器中設置參數。而這裡PropUtils是自己寫的一個讀取properties文件的工具類,這樣就實現瞭將properties中的值動態添加到web.xml中瞭,最後打包修改properties的時候就可以修改web.xml瞭。
filter.properties文件
FILTER.NAME=HHH
PropUtils工具類
此工具類使用ResourceBundle讀取properties文件,此工具類是java.util中的方法,其中還有一些stringUtils的方法,用來判斷字符串是否為空,將字符串轉換成大寫等功能,就不寫在上面瞭。
package com.solr.util; import java.text.MessageFormat; import java.util.Locale; import java.util.ResourceBundle; import org.apache.log4j.Logger; public class PropUtils { private static final String URL_RESOURCE_FILE_PATH = "props/filter"; private static final Logger LOG = Logger.getLogger(PropUtils.class); private static final ResourceBundle rb = ResourceBundle.getBundle(URL_RESOURCE_FILE_PATH, Locale.getDefault(),PropUtils.class.getClassLoader()); /** * @param key 對應properties內的key * @return properties對應字符串 */ public static String getValueByKey(String key){ return getValueByKey(key,null); } /** * @param key 對應properties內的key * @param param 參數下標0開始依次排列 * @return properties內填入對應參數的字符串 */ public static String getValueByKey(String key,Object [] param){ String value = ""; try { value = rb.getString(StringUtils.toUpper(key)); } catch (Exception e) { LOG.info(e,e); } if (StringUtils.isBlank(value)){ return key; } String strReturn = ""; if (param == null || param.length == 0){ strReturn = MessageFormat.format(value, param); }else { strReturn = value; } return strReturn.trim(); } }
查看web.xml參數
在啟動服務器的時候,會對過濾器進行初始化,我們可以在初始化的時候查看剛才配置的web.xml是否成功。
package com.solr.filter; import java.io.IOException; import java.util.Enumeration; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class StringFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub System.out.println("init"); Enumeration<String> initParameterNames = filterConfig.getInitParameterNames(); while (initParameterNames.hasMoreElements()) { String param = (String) initParameterNames.nextElement(); System.out.println(param + ":" + filterConfig.getInitParameter(param)); } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub System.out.println("dofilter"); } @Override public void destroy() { // TODO Auto-generated method stub System.out.println("destroy"); } }
啟動服務器進行測試
啟動服務器的時候報錯瞭:
八月 17, 2018 2:48:27 下午 org.apache.catalina.core.ContainerBase startInternal 嚴重: A child container failed during start java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]] at java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.util.concurrent.FutureTask.get(FutureTask.java:192) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1241) at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:300) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145) at org.apache.catalina.core.StandardService.startInternal(StandardService.java:444) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145) at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:758) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145) at org.apache.catalina.startup.Catalina.start(Catalina.java:705) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:294) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:428) Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:162) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1702) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1692) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: org.apache.catalina.LifecycleException: A child container failed during start at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:1249) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:819) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145) ... 6 more
錯誤的意思大概是加載組件遇到瞭問題。這個問題是在想通過編碼的方式來實現配置web.xml的時候出現的,即在之前是沒有遇到這個問題的,實現繼承AbstractAnnotationConfigDispatcherServletInitializer,並向web.xml中添加過濾器的時候遇到此問題的。
最終原因是通過編碼添加的過濾器名稱為testFilter,而web.xml中原先就有這個名稱的過濾器,兩個過濾器名稱沖突,造成服務器啟動失敗。
解決方式:刪除web.xml中原先的過濾器配置,通過編碼添加此過濾器。
web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0" metadata-complete="true"> <!--用maven創建的web-app需要修改servlet的版本為3.1 --> <welcome-file-list> <welcome-file>/index.jsp</welcome-file> </welcome-file-list> <!--配置DispatcherServlet --> <servlet> <servlet-name>mypage-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 配置SpringMVC 需要配置的文件 spring-dao.xml,spring-service.xml,spring-web.xml Mybites -> spring -> springMvc --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/spring-*.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>mypage-dispatcher</servlet-name> <!--默認匹配所有請求 --> <url-pattern>/</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> </servlet-mapping> </web-app>
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 基於module-info.class的問題
- spring framework源碼調試技巧
- SpringMVC記錄我遇到的坑_AOP註解無效,切面不執行的解決
- 帶你快速上手Servlet
- 詳解JavaWeb中的過濾器Filter