<!-- 过滤资源文件 --> <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应用中,热部署,拒绝打包。。提高开发效率