背景
フロントエンドには、2つのタイムスタンプ(beginDate,endDate)を時間範囲として渡すtimeコンポーネントがあります 。endDateに1日追加する必要があります}}。
直接の解決策:
Date beginDate=param.getBeginDate();
Date endDate=param.getEndDate();
if ((beginDate != null && endDate != null) && beginDate.equals(endDate)) {
//開始時刻と終了時刻が同じなら、終了時刻は1日増える。
c.setTime(beginDate);
c.add(Calendar.DAY_OF_MONTH, 1);
Date endTime = c.getTime();
endDateMap.get(arg.getClass()).set(arg, endTime);
}
しかし、そうすると、すべての時間範囲クエリーメソッドにこのコードを追加しなければならなくなり、すっきりしません。
したがって、メソッド本体に入り込まないアノテーションを使用して、このエントリーの修正を実装することを検討してください。
カスタム注釈+AOP
まず、そのプロジェクトが
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
次に、時間範囲クエリーメソッドをラベリングするためのカスタムアノテーション。
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeSpanCheck {
//String beginDateFieldName();
//String endDateFieldName();
}
もともとは、beginDateとendDateのフィールド名を手動で定義したかったのですが、よくよく考えてみると、ここでフィールド名を変更すると、エラーと一緒に変更される可能性がないので、すでにアノテーションを使って識別を行っているので、もう一度使った方がいいかもしれません!
@Documented
//メソッド@Target上記とは異なり、このアノテーションは変数のアノテーションに使用される。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BeginDate {
}
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EndDate {
}
アノテーションを定義したら、対応するメソッドとフィールドに追加します。
@Component
@Aspect
@Slf4j
public class TimeSpanCheckAop {
private Calendar c = Calendar.getInstance();
//フィールドをキャッシュすることで、メソッド呼び出しのたびにリフレクションを実行するオーバーヘッドを避けることができる。
private Map<Class, Field> beginDateMap = new HashMap<>();
private Map<Class, Field> endDateMap = new HashMap<>();
//カット・ポイント、つまりaopを実行する必要がある場所である。
@Pointcut("execution(* xxx.xxx.service.impl..*(..)) && @annotation(xxx.xxx.service.aop.TimeSpanCheck)")
public void pointCut() {
}
/**
* メソッドが@TimeSpanCheckbegindateとenddateは同じで、enddateプラス1日である。
*/
@Around("pointCut()")
public Object TimeSpanCheck(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
TimeSpanCheck timeSpanCheck = method.getAnnotation(TimeSpanCheck.class);
if (timeSpanCheck == null) {
return true;
}
Object arg = args[0];
if (beginDateMap.get(arg.getClass()) == null && endDateMap.get(arg.getClass()) == null) {
//入力変数を繰り返し、ラベルの付いた@BeginDate @EndDateフィールドを作成し、キャッシュ・マップに格納する。
for (Field field : arg.getClass().getDeclaredFields()) {
BeginDate beginDate = field.getAnnotation(BeginDate.class);
EndDate endDate = field.getAnnotation(EndDate.class);
if (beginDate != null) {
field.setAccessible(true);
beginDateMap.put(arg.getClass(), field);
}
if (endDate != null) {
field.setAccessible(true);
endDateMap.put(arg.getClass(), field);
}
}
}
//フィールドを取得し、入力パラメーターを変更する
Field beginDateField = beginDateMap.get(arg.getClass());
Field endDateField = endDateMap.get(arg.getClass());
if (beginDateField != null && endDateField != null) {
Date beginDate = (Date) beginDateField.get(arg);
Date endDate = (Date) endDateField.get(arg);
if ((beginDate != null && endDate != null) && beginDate.equals(endDate)) {
//開始時刻と終了時刻が同じなら、終了時刻は1日増える。
c.setTime(beginDate);
c.add(Calendar.DAY_OF_MONTH, 1);
Date endTime = c.getTime();
endDateMap.get(arg.getClass()).set(arg, endTime);
}
}
//オリジナルメソッドの実行
return joinPoint.proceed(args);
}
}
検証
ご覧のように、このメソッドを実行すると、endDateはbeginDate+1日となり、望ましい効果が得られます。





