一、实现资源过滤
(一)maven-resources-plugin 插件
1、Maven 区别对待Java代码文件和资源文件,maven-compiler-plugin用来编译Java代码,maven-resources-plugin则用来处理资源文件。默认的主资源文件目录是 src/main/resources。
2、很多用户会需要添加额外的资源文件目录,这个时候就可以通过配置maven-resources-plugin来实现。实现资源的过滤只需要添加 <filtering>true</filtering>
标签。
<!-- 资源过滤过滤 src/main/resources --> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> <resource> <directory>config</directory> </resource> </resources>
(二)资源过滤
1、两个资源文件夹:src/main/resources 和 config 。定义了同样的数据库配置。
jdbc.driverClassName = ${db.driver} jdbc.url = ${db.url} jdbc.username = ${db.username} jdbc.password = ${db.password}
2、定义资源文件及制定需要过滤的资源文件。(在<build> 标签)
<!-- 资源过滤过滤 src/main/resources --> <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> <resource> <directory>config</directory> </resource> </resources>
两个文件都被指定为资源文件,并且对src/main/resources 下文件是实现过滤。
3、利用 <profiles> 定义灵活构建的属性。
<!-- 定义灵活构建的属性 --> <profiles> <!-- DEV开发环境属性 --> <profile> <id>DEV</id> <properties> <db.driver>com.mysql.jdbc.Driver</db.driver> <db.url>jdbc:mysql://localhost:3306/dev_oa_0303</db.url> <db.username>dev-name</db.username> <db.password>dev-password</db.password> </properties> <!-- 激活方式: 1、命令行:mvn clean install -PDEV,UAT 2、setting中配置: <activeProfiles><activeProfile>dev</activeProfile></activeProfiles> 3、存在属性激活:<activation><property><name>a</name></property></activation>存在属性a 4、存在属性值:<activation><property><name>test</name><value>1</value></property></activation> 存在属性test=1,即激活。可以命令行:mvn clean install -Dtest=1; 5、默认激活:<activeByDefault>true</activeByDefault>. --> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> <!--UAT测试环境属性 --> <profile> <id>UAT</id> <properties> <db.driver>com.mysql.jdbc.Driver</db.driver> <db.url>jdbc:mysql://localhost:3306/uat_oa_0505</db.url> <db.username>uat-name</db.username> <db.password>uat-password</db.password> </properties> </profile> </profiles>
1)一个 profile 代表一个动态项,使用不同的Id 区分。这个Id 作为 -P 的参数使用。
2)使用properties 标签定义属性,这边属性的标签名需要与配置文件中${key}一致。
3)激活方式:
①、命令行激活:mvn clean install -PDEV,UAT
②、setting中配置激活: 使用<activeProfiles><activeProfile>dev</activeProfile></activeProfiles>标签。
③、存在属性激活:<activation><property><name>a</name></property></activation>存在属性激活
④、存在属性值:<activation><property><name>test</name><value>1</value></property></activation>
,存在属性test=1,即激活。可以在命令行:mvn clean install -Dtest=1;⑤、默认激活:<activeByDefault>true</activeByDefault>
4、动态构建: 运行时输入 clean install ,使用默认激活的 profile 配置。
1)两个文件都被作为配置文件处理。
2)其中 jdbc.properties 中的属性引用被动态替换了。并且是被默认的 id = DEV 的profile 替换。
5、运行时输入 clean install -PUAT,激活使用 id=UAT 的profile
配置。
二、创建web项目
1、Maven学习 (三) 使用m2eclipse创建web项目
三、一个成功的灵活构建项目实例
(一)简介
1、三类配置文件:都放在src/main/resources 下
1)配置文件总类:
application-file.properties,定义了需要的配置文件,其中A、B为通用的配置,而C则动态构建。
2)新建local 和 product两个环境的私有配置文件:application.local.properties 和 application.product.properties
3)所有的配置文件如下:
2、pom配置:
1)profiles 动态构建如下:默认激活 dev 。
<profiles> <profile> <id>dev</id> <properties> <dev.mode>true</dev.mode> <env.prop.application.file> application.local.properties </env.prop.application.file> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> <profile> <id>product</id> <properties> <dev.mode>true</dev.mode> <env.prop.application.file> application.product.properties </env.prop.application.file> </properties> </profile> </profiles>
2)对资源文件进行过滤
<!-- 资源过滤过滤 src/main/resources --> <resources> <resource> <directory>${basedir}/src/main/resources</directory> <filtering>true</filtering> </resource> </resources>
3)配置Tomcat 插件。
<!-- tomcat的插件 --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>tomcat-maven-plugin</artifactId> <version>1.1</version> <configuration> <path>/${project.build.target.file.name}</path> </configuration> </plugin>
4)如运行命令:clean install -Pproduct ,那么会动态替换application-file.properties 配置文件中的各环境的私有配置。如:
(二)配置文件读取类
1、需要定义一个配置文件的读取类,业务需求为,先读取application-file.properties ,然后按照顺序,依次读取其中配置的三个配置文件。这样配合Maven的动态构建,就实现了不同环境读取不同的配置文件。
2、默认的 Properties 类时无序的,我们需要实现一个有序的Properties 类。
package util; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.apache.commons.lang3.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.util.DefaultPropertiesPersister; import org.springframework.util.PropertiesPersister; /** * 系统属性工具类 * PropertyUtil * @title * @desc * @author SAM-SHO * @Jan 15, 2015 */ public class PropertyUtil { private static Logger logger = LoggerFactory.getLogger(PropertyUtil.class); private static Properties properties; private static PropertiesPersister propertiesPersister = new DefaultPropertiesPersister(); private static ResourceLoader resourceLoader = new DefaultResourceLoader(); private static final String DEFAULT_ENCODING = "UTF-8"; /** * 初始化读取配置文件,读取的文件列表位于classpath下面的application-files.properties * * * 多个配置文件会用最后面的覆盖相同属性值 * * @throws IOException * 读取属性文件时 */ public static void init() throws IOException { String fileNames = "application-file.properties"; innerInit(fileNames); } /** * 初始化读取配置文件,读取的文件列表位于classpath下面的application-[type]-files.properties * * * 多个配置文件会用最后面的覆盖相同属性值 * * @param type * 配置文件类型,application-[type]-files.properties * * @throws IOException * 读取属性文件时 */ public static void init(String type) throws IOException { String fileNames = "application-" + type + "-files.properties"; innerInit(fileNames); } /** * 内部处理 * * @param fileNames * @throws IOException */ private static void innerInit(String fileNames) throws IOException { ClassLoader loader = Thread.currentThread().getContextClassLoader(); InputStream resourceAsStream = loader.getResourceAsStream(fileNames); // 默认的Properties实现使用HashMap算法,为了保持原有顺序使用有序Map Properties files = new LinkedProperties(); files.load(resourceAsStream); Set<Object> fileKeySet = files.keySet(); String[] propFiles = new String[fileKeySet.size()]; List<Object> fileList = new ArrayList<Object>(); fileList.addAll(files.keySet()); for (int i = 0; i < propFiles.length; i++) { String fileKey = fileList.get(i).toString(); propFiles[i] = files.getProperty(fileKey); } logger.debug("读取属性文件:{}", ArrayUtils.toString(propFiles)); ; properties = loadProperties(propFiles); Set<Object> keySet = properties.keySet(); for (Object key : keySet) { logger.debug("property: {}, value: {}", key, properties.getProperty(key.toString())); } } /** * 载入多个properties文件, 相同的属性在最后载入的文件中的值将会覆盖之前的载入. 文件路径使用Spring Resource格式, * 文件编码使用UTF-8. * * @see org.springframework.beans.factory.config.PropertyPlaceholderConfigurer */ public static Properties loadProperties(String... resourcesPaths) throws IOException { Properties props = new Properties(); for (String location : resourcesPaths) { logger.debug("Loading properties file from:" + location); InputStream is = null; try { Resource resource = resourceLoader.getResource(location); is = resource.getInputStream(); propertiesPersister.load(props, new InputStreamReader(is, DEFAULT_ENCODING)); } catch (IOException ex) { logger.info("Could not load properties from classpath:" + location + ": " + ex.getMessage()); } finally { if (is != null) { is.close(); } } } return props; } /** * 获取键值对Map * * @return */ public static Map<String, String> getKeyValueMap() { Set<String> keys = getKeys(); Map<String, String> values = new HashMap<String, String>(); for (String key : keys) { values.put(key, get(key)); } return values; } /** * 获取所有的key * * @return */ public static Set<String> getKeys() { return properties.stringPropertyNames(); } /** * 获取属性值 * * @param key * 键 * @return 值 */ public static String get(String key) { String propertyValue = properties.getProperty(key); logger.debug("获取属性:{},值:{}", key, propertyValue); return propertyValue; } public static void main(String[] args) { try { PropertyUtil.init(); } catch (IOException e) { e.printStackTrace(); } } }
package util; import java.io.PrintStream; import java.io.PrintWriter; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; import java.util.Set; /** * 有序Properties */ public class LinkedProperties extends Properties { private static final long serialVersionUID = 1L; private Map<Object, Object> linkMap = new LinkedHashMap<Object, Object>(); public void clear() { linkMap.clear(); } public boolean contains(Object value) { return linkMap.containsValue(value); } public boolean containsKey(Object key) { return linkMap.containsKey(key); } public boolean containsValue(Object value) { return linkMap.containsValue(value); } public Enumeration elements() { throw new RuntimeException("Method elements is not supported in LinkedProperties class"); } public Set entrySet() { return linkMap.entrySet(); } public boolean equals(Object o) { return linkMap.equals(o); } public Object get(Object key) { return linkMap.get(key); } public String getProperty(String key) { Object oval = get(key); //here the class Properties uses super.get() if (oval == null) return null; return (oval instanceof String) ? (String) oval : null; //behavior of standard properties } public boolean isEmpty() { return linkMap.isEmpty(); } public Enumeration keys() { Set keys = linkMap.keySet(); return Collections.enumeration(keys); } public Set keySet() { return linkMap.keySet(); } public void list(PrintStream out) { this.list(new PrintWriter(out, true)); } public void list(PrintWriter out) { out.println("-- listing properties --"); for (Map.Entry e : (Set<Map.Entry>) this.entrySet()) { String key = (String) e.getKey(); String val = (String) e.getValue(); if (val.length() > 40) { val = val.substring(0, 37) + "..."; } out.println(key + "=" + val); } } public Object put(Object key, Object value) { return linkMap.put(key, value); } public int size() { return linkMap.size(); } public Collection values() { return linkMap.values(); } }
(三)项目启动时,读取配置的Servlet。
1、PropertiesServlet 的代码如下:
package servlet; import java.io.IOException; import java.util.Set; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import util.PropertyUtil; /** * classpath下面的属性配置文件读取初始化类 * PropertiesServlet * @title * @desc * @author SAM-SHO * @Jan 15, 2015 */ public class PropertiesServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected Logger logger = LoggerFactory.getLogger(getClass()); /** * @see Servlet#init(ServletConfig) */ public void init(ServletConfig config) throws ServletException { try { PropertyUtil.init(); ServletContext servletContext = config.getServletContext(); setParameterToServerContext(servletContext);; logger.info("++++ 初始化[classpath下面的属性配置文件]完成 ++++"); } catch (IOException e) { logger.error("初始化classpath下的属性文件失败", e); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action = StringUtils.defaultString(req.getParameter("action")); resp.setContentType("text/plain;charset=UTF-8"); if ("reload".equals(action)) { // 重载 try { PropertyUtil.init(); setParameterToServerContext(req.getSession().getServletContext()); logger.info("++++ 重新初始化[classpath下面的属性配置文件]完成 ++++,{IP={}}", req.getRemoteAddr()); resp.getWriter().print("<b>属性文件重载成功!</b>"); // writeProperties(resp); } catch (IOException e) { logger.error("重新初始化classpath下的属性文件失败", e); } } else if ("getprop".equals(action)) { // 获取属性 String key = StringUtils.defaultString(req.getParameter("key")); resp.getWriter().print(key + "=" + PropertyUtil.get(key)); } else if ("list".equals(action)) { // 获取属性列表 // writeProperties(resp); } } private void setParameterToServerContext(ServletContext servletContext) { servletContext.setAttribute("prop", PropertyUtil.getKeyValueMap()); } }
2、PropertiesServlet 配置:
<!-- 配置文件 --> <servlet> <servlet-name>PropertiesServlet</servlet-name> <servlet-class>servlet.PropertiesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>PropertiesServlet</servlet-name> <url-pattern>/servlet/properties</url-pattern> </servlet-mapping>
(四)启动项目,使用tomcat-maven-plugin插件
1、启动方式:tomcat:run 和 tomcat:run -Dmaven.tomcat.port=8880(指定端口)
2、项目启动:
1)tomcat:run 默认运行dev环境的配置。
2)tomcat:run -Pproduct ,指定移动 product 的profile(运行product 的环境)。(这边的-P,即指的就是profile)。