<!-- 过滤资源文件 --> <servlet> <servlet-name>PropertiesFilterServlet</servlet-name> <servlet-class> com.taobao.upp.mpc.util.fiter.PropertiesFilterServlet </servlet-class> <init-param> <param-name>sourceDir</param-name> <param-value>/config/</param-value> </init-param> <init-param> <param-name>outputDir</param-name> <param-value>/WEB-INF/</param-value> </init-param> <init-param> <param-name>filterProperties</param-name> <param-value>/config/antx.properties</param-value> </init-param> <init-param> <param-name>encoding</param-name> <param-value>GB2312</param-value> </init-param> <load-on-startup>0</load-on-startup> </servlet>
web.xml启动此servlet将指定目录下的所有文件用filterProperties对应的文件过滤并拷贝到web-inf下
下面是PropertiesFilterServlet所相关的java类
PropertiesFilterServlet
public class PropertiesFilterServlet extends HttpServlet { private static final long serialVersionUID = -7226869902759342312L; private static final String SOURCE_DIR = "sourceDir"; private static final String OUTPUT_DIR = "outputDir"; private static final String ENCODING = "encoding"; private static final String DEFAULT_ENCODING = "GB2312"; private static final String FILTER_PROPERTIES = "filterProperties"; private static final String ESCAPE_SVNFILE = "svn"; /** * 从WEB.XML中读取过滤文件源目录及目标目录参数,读取文件时过滤掉了.SVN文件 * 在拷贝过程中进行${}变量的过滤 * @author jishao */ @Override public void init() throws ServletException { String sourceFiles = getServletContext().getRealPath( getInitParameter(SOURCE_DIR)); String outputFiles = getServletContext().getRealPath( getInitParameter(OUTPUT_DIR)); String filterProperties = getServletContext().getRealPath( getInitParameter(FILTER_PROPERTIES)); String encoding = TBStringUtil.isEmpty(getInitParameter(ENCODING)) ? DEFAULT_ENCODING : getInitParameter(ENCODING); if (TBStringUtil.isEmpty(sourceFiles) || TBStringUtil.isEmpty(sourceFiles)) { throw new ServletException("sourceDir outPut or filterProperties is null"); } else { List propertiesFilePaths = new ArrayList(); String fromPath = sourceFiles; File fromDirectory = new File(fromPath); File[] files = fromDirectory.listFiles(new FilteringUtils(ESCAPE_SVNFILE)); propertiesFilePaths.add(filterProperties); FileFilter fileFilter = new DefaultFileFilter(); for (File fromFile : files) { String toFilePath = outputFiles + "\\" + fromFile.getName(); File toFile = new File(toFilePath); try { fileFilter.copyFile(fromFile, toFile, true, propertiesFilePaths, true, encoding); } catch (FilteringException e) { e.printStackTrace(); break; } } super.init(); } } }
DefaultFileFilter
public class DefaultFileFilter implements FileFilter { /** * @author jishao * @see com.taobao.upp.mpc.util.fiter.FileFilter * #copyFile(File, File, boolean, List, boolean, String) */ public void copyFile(File from, File to, boolean filtering, List filters, boolean escapedBackslashesInFilePath, String encoding) throws FilteringException { List filterWrappers = getDefaultFilterWrappers(filters, true); copyFile(from, to, filtering, filterWrappers, encoding, false); } /** * copyFile 复制文件 * @param from file to copy/filter * @param to destination file * @param filtering enable or not filering * @param escapedBackslashesInFilePath format window path * @param filters {@link List} of String which are path to a Property file * @param overwrite * @throws FilteringException * @author jishao * @since 2010-3-12 上午10:27:12 */ public void copyFile(File from, File to, boolean filtering, List filterWrappers, String encoding, boolean overwrite) throws FilteringException { try { if (filtering) { FileUtils.FilterWrapper[] wrappers = (FileUtils.FilterWrapper[]) filterWrappers .toArray(new FileUtils.FilterWrapper[filterWrappers .size()]); FileUtils.copyFile(from, to, encoding, wrappers); } else { FileUtils.copyFile(from, to, encoding, new FileUtils.FilterWrapper[0], overwrite); } } catch (IOException e) { throw new FilteringException(e.getMessage(), e); } } /** * @author jishao * 在这里,我们建立一些将用于阅读的一些属性文件 过滤变量表达式$() 创建一个filterProperties的副本 * @see com.taobao.upp.mpc.util.fiter.FileFilter * #getDefaultFilterWrappers(List, boolean) */ public List getDefaultFilterWrappers(List filters, boolean escapedBackslashesInFilePath) throws FilteringException { final Properties baseProps = new Properties(); // Project properties final Properties filterProperties = new Properties(); // load properties loadProperties(filterProperties, filters, baseProps); List defaultFilterWrappers = new ArrayList(1); // support ${token} final ValueSource propertiesValueSource = new PropertiesEscapingValue( escapedBackslashesInFilePath, filterProperties); FileUtils.FilterWrapper one = new FileUtils.FilterWrapper() { @Override public Reader getReader(Reader reader) { StringSearchInterpolator propertiesInterpolator = new StringSearchInterpolator(); propertiesInterpolator.addValueSource(propertiesValueSource); InterpolatorFilterReader filterReader = new InterpolatorFilterReader( reader, propertiesInterpolator); filterReader.setInterpolateWithPrefixPattern(false); // first try it must be preserved filterReader.setPreserveEscapeString(true); return filterReader; } }; defaultFilterWrappers.add(one); return defaultFilterWrappers; } /** * loadProperties 加载属性文件(antx.properties) * @param filterProperties * @param propertiesFilePaths * @param baseProps * @Exception throws FilteringException * @author jishao * @since 2010-3-12 上午10:43:05 */ public void loadProperties(Properties filterProperties, List propertiesFilePaths, Properties baseProps) throws FilteringException { if (propertiesFilePaths != null) { for (Iterator iterator = propertiesFilePaths.iterator(); iterator .hasNext();) { String filterFile = (String) iterator.next(); if (StringUtils.isEmpty(filterFile)) { // skip empty file name continue; } try { Properties properties = PropertyUtils.loadPropertyFile( new File(filterFile), baseProps); filterProperties.putAll(properties); } catch (IOException e) { throw new FilteringException( "Error loading property file '" + filterFile + "'", e); } } } } }
FileFilter
public interface FileFilter { /** * 将需要复制一些文件使用defaultFilterWrappers过滤 * @see getDefaultFilterWrappers * * @param from file to copy/filter * @param to destination file * @param filtering enable or not filering * @param escapedBackslashesInFilePath format window path * @param filters {@link List} of String which are path to a Property file * @throws FilteringException */ void copyFile(File from, final File to, boolean filtering, List filters, boolean escapedBackslashesInFilePath, String encoding) throws FilteringException; /** * interpolate with token ${} and values from sysProps, project.properties, filters and project filters. * @param filters {@link List} of properties file * @param escapedBackslashesInFilePath format window path * @return {@link List} of FileUtils.FilterWrapper */ List getDefaultFilterWrappers(List filters, boolean escapedBackslashesInFilePath) throws FilteringException; }
FilteringException
public class FilteringException extends Exception { private static final long serialVersionUID = -4571729422567136511L; public FilteringException() { // nothing } /** * @param message */ public FilteringException(String message) { super(message); } /** * @param cause */ public FilteringException(Throwable cause) { super(cause); } /** * @param message * @param cause */ public FilteringException(String message, Throwable cause) { super(message, cause); } }
FilteringUtils
public class FilteringUtils implements FilenameFilter { private final Pattern pattern; public FilteringUtils(String regex) { pattern = Pattern.compile(regex); } public boolean accept(File arg0, String name) { String nameString = new File(name).getName(); String postfix = nameString.substring(nameString.lastIndexOf(".") + 1); return !pattern.matcher(postfix).matches(); } public static final String escapeWindowsPath(String val) { if (!StringUtils.isEmpty(val) && val.indexOf(":\\") == 1) { val = StringUtils.replace(val, "\\", "\\\\"); val = StringUtils.replace(val, ":", "\\:"); } return val; } }
PropertiesEscapingValue
public class PropertiesEscapingValue implements ValueSource { private final boolean escapedBackslashesInFilePath; private final Properties properties; public PropertiesEscapingValue( boolean escapedBackslashesInFilePath, Properties properties ) { this.escapedBackslashesInFilePath = escapedBackslashesInFilePath; this.properties = properties == null ? new Properties() : properties; } public Object getValue( String expression ) { String value = properties.getProperty( expression ); return escapedBackslashesInFilePath ? FilteringUtils.escapeWindowsPath( value ) : value; } public void clearFeedback() { // nothing here } public List getFeedback() { return Collections.EMPTY_LIST; } }
PropertyUtils
public final class PropertyUtils { /** * private empty constructor to prevent instantiation */ private PropertyUtils() { // prevent instantiation } /** * Reads a property file, resolving all internal variables, using the supplied base properties. * <p> * The properties are resolved iteratively, so if the value of property A refers to property B, * then after resolution the value of property B will contain the value of property B. * </p> * * @param propFile The property file to load. * @param baseProps Properties containing the initial values to subsitute into the properties file. * @return Properties object containing the properties in the file with their values fully resolved. * @throws IOException if profile does not exist, or cannot be read. */ public static Properties loadPropertyFile( File propFile, Properties baseProps ) throws IOException { if ( !propFile.exists() ) { throw new FileNotFoundException( propFile.toString() ); } final Properties fileProps = new Properties(); final FileInputStream inStream = new FileInputStream( propFile ); try { fileProps.load( inStream ); } finally { IOUtil.close( inStream ); } final Properties combinedProps = new Properties(); combinedProps.putAll( baseProps == null ? new Properties() : baseProps ); combinedProps.putAll( fileProps ); // The algorithm iterates only over the fileProps which is all that is required to resolve // the properties defined within the file. This is slighlty different to current, however // I suspect that this was the actual original intent. // // The difference is that #loadPropertyFile(File, boolean, boolean) also resolves System properties // whose values contain expressions. I believe this is unexpected and is not validated by the test cases, // as can be verified by replacing the implementation of #loadPropertyFile(File, boolean, boolean) // with the commented variant I have provided that reuses this method. for ( Iterator iter = fileProps.keySet().iterator(); iter.hasNext(); ) { final String k = (String) iter.next(); final String propValue = getPropertyValue( k, combinedProps ); fileProps.setProperty( k, propValue ); } return fileProps; } /** * Reads a property file, resolving all internal variables. * * @param propfile The property file to load * @param fail wheter to throw an exception when the file cannot be loaded or to return null * @param useSystemProps wheter to incorporate System.getProperties settings into the returned Properties object. * @return the loaded and fully resolved Properties object * @throws IOException if profile does not exist, or cannot be read. */ public static Properties loadPropertyFile( File propfile, boolean fail, boolean useSystemProps ) throws IOException { final Properties baseProps = new Properties(); if ( useSystemProps ) { baseProps.putAll( System.getProperties() ); } final Properties resolvedProps = new Properties(); try { resolvedProps.putAll( loadPropertyFile( propfile, baseProps ) ); } catch ( FileNotFoundException e ) { if ( fail ) { throw new FileNotFoundException( propfile.toString() ); } } if ( useSystemProps ) { resolvedProps.putAll( baseProps ); } return resolvedProps; } /** * Retrieves a property value, replacing values like ${token} * using the Properties to look them up. * * It will leave unresolved properties alone, trying for System * properties, and implements reparsing (in the case that * the value of a property contains a key), and will * not loop endlessly on a pair like * test = ${test}. * @param k * @param p * @return */ private static String getPropertyValue( String k, Properties p ) { // This can also be done using InterpolationFilterReader, // but it requires reparsing the file over and over until // it doesn't change. String v = p.getProperty( k ); String ret = ""; int idx, idx2; while ( ( idx = v.indexOf( "${" ) ) >= 0 ) { // append prefix to result ret += v.substring( 0, idx ); // strip prefix from original v = v.substring( idx + 2 ); // if no matching } then bail if ( ( idx2 = v.indexOf( '}' ) ) < 0 ) { break; } // strip out the key and resolve it // resolve the key/value for the ${statement} String nk = v.substring( 0, idx2 ); v = v.substring( idx2 + 1 ); String nv = p.getProperty( nk ); // try global environment.. if ( nv == null && !StringUtils.isEmpty( nk ) ) { nv = System.getProperty( nk ); } // if the key cannot be resolved, // leave it alone ( and don't parse again ) // else prefix the original string with the // resolved property ( so it can be parsed further ) // taking recursion into account. if ( nv == null || nv.equals( k ) || k.equals( nk ) ) { ret += "${" + nk + "}"; } else { v = nv + v; } } return ret + v; } }
将maven需要的功能合并到web应用中,热部署,拒绝打包。。提高开发效率