前言
因為公司項目需要,目前有本地環境、測試環境、開發環境。每次在將項目打包成war包的時候,都需要修改多處的配置,而使用maven的profile打包項目的時候,可以根據執行打包命令時所帶的參數來進行自動修改。
但是這種方式只對properties文件生效,即可以自動修改properties中的參數,但是公司的項目有一個web.xml中的配置參數也需要修改,這時候就要考慮如何通過properties文件動態修改web.xml中的參數了。
實現思路
web.xml中需要修改的部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
< 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的類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
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文件
1
|
FILTER.NAME=HHH |
PropUtils工具類
此工具類使用ResourceBundle讀取properties文件,此工具類是java.util中的方法,其中還有一些stringUtils的方法,用來判斷字符串是否為空,將字符串轉換成大寫等功能,就不寫在上面了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
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是否成功。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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" ); } } |
啟動服務器進行測試
啟動服務器的時候報錯了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
八月 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
< 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 > |
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/nb7474/article/details/81777655