import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
@Override
public List<Integer> getLast7DayCount(String columnName) {
Calendar calendar = Calendar.getInstance();
// 设置开始时间为六天前的00:00:00
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
calendar.add(Calendar.DAY_OF_YEAR, -6); // 六天前
Date startDate = calendar.getTime(); // 获取六天前的开始时间
// 设置结束时间为今天的23:59:59
calendar = Calendar.getInstance(); // 重新获取当前时间
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999); // 包括到999毫秒
Date endDate = calendar.getTime(); // 获取今天的结束时间
System.out.println("Start Date: " + startDate);
System.out.println("End Date: " + endDate);
// 从开始时间到结束时间查询用户
List<User> usersInLast7Days = UserMapper.findUsersByTimeRange(columnName, startDate, endDate);
// 统计每天的新增数量
List<Integer> newCounts = new ArrayList<>();
// 重新设置 calendar 以计算每一天
calendar.setTime(startDate);
for (int i = 0; i < 7; i++) {
// 计算当天的开始和结束时间
long startOfDay = calendar.getTimeInMillis(); // 当天 00:00:00
long endOfDay = startOfDay + 24 * 60 * 60 * 1000; // +24小时,确保到下一个零点
// 计算当天新增用户数量
int count = (int) usersInLast7Days.stream()
.filter(user -> {
try {
// 构造 getter 方法名
String methodName = "get" + capitalize(columnName);
Method method = user.getClass().getMethod(methodName);
// 获取字段值并进行时间比较
Date dateValue = (Date) method.invoke(user);
return dateValue != null && (dateValue.getTime() >= startOfDay) && (dateValue.getTime() < endOfDay);
} catch (Exception e) {
e.printStackTrace();
return false; // 如果发生异常,默认过滤掉该记录
}
})
.count();
newCounts.add(count);
// 打印对应日期和新增用户数量
System.out.printf("Date: %s, New Immit: %d%n", calendar.getTime(), count);
// 前移 calendar 到下一天
calendar.add(Calendar.DAY_OF_YEAR, 1);
}
return newCounts;
}
// 辅助方法:首字母大写
private String capitalize(String str) {
if (str == null || str.isEmpty()) {
return str;
}
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
代码讲解
-
反射调用法:在
filter
方法中,通过调用user.getClass().getMethod(methodName)
获取动态生成的 getter 方法。通过反射使用invoke
方法调用该 getter。 -
首字母大写转换:
capitalize
方法将传入的字符串的首字母变为大写,以符合 Java 的 getter 方法命名规则(如createTime
的 getter 是getCreateTime
)。 -
异常处理:在反射调用过程中可能会抛出异常,因此需要使用
try-catch
块来捕获并处理。例如,方法未找到、反射失败等情况。
使用
您可以将 getLast7DayCount("createTime")
作为调用,系统将根据字段名动态调用指定的 getter 方法,从而实现查询指定 date 字段前七天的增量。
确保 createTime
是 User
类中的一个字段,并且有相应的 getter 方法供反射访问。
2. Mapper 接口
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
public interface UserMapper {
List<User> findUsersByTimeRange(@Param("columnName") String columnName, @Param("startDate") Date startDate, @Param("endDate") Date endDate);
}
2. Mapper XML 文件
接下来,在 Mapper XML 文件中,您需要使用 <choose>
、<when>
和 <otherwise>
标签来动态构造 SQL 查询。以下是一个示例,假设您只需要处理 createTime
和 destroyTime
两个字段:
<mapper namespace="com.yourpackage.UserMapper">
<select id="findUsersByTimeRange" resultType="com.modules.usermanage.po.User">
SELECT * FROM userinfo
WHERE
<choose>
<when test="columnName == 'createTime'">
createTime >= #{startDate} AND createTime <= #{endDate}
</when>
<when test="columnName == 'destroyTime'">
destroyTime >= #{startDate} AND destroyTime <= #{endDate}
</when>
<otherwise>
-- 处理未定义的字段名情况
1 = 0 -- 这将永远返回空结果
</otherwise>
</choose>
</select>
</mapper>
代码解释
-
动态 SQL:使用
<choose>
标签来根据columnName
的值选择不同的 SQL 片段。每个<when>
标签对应一个可能的字段名,并定义相应的 SQL 条件。 -
默认情况处理:使用
<otherwise>
来处理未定义字段的情况。这里的1 = 0
语句将确保查询不会返回任何结果,避免 SQL 错误。 -
字段名:在
columnName
传入的值必须与数据库中的字段名一致(如createTime
或destroyTime
)。如果需要支持更多字段,可以继续添加更多的<when>
标签。
使用示例
当您调用 findUsersByTimeRange("createTime", startDate, endDate)
时,MyBatis 将根据 columnName
的值动态构造 SQL 查询,并返回符合条件的用户列表。
注意事项
- 确保传入的
columnName
仅包含安全的字段名,避免 SQL 注入风险。通常,您可以通过在程序中进行验证来确保字段名的安全性。 - 如果需要查询的字段较多,可能需要考虑其他方式来简化代码,如使用 SQL 生成器或 ORM 框架。