このような与えられた文字列で
".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf"
customer
とyyyyMMdd
のタイムスタンプを置き換える必要があります。
customer
プレースホルダーを置き換えるには、Apache CommonsのStrSubstitutor
を使用できます。しかし、SimpleDateFormat
を置き換える方法は?私たちは春の環境で走っているので、たぶんSpring EL
はオプションですか?
プレースホルダーのマークアップは固定されていません。別のライブラリが構文の変更を必要とする場合は問題ありません。
この小さなテストは問題を示しています:
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
String template = ".../uploads/${customer}/${dateTime('yyyyMMdd')}/report.pdf";
@Test
public void shouldResolvePlaceholder()
{
final Map<String, String> model = new HashMap<String, String>();
model.put("customer", "Mr. Foobar");
final String filledTemplate = StrSubstitutor.replace(this.template, model);
assertEquals(".../uploads/Mr. Foobar/" + this.formatter.format(new Date()) + "/report.pdf", filledTemplate);
}
代わりに MessageFormat
を使用しないのはなぜですか?
String result = MessageFormat.format(".../uploads/{0}/{1,date,yyyyMMdd}/report.pdf", customer, date);
または String.format
String result = String.format(".../uploads/%1$s/%2$tY%2$tm%2$td/report.pdf", customer, date);
NilsHが提案したように、MessageFormatはこの目的にとって本当に素晴らしいものです。名前付き変数を使用するには、クラスの背後にMessageFormatを隠すことができます。
public class FormattedStrSubstitutor {
public static String formatReplace(Object source, Map<String, String> valueMap) {
for (Map.Entry<String, String> entry : valueMap.entrySet()) {
String val = entry.getValue();
if (isPlaceholder(val)) {
val = getPlaceholderValue(val);
String newValue = reformat(val);
entry.setValue(newValue);
}
}
return new StrSubstitutor(valueMap).replace(source);
}
private static boolean isPlaceholder(String isPlaceholder) {
return isPlaceholder.startsWith("${");
}
private static String getPlaceholderValue(String val) {
return val.substring(2, val.length()-1);
}
private static String reformat(String format) {
String result = MessageFormat.format("{0,date," + format + "}", new Date());
return result;
}
}
そして、あなたはあなたのテストケースを調整する必要があります:
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
String template = ".../uploads/${customer}/${dateTime}/report.pdf";
@Test
public void shouldResolvePlaceholder() {
final Map<String, String> model = new HashMap<String, String>();
model.put("customer", "Mr. Foobar");
model.put("dateTime", "${yyyyMMdd}");
final String filledTemplate = FormattedStrSubstitutor.formatReplace(this.template,
model);
assertEquals(".../uploads/Mr. Foobar/" + this.formatter.format(new Date())
+ "/report.pdf", filledTemplate);
}
ジェネリックを削除し、Stringに置き換えました。また、isPlaceholder
およびgetPlaceholderValue
はハードコーディングされており、$ {value}構文を期待しています。
ただし、これは問題を解決するためのアイデアにすぎません。これを行うには、StrSubstitutor
のメソッドを使用できます(isまたはmake FormattedStrSubstitutor extends StrSubstitutor
を使用するだけです)。
また、たとえば、$ d {value}を日付の書式設定に使用し、$ foo {value}fooフォーマット用。
[〜#〜]更新[〜#〜]
完全な解決策なしでは眠れませんでした。このメソッドをFormattedStrSubstitutor
クラスに追加できます:
public static String replace(Object source,
Map<String, String> valueMap) {
String staticResolved = new StrSubstitutor(valueMap).replace(source);
Pattern p = Pattern.compile("(\\$\\{date)(.*?)(\\})");
Matcher m = p.matcher(staticResolved);
String dynamicResolved = staticResolved;
while (m.find()) {
String result = MessageFormat.format("{0,date" + m.group(2) + "}",
new Date());
dynamicResolved = dynamicResolved.replace(m.group(), result);
}
return dynamicResolved;
}
あなたのテストケースはあなたの質問のようです(プレースホルダーの小さな変更):
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
String template = ".../uploads/${customer}/${date,yyyyMMdd}/report.pdf";
@Test
public void shouldResolvePlaceholder() {
final Map<String, String> model = new HashMap<String, String>();
model.put("customer", "Mr. Foobar");
final String filledTemplate = FormattedStrSubstitutor.replace(this.template,
model);
assertEquals(
".../uploads/Mr. Foobar/" + this.formatter.format(new Date())
+ "/report.pdf", filledTemplate);
}
以前と同じ制限。ジェネリックはなく、プレースホルダーのプレフィックスとサフィックスを修正しました。
こんなに簡単なの?
static final Pattern DOLLARS = Pattern.compile("\\$\\{([^}]+)}");
public static String resolve(String string, Map<String,String> config) {
StringBuilder builder = new StringBuilder();
Matcher matcher = DOLLARS.matcher(string);
int start = 0;
while (matcher.find(start)) {
builder.append(string.substring(start, matcher.start()));
String property = matcher.group(1);
String value = config.get(property);
builder.append(value);
start = matcher.end();
}
builder.append(string.substring(start));
return builder.toString();
}