diff --git a/minsu/minsuguanliw/src/main/java/com/controller/CommonController.java b/minsu/minsuguanliw/src/main/java/com/controller/CommonController.java index d388dcf3..f1991a8c 100644 --- a/minsu/minsuguanliw/src/main/java/com/controller/CommonController.java +++ b/minsu/minsuguanliw/src/main/java/com/controller/CommonController.java @@ -38,118 +38,171 @@ import com.utils.R; /** * 通用接口 */ +// 该类被标注为RestController,意味着这个类中的方法返回值会直接以JSON等格式响应给客户端,常用于构建RESTful API @RestController public class CommonController{ + // 创建一个日志记录器,用于记录该类中的相关日志信息,方便调试和问题排查 private static final Logger logger = LoggerFactory.getLogger(CommonController.class); + + // 自动注入CommonService,通过依赖注入的方式获取对应的业务逻辑处理类实例 @Autowired private CommonService commonService; - + // 自动注入ConfigService,用于获取配置相关的服务,可能用来读取系统配置信息等 @Autowired private ConfigService configService; - + // 用于百度人脸识别的客户端实例,初始化为null,后续会根据配置进行初始化 private static AipFace client = null; - + // 存储百度地图AK(Access Key),初始化为null,会从配置中读取 private static String BAIDU_DITU_AK = null; - + // 处理获取位置信息的请求映射,接收经度(lng)和纬度(lat)参数,用于根据经纬度获取对应的城市等位置信息 @RequestMapping("/location") public R location(String lng,String lat) { + // 如果百度地图AK为空,则尝试从配置中获取 if(BAIDU_DITU_AK==null) { + // 通过ConfigService根据配置名称("baidu_ditu_ak")查询对应的配置实体,并获取其值作为百度地图AK BAIDU_DITU_AK = configService.selectOne(new EntityWrapper().eq("name", "baidu_ditu_ak")).getValue(); + // 如果获取到的百度地图AK仍然为空,说明配置有误,返回错误信息给客户端 if(BAIDU_DITU_AK==null) { return R.error("请在配置管理中正确配置baidu_ditu_ak"); } } + // 调用BaiduUtil的方法,根据百度地图AK以及传入的经度和纬度获取对应的位置信息(以Map形式返回) Map map = BaiduUtil.getCityByLonLat(BAIDU_DITU_AK, lng, lat); + // 将获取到的位置信息封装到响应结果中,以"data"为键,返回成功响应给客户端 return R.ok().put("data", map); } - + /** - * 人脸比对 - * - * @param face1 人脸1 - * @param face2 人脸2 - * @return + * 人脸比对方法,用于比对两张人脸图片是否相似。 + * @param face1 人脸1对应的文件名(可能是存储在服务器特定位置的文件名称) + * @param face2 人脸2对应的文件名 + * @param request HttpServletRequest对象,用于获取服务器相关上下文信息等 + * @return 返回包含比对结果的响应信息给客户端 */ + @RequestMapping("/matchFace") public R matchFace(String face1, String face2, HttpServletRequest request) { + // 如果百度人脸识别客户端实例为空,则进行初始化操作 if(client==null) { + // 以下代码被注释掉,可能原本是打算获取AppID的配置值,但目前未使用 /*String AppID = configService.selectOne(new EntityWrapper().eq("name", "AppID")).getValue();*/ + // 获取APIKey配置值,用于百度人脸识别的认证等操作 String APIKey = configService.selectOne(new EntityWrapper().eq("name", "APIKey")).getValue(); + // 获取SecretKey配置值,同样用于百度人脸识别的相关认证操作 String SecretKey = configService.selectOne(new EntityWrapper().eq("name", "SecretKey")).getValue(); + // 通过BaiduUtil的方法,使用获取到的APIKey和SecretKey获取访问令牌(token),用于后续与百度人脸识别服务交互的认证 String token = BaiduUtil.getAuth(APIKey, SecretKey); + // 如果获取到的令牌为空,说明配置的APIKey和SecretKey有问题,返回错误信息给客户端 if(token==null) { return R.error("请在配置管理中正确配置APIKey和SecretKey"); } + // 创建百度人脸识别客户端实例,传入相关认证参数(此处AppID传入null,实际可能需要正确配置) client = new AipFace(null, APIKey, SecretKey); + // 设置连接超时时间为2000毫秒 client.setConnectionTimeoutInMillis(2000); + // 设置套接字超时时间为60000毫秒 client.setSocketTimeoutInMillis(60000); } + JSONObject res = null; try { + // 根据服务器上下文获取文件1的完整路径,该文件对应人脸1的图片 File file1 = new File(request.getSession().getServletContext().getRealPath("/upload")+"/"+face1); + // 根据服务器上下文获取文件2的完整路径,该文件对应人脸2的图片 File file2 = new File(request.getSession().getServletContext().getRealPath("/upload")+"/"+face2); + // 将文件1转换为字节数组,再进行Base64编码,得到图片的Base64编码字符串 String img1 = Base64Util.encode(FileUtil.FileToByte(file1)); + // 同样对文件2进行操作,得到其Base64编码字符串 String img2 = Base64Util.encode(FileUtil.FileToByte(file2)); + // 创建一个MatchRequest对象,用于封装人脸1的图片Base64编码及编码格式信息 MatchRequest req1 = new MatchRequest(img1, "BASE64"); + // 创建一个MatchRequest对象,用于封装人脸2的图片Base64编码及编码格式信息 MatchRequest req2 = new MatchRequest(img2, "BASE64"); + // 创建一个ArrayList来存放MatchRequest对象,用于批量提交人脸比对请求 ArrayList requests = new ArrayList(); + // 将人脸1的MatchRequest对象添加到列表中 requests.add(req1); + // 将人脸2的MatchRequest对象添加到列表中 requests.add(req2); + // 调用百度人脸识别客户端的match方法,传入封装好的请求列表,进行人脸比对操作,获取比对结果 res = client.match(requests); + // 打印比对结果中的"result"部分,可能用于调试查看比对详情(此处可以考虑更合理的日志记录方式) System.out.println(res.get("result")); } catch (FileNotFoundException e) { + // 如果文件不存在,打印堆栈信息方便排查问题,并返回文件不存在的错误信息给客户端 e.printStackTrace(); return R.error("文件不存在"); } catch (IOException e) { + // 如果发生IO异常,打印堆栈信息方便排查问题 e.printStackTrace(); - } + } + // 将比对结果解析后封装到响应结果中,以"data"为键,返回成功响应给客户端 return R.ok().put("data", com.alibaba.fastjson.JSONObject.parse(res.get("result").toString())); } - - /** - * 获取table表中的column列表(联动接口) - * @return - */ + + +// 此方法用于获取指定数据表(table)中指定列(column)的列表数据,设计为一个联动接口,可能用于前端界面上如下拉菜单等组件的联动数据获取场景 +// 通过接收表名、列名以及可选的层级(level)和父级(parent)参数,来灵活查询满足条件的数据列表,并将结果返回给客户端 +// 该接口标注了 @RequestMapping 注解,指定了访问路径的格式,其中 {tableName} 和 {columnName} 是路径变量,会在请求时被实际的值替换 +// 同时标注了 @IgnoreAuth 注解,可能意味着此接口访问不需要进行权限认证(具体取决于项目中对该注解的定义和实现) +// @return 返回一个 R 类型的对象,通常用于封装响应结果(成功时包含查询到的数据列表等信息) @RequestMapping("/option/{tableName}/{columnName}") @IgnoreAuth public R getOption(@PathVariable("tableName") String tableName, @PathVariable("columnName") String columnName,String level,String parent) { + // 创建一个用于存储查询参数的 Map,键为字符串类型,值为 Object 类型,后续将传递给服务层(commonService)的方法用于查询操作 Map params = new HashMap(); + // 将表名参数放入 params 这个参数 Map 中,键为 "table",方便服务层方法知晓要操作的是哪个数据表 params.put("table", tableName); + // 将列名参数放入 params 这个参数 Map 中,键为 "column",用于指定要从数据表中获取哪一列的数据 params.put("column", columnName); + // 判断传入的 level 参数是否不为空字符串(即有实际的值传入),如果是,则将其放入参数 Map 中,键为 "level" + // 这个 level 参数可能用于在查询数据时按照某种层级关系进行筛选,比如在具有层级结构的数据表中筛选出特定层级的数据 if(StringUtils.isNotBlank(level)) { params.put("level", level); } + // 判断传入的 parent 参数是否不为空字符串(即有实际的值传入),如果是,则将其放入参数 Map 中,键为 "parent" + // 该参数可能用于在查询数据时基于某个父级元素进行筛选,例如获取某个父分类下的子项数据等场景 if(StringUtils.isNotBlank(parent)) { params.put("parent", parent); } + // 调用 commonService 的 getOption 方法,传递组装好的参数 Map,获取满足条件的数据列表,此处假设 commonService 是已经注入并实现了相应业务逻辑的服务类 List data = commonService.getOption(params); + // 使用 R 类型对象(可能是项目自定义的用于统一响应格式的类)封装查询到的数据列表,以 "data" 作为键值对中的键,将结果返回给客户端,返回的状态为成功状态(通过 R.ok() 表示) return R.ok().put("data", data); } - - /** - * 根据table中的column获取单条记录 - * @return - */ + + +// 此方法用于根据指定数据表(table)中的指定列(column)以及该列的具体值(columnValue)来获取单条记录数据 +// 接口同样标注了 @RequestMapping 注解定义访问路径格式,{tableName} 和 {columnName} 为路径变量,并且标注了 @IgnoreAuth 注解,可能不需要权限认证即可访问 +// @return 返回一个 R 类型的对象,在成功时会包含查询到的单条记录数据(以 Map 形式返回,具体结构取决于数据表的字段情况) @RequestMapping("/follow/{tableName}/{columnName}") @IgnoreAuth public R getFollowByOption(@PathVariable("tableName") String tableName, @PathVariable("columnName") String columnName, @RequestParam String columnValue) { + // 创建一个用于存储查询参数的 Map,用于传递给服务层(commonService)的方法来执行具体的查询操作 Map params = new HashMap(); + // 将表名参数放入 params 这个参数 Map 中,键为 "table",用于明确操作的是哪一个数据表 params.put("table", tableName); + // 将列名参数放入 params 这个参数 Map 中,键为 "column",用于指定依据哪一列的数据来查找记录 params.put("column", columnName); + // 将列的具体值参数放入 params 这个参数 Map 中,键为 "columnValue",这个值将用于在数据表中匹配相应的记录,比如根据某个唯一标识列的值来获取对应的记录 params.put("columnValue", columnValue); + // 调用 commonService 的 getFollowByOption 方法,传递组装好的参数 Map,获取满足条件的单条记录数据,假设 commonService 已经正确实现了对应的业务逻辑方法 Map result = commonService.getFollowByOption(params); + // 使用 R 类型对象封装查询到的单条记录数据,以 "data" 作为键值对中的键,将结果返回给客户端,返回状态为成功状态(通过 R.ok() 表示) return R.ok().put("data", result); } - - /** - * 修改table表的sfsh状态 - * @param map - * @return - */ + +// 此方法用于修改指定数据表(table)的 sfsh 状态,接收表名作为路径变量以及一个包含修改相关数据的 Map 参数(可能包含具体要修改的记录标识、新的状态值等信息) +// 通过调用 commonService 的 sh 方法来执行实际的修改操作,具体修改逻辑在 commonService.sh 方法中实现(此处未展示具体代码) +// @param map 包含修改 sfsh 状态相关数据的 Map,具体内容由客户端传入,其结构和内容取决于业务需求以及数据表的设计情况 +// @return 返回一个 R 类型的对象,表示操作成功的响应结果(这里没有返回具体修改后的详细数据等,仅表示操作成功) @RequestMapping("/sh/{tableName}") public R sh(@PathVariable("tableName") String tableName, @RequestBody Map map) { + // 将表名添加到传入的 map 参数中,键为 "table",以便在服务层(commonService)的 sh 方法中能准确知道要修改的是哪个数据表的 sfsh 状态 map.put("table", tableName); + // 调用 commonService 的 sh 方法,传递包含表名等信息的 map 参数,执行实际的修改 sfsh 状态的操作,具体的修改逻辑在 commonService.sh 方法内部实现 commonService.sh(map); + // 返回一个表示操作成功的 R 类型对象,给客户端反馈修改操作已经顺利完成 return R.ok(); } @@ -161,88 +214,149 @@ public class CommonController{ * @param map * @return */ + + // 此方法用于获取提醒相关的数量统计信息,通过接收表名、列名、类型以及其他相关查询参数(以Map形式接收)来确定统计范围和条件 + // @RequestMapping注解指定了访问此接口的路径格式,其中 {tableName}、{columnName}、{type} 为路径变量,会在请求时被实际的值替换 + // @IgnoreAuth注解表示该接口访问可能不需要进行权限认证(具体取决于项目中对该注解的定义和实现) + // @param tableName 表示要操作的数据表名称 + // @param columnName 表示数据表中相关的列名称,可能和提醒业务逻辑相关的某个字段 + // @param type 表示提醒的类型,不同类型可能对应不同的统计逻辑 + // @param map 包含其他额外的查询参数,例如在特定类型下可能包含提醒的起止时间等信息 + // @return 返回一个R类型的对象,用于封装响应结果,在成功时包含统计得到的提醒数量(以 "count" 作为键值对中的键) @RequestMapping("/remind/{tableName}/{columnName}/{type}") @IgnoreAuth - public R remindCount(@PathVariable("tableName") String tableName, @PathVariable("columnName") String columnName, - @PathVariable("type") String type,@RequestParam Map map) { + public R remindCount(@PathVariable("tableName") String tableName, @PathVariable("columnName") String columnName, @PathVariable("type") String type, @RequestParam Map map) { + // 将表名添加到传入的map参数中,键为 "table",方便后续在服务层(commonService)的方法中明确操作的数据表 map.put("table", tableName); + // 将列名添加到传入的map参数中,键为 "column",用于指定和提醒业务相关的列字段 map.put("column", columnName); + // 将提醒类型添加到传入的map参数中,键为 "type",服务层方法可根据此类型执行不同的统计逻辑 map.put("type", type); - + // 如果提醒类型等于 "2",则进行以下时间相关的处理逻辑,可能是针对类型为 "2" 的提醒设置特定的时间范围查询条件 if(type.equals("2")) { + // 创建一个SimpleDateFormat对象,用于格式化日期为 "yyyy-MM-dd" 的格式,方便后续在查询参数中设置日期格式统一的时间范围 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + // 获取一个Calendar实例,用于进行日期的计算操作,例如增加或减少天数等 Calendar c = Calendar.getInstance(); Date remindStartDate = null; Date remindEndDate = null; + + // 判断传入的查询参数中是否包含 "remindstart"(可能表示提醒开始时间的参数),如果有则进行以下处理 if(map.get("remindstart")!=null) { + // 将 "remindstart" 参数的值转换为整数类型,可能表示相对于当前日期要增加的天数等含义 Integer remindStart = Integer.parseInt(map.get("remindstart").toString()); - c.setTime(new Date()); + // 将Calendar实例的时间设置为当前日期 + c.setTime(new Date()); + // 在当前日期基础上增加指定的天数,此处根据 "remindstart" 的值来调整日期 c.add(Calendar.DAY_OF_MONTH,remindStart); + // 获取调整后的日期对象,即提醒开始日期 remindStartDate = c.getTime(); + // 将提醒开始日期按照指定格式进行格式化后,重新放入map参数中,替换原来的值,以便后续传递给服务层方法时日期格式符合要求 map.put("remindstart", sdf.format(remindStartDate)); } + + // 判断传入的查询参数中是否包含 "remindend"(可能表示提醒结束时间的参数),如果有则进行以下处理 if(map.get("remindend")!=null) { + // 将 "remindend" 参数的值转换为整数类型,类似 "remindstart",可能表示相对于当前日期要增加的天数等含义 Integer remindEnd = Integer.parseInt(map.get("remindend").toString()); + // 将Calendar实例的时间设置为当前日期 c.setTime(new Date()); + // 在当前日期基础上增加指定的天数,此处根据 "remindend" 的值来调整日期 c.add(Calendar.DAY_OF_MONTH,remindEnd); + // 获取调整后的日期对象,即提醒结束日期 remindEndDate = c.getTime(); + // 将提醒结束日期按照指定格式进行格式化后,重新放入map参数中,替换原来的值,以便后续传递给服务层方法时日期格式符合要求 map.put("remindend", sdf.format(remindEndDate)); } } - + + // 调用commonService的remindCount方法,传递处理好的查询参数map,获取满足条件的提醒数量统计结果 int count = commonService.remindCount(map); + // 使用R类型对象封装统计得到的提醒数量,以 "count" 作为键值对中的键,将结果返回给客户端,返回的状态为成功状态(通过R.ok()表示) return R.ok().put("count", count); } - /** - * 圖表统计 - */ + // 此方法用于进行图表相关的统计操作,可能是根据指定数据表中的数据生成图表所需的数据统计结果 + // 接口标注了 @IgnoreAuth 注解,意味着该接口访问可能不需要进行权限认证(具体取决于项目中对该注解的定义和实现) + // @RequestMapping注解指定了访问此接口的访问路径,其中 {tableName} 为路径变量,会被实际传入的表名替换 + // @param tableName 表示要操作的数据表名称,是图表统计数据的来源表 + // @param params 包含其他额外的图表统计相关的查询参数(以Map形式传入),具体参数内容取决于图表统计的业务需求和设计 + // @return 返回一个R类型的对象,用于封装响应结果,在成功时包含图表统计得到的数据结果(以 "data" 作为键值对中的键) @IgnoreAuth @RequestMapping("/group/{tableName}") public R group1(@PathVariable("tableName") String tableName, @RequestParam Map params) { + // 将表名添加到传入的params参数中,键为 "table1",方便服务层(commonService)的方法知晓操作的数据表,此处键为 "table1" 可能是服务层方法内部约定的参数名 params.put("table1", tableName); + // 调用commonService的chartBoth方法,传递包含表名等信息的查询参数params,获取图表统计相关的数据结果,假设commonService已经正确实现了对应的业务逻辑方法 List> result = commonService.chartBoth(params); + // 使用R类型对象封装图表统计得到的数据结果,以 "data" 作为键值对中的键,将结果返回给客户端,返回的状态为成功状态(通过R.ok()表示) return R.ok().put("data", result); } - - /** - * 单列求和 - */ + // 此方法用于对指定数据表中的单列数据进行求和操作,获取该列数据的总和统计值 + // @RequestMapping注解指定了访问此接口的路径格式,其中 {tableName}、{columnName} 为路径变量,会在请求时被实际的值替换 + // @IgnoreAuth注解表示该接口访问可能不需要进行权限认证(具体取决于项目中对该注解的定义和实现) + // @param tableName 表示要操作的数据表名称,即包含要进行求和操作列的数据表 + // @param columnName 表示数据表中要进行求和的列名称 + // @return 返回一个R类型的对象,用于封装响应结果,在成功时包含单列求和得到的结果数据(以 "data" 作为键值对中的键) @RequestMapping("/cal/{tableName}/{columnName}") @IgnoreAuth public R cal(@PathVariable("tableName") String tableName, @PathVariable("columnName") String columnName) { - Map params = new HashMap(); + // 创建一个用于存储查询参数的Map,用于传递给服务层(commonService)的方法来执行单列求和操作 + Map params = new HashMap<>(); + // 将表名参数放入params这个参数Map中,键为 "table",方便服务层方法明确操作的数据表 params.put("table", tableName); + // 将列名参数放入params这个参数Map中,键为 "column",用于指定要进行求和操作的列 params.put("column", columnName); + // 调用commonService的selectCal方法,传递组装好的参数Map,获取单列求和的结果数据,假设commonService已经正确实现了对应的业务逻辑方法 Map result = commonService.selectCal(params); + // 使用R类型对象封装单列求和得到的结果数据,以 "data" 作为键值对中的键,将结果返回给客户端,返回的状态为成功状态(通过R.ok()表示) return R.ok().put("data", result); } - - /** - * 分组统计 - */ + + // 此方法用于进行分组统计操作,根据指定数据表(tableName)中的指定列(columnName)来进行分组统计分析 + // @RequestMapping注解指定了访问此接口的路径格式,其中 {tableName} 和 {columnName} 为路径变量,会在请求时被实际传入的表名和列名替换 + // @IgnoreAuth注解表示该接口访问可能不需要进行权限认证(具体取决于项目中对该注解的定义和实现) + // @param tableName 表示要操作的数据表名称,是进行分组统计的数据来源表 + // @param columnName 表示数据表中用于分组的列名称,依据该列的值将数据进行分组后再做统计相关操作 + // @return 返回一个R类型的对象,用于封装响应结果,在成功时包含分组统计得到的数据结果(以 "data" 作为键值对中的键) @RequestMapping("/group/{tableName}/{columnName}") @IgnoreAuth public R group(@PathVariable("tableName") String tableName, @PathVariable("columnName") String columnName) { - Map params = new HashMap(); + // 创建一个用于存储查询参数的Map,键为字符串类型,值为Object类型,后续将传递给服务层(commonService)的方法用于分组统计操作 + Map params = new HashMap<>(); + // 将表名参数放入params这个参数Map中,键为 "table",方便服务层方法知晓要操作的是哪个数据表 params.put("table", tableName); + // 将用于分组的列名参数放入params这个参数Map中,键为 "column",服务层方法将依据此列进行分组统计 params.put("column", columnName); + // 调用commonService的selectGroup方法,传递组装好的参数Map,获取分组统计相关的数据结果,假设commonService已经正确实现了对应的业务逻辑方法 List> result = commonService.selectGroup(params); + // 使用R类型对象封装分组统计得到的数据结果,以 "data" 作为键值对中的键,将结果返回给客户端,返回的状态为成功状态(通过R.ok()表示) return R.ok().put("data", result); } - - /** - * (按值统计) - */ + + // 此方法用于进行按值统计操作,根据指定数据表(tableName)中的指定的X列(xColumnName)和Y列(yColumnName)来进行相关统计分析,具体统计逻辑由服务层方法决定 + // @RequestMapping注解指定了访问此接口的路径格式,其中 {tableName}、{xColumnName}、{yColumnName} 为路径变量,会在请求时被实际传入的表名、X列名和Y列名替换 + // @IgnoreAuth注解表示该接口访问可能不需要进行权限认证(具体取决于项目中对该注解的定义和实现) + // @param tableName 表示要操作的数据表名称,是进行按值统计的数据来源表 + // @param yColumnName 表示数据表中作为Y维度(具体维度含义取决于业务逻辑)的列名称,用于统计相关操作中的一个关键列 + // @param xColumnName 表示数据表中作为X维度(与Y维度共同构成统计维度关系,具体由业务逻辑确定)的列名称,也是用于统计相关操作的关键列 + // @return 返回一个R类型的对象,用于封装响应结果,在成功时包含按值统计得到的数据结果(以 "data" 作为键值对中的键) @RequestMapping("/value/{tableName}/{xColumnName}/{yColumnName}") @IgnoreAuth - public R value(@PathVariable("tableName") String tableName, @PathVariable("yColumnName") String yColumnName, @PathVariable("xColumnName") String xColumnName) { - Map params = new HashMap(); + public R value(@PathVariable("tableName") String tableName, @PathVariable("yColumnName") String yColumnName, + @PathVariable("xColumnName") String xColumnName) { + // 创建一个用于存储查询参数的Map,用于传递给服务层(commonService)的方法来执行按值统计操作 + Map params = new HashMap<>(); + // 将表名参数放入params这个参数Map中,键为 "table",便于服务层方法明确操作的数据表 params.put("table", tableName); + // 将X列名参数放入params这个参数Map中,键为 "xColumn",用于指定按值统计中X维度对应的列,服务层方法将依据此列进行相应统计逻辑 params.put("xColumn", xColumnName); + // 将Y列名参数放入params这个参数Map中,键为 "yColumn",用于指定按值统计中Y维度对应的列,与X列共同参与统计分析 params.put("yColumn", yColumnName); + // 调用commonService的selectValue方法,传递组装好的参数Map,获取按值统计相关的数据结果,假设commonService已经正确实现了对应的业务逻辑方法 List> result = commonService.selectValue(params); + // 使用R类型对象封装按值统计得到的数据结果,以 "data" 作为键值对中的键,将结果返回给客户端,返回的状态为成功状态(通过R.ok()表示) return R.ok().put("data", result); } @@ -261,10 +375,18 @@ public class CommonController{ * sumCloum 统计字段 * @return */ + + // 此方法用于执行一种新的分组求和统计操作,接收一个包含各种查询参数的Map对象,参数具体内容由客户端传入,根据这些参数进行相应的统计计算 +// @RequestMapping注解指定了访问此接口的路径,客户端通过访问该路径来触发此方法执行相应的业务逻辑 +// @param params 一个包含各种统计相关查询参数的Map,键为字符串类型,值为Object类型,其具体的键值对内容取决于业务需求和统计逻辑,例如可能包含数据表名、要分组的列名、求和的列名等信息 +// @return 返回一个R类型的对象,用于封装响应结果,在成功时会将新的分组求和统计得到的数据结果以 "data" 作为键值对中的键进行封装并返回给客户端,表示操作成功 @RequestMapping("/newSelectGroupSum") public R newSelectGroupSum(@RequestParam Map params) { + // 使用日志记录器记录DEBUG级别的日志信息,输出当前执行的方法名称(通过 this.getClass().getName() 获取类名)以及传入的参数信息,方便在调试时查看方法的调用情况和参数情况 logger.debug("newSelectGroupSum:,,Controller:{},,params:{}",this.getClass().getName(),params); + // 调用commonService的newSelectGroupSum方法,传递接收到的包含查询参数的Map对象,获取新的分组求和统计相关的数据结果,假设commonService已经正确实现了对应的业务逻辑方法 List> result = commonService.newSelectGroupSum(params); + // 使用R类型对象封装新的分组求和统计得到的数据结果,以 "data" 作为键值对中的键,将结果返回给客户端,返回的状态为成功状态(通过R.ok()表示) return R.ok().put("data", result); } @@ -279,11 +401,23 @@ public class CommonController{ 有值 Number(res.data.value.toFixed(1)) 无值 if(res.data){} * */ + + // 标注了 @IgnoreAuth 注解,意味着该接口访问可能不需要进行权限认证(具体取决于项目中对该注解的定义和实现)。 @IgnoreAuth + // @RequestMapping 注解用于将 HTTP 请求映射到对应的处理方法上,这里指定了访问此接口的路径为 "/queryScore", + // 当客户端发起对应路径的请求时,该方法就会被调用执行相应的业务逻辑。 @RequestMapping("/queryScore") + // 定义了一个名为 queryScore 的公共方法,用于查询分数相关的数据,接收一个包含各种查询参数的 Map 对象。 public R queryScore(@RequestParam Map params) { + // 创建一个日志记录器,用于记录该类中的相关日志信息,此处使用 DEBUG 级别记录日志,方便调试和排查问题。 + // 这条日志语句会输出当前执行的方法名称(通过 this.getClass().getName() 获取类名)以及传入的参数信息, + // 便于在调试过程中查看该方法被调用时具体传入了哪些参数。 logger.debug("queryScore:,,Controller:{},,params:{}",this.getClass().getName(),params); + // 调用 commonService 的 queryScore 方法,传递接收到的包含查询参数的 Map 对象,获取查询分数相关的数据结果, + // 这里假设 commonService 是已经注入并且正确实现了对应业务逻辑的服务类,能够根据传入的参数执行具体的查询操作并返回相应结果。 Map queryScore = commonService.queryScore(params); + // 使用 R 类型对象(可能是项目自定义的用于统一响应格式的类)封装查询得到的分数相关数据结果, + // 以 "data" 作为键值对中的键,将结果返回给客户端,返回的状态为成功状态(通过 R.ok() 表示)。 return R.ok().put("data", queryScore); } @@ -293,10 +427,24 @@ public class CommonController{ * groupColumn 分组字段 * @return */ + + // @RequestMapping注解用于将HTTP请求路径映射到对应的处理方法上,这里指定了此方法对应的请求路径为"/newSelectGroupCount", + // 意味着当客户端发起访问该路径的请求时,此方法将会被调用执行相应的业务逻辑操作。 @RequestMapping("/newSelectGroupCount") + // 定义了一个公共方法newSelectGroupCount,它用于执行一种新的分组计数统计操作,接收一个包含各种统计相关参数的Map对象, + // 这些参数由客户端传入,用于明确具体的统计范围、条件等内容,其键为字符串类型,值可以是各种Java对象类型。 public R newSelectGroupCount(@RequestParam Map params) { + // 创建了一个日志记录器logger,用于记录该方法执行过程中的相关日志信息,此处使用DEBUG级别来记录日志,方便在调试阶段查看详细的执行情况。 + // 通过下面这行日志语句,会在日志中输出当前正在执行的方法名称(通过this.getClass().getName()获取类的全限定名来表示方法所在类) + // 以及传入该方法的参数信息,有助于排查在调用此方法时参数是否符合预期等问题。 logger.debug("newSelectGroupCount:,,Controller:{},,params:{}",this.getClass().getName(),params); + // 调用commonService(此处应是已经通过依赖注入获取到的业务服务类实例,并且假设其内部已经正确实现了相应的业务逻辑方法)的 + // newSelectGroupCount方法,将接收到的包含统计参数的Map对象传递进去,以获取新的分组计数统计操作的结果数据, + // 返回的数据类型是一个包含多个Map的List集合,每个内层的Map可能表示一组统计结果相关的信息,具体取决于业务逻辑的设计。 List> result = commonService.newSelectGroupCount(params); + // 使用R类型的对象(大概率是项目自定义的用于统一封装响应结果的类,例如包含了响应状态码、消息以及具体数据等信息)来封装统计结果, + // 以"data"作为键值对中的键,将获取到的分组计数统计结果放入其中,然后将整个封装好的R对象返回给客户端, + // 通过R.ok()表示此次操作执行成功,客户端接收到返回结果后可根据约定的格式解析并获取相应的统计数据信息。 return R.ok().put("data", result); } @@ -309,47 +457,86 @@ public class CommonController{ * dateFormatType 日期格式化类型 1:年 2:月 3:日 * @return */ + + // 此方法用于对当前表按照日期进行分组求和统计操作,根据传入的不同参数来确定具体的统计逻辑和日期格式化方式等内容。 + // 通过接收一个包含多个参数的Map对象,从其中获取必要的信息进行相应处理,并调用服务层方法完成统计功能,最后将结果返回给客户端。 + // @RequestMapping注解指定了访问此接口的请求路径为"/newSelectDateGroupSum",当客户端发起对应路径的请求时,该方法会被触发执行。 @RequestMapping("/newSelectDateGroupSum") public R newSelectDateGroupSum(@RequestParam Map params) { + // 使用日志记录器记录DEBUG级别的日志信息,输出当前执行的方法名称(通过 this.getClass().getName() 获取类名)以及传入的参数信息, + // 方便在调试时查看方法的调用情况以及传入参数是否符合预期等情况。 logger.debug("newSelectDateGroupSum:,,Controller:{},,params:{}",this.getClass().getName(),params); + + // 从传入的参数Map中获取日期格式化类型(dateFormatType)参数的值,并转换为字符串类型进行后续判断处理。 + // 该参数用于决定对日期进行何种程度的格式化,进而影响分组统计的逻辑,例如按照年、月或日来分组求和。 String dateFormatType = String.valueOf(params.get("dateFormatType")); + + // 根据获取到的日期格式化类型进行判断,如果为 "1",表示按照年份进行日期格式化及分组求和统计。 if("1".equals(dateFormatType)){ + // 在参数Map中添加 "dateFormat" 键值对,其值为 "%Y",这是一种日期格式化的占位符表示形式,用于后续在数据库查询等操作中 + // 将日期格式化为只保留年份信息,以便按照年份进行分组求和统计。 params.put("dateFormat", "%Y"); + // 如果日期格式化类型为 "2",表示按照月份进行日期格式化及分组求和统计。 }else if("2".equals(dateFormatType)){ + // 在参数Map中添加 "dateFormat" 键值对,其值为 "%Y-%m",用于将日期格式化为包含年份和月份的信息,满足按月分组求和统计的需求。 params.put("dateFormat", "%Y-%m"); + // 如果日期格式化类型为 "3",表示按照日期(天)进行日期格式化及分组求和统计。 }else if("3".equals(dateFormatType)){ + // 在参数Map中添加 "dateFormat" 键值对,其值为 "%Y-%m-%d",用于将日期格式化为包含完整的年、月、日信息,便于按日进行分组求和统计。 params.put("dateFormat", "%Y-%m-%d"); + // 如果日期格式化类型不是上述预定义的 "1"、"2"、"3" 中的任何一个,则表示传入的日期格式化类型不正确,不符合业务逻辑要求。 }else{ - R.error("日期格式化不正确"); + // 返回一个表示错误状态的R对象,其中包含了错误提示信息 "日期格式化不正确",用于告知客户端请求参数有误,无法正常执行统计操作。 + return R.error("日期格式化不正确"); } + + // 调用commonService(假设是已经注入并正确实现了对应业务逻辑的服务类)的newSelectDateGroupSum方法,传递处理好的包含各种参数的Map对象, + // 获取按照日期分组求和统计后的结果数据,返回的数据类型是一个包含多个Map的List集合,每个内层的Map可能对应一组分组求和的统计结果信息。 List> result = commonService.newSelectDateGroupSum(params); + + // 使用R类型对象(通常是项目自定义用于统一响应格式的类)封装统计得到的结果数据,以 "data" 作为键值对中的键,将结果返回给客户端, + // 通过R.ok()表示此次操作执行成功,客户端可根据约定的格式解析返回结果获取相应的分组求和统计数据。 return R.ok().put("data", result); } - /** - * - * 查询字典表的分组统计总条数 - * tableName 表名 - * groupColumn 分组字段 - * dateFormatType 日期格式化类型 1:年 2:月 3:日 - * @return - */ + // 此方法用于查询字典表的分组统计总条数,同样依据传入的参数来确定具体的统计逻辑以及日期格式化方式等,与上面的方法类似但功能是统计总条数。 + // 通过接收包含相关参数的Map对象,对日期格式化类型进行判断处理后,调用服务层相应方法完成统计功能,并将结果返回给客户端。 + // @RequestMapping注解指定了访问此接口的请求路径为"/newSelectDateGroupCount",客户端访问该路径时会触发此方法执行。 @RequestMapping("/newSelectDateGroupCount") public R newSelectDateGroupCount(@RequestParam Map params) { + // 记录DEBUG级别的日志信息,输出当前执行的方法名称以及传入的参数情况,方便调试过程中查看方法调用及参数相关情况。 logger.debug("newSelectDateGroupCount:,,Controller:{},,params:{}",this.getClass().getName(),params); + + // 获取传入参数Map中的日期格式化类型(dateFormatType)参数的值,并转换为字符串类型,用于后续的条件判断操作。 String dateFormatType = String.valueOf(params.get("dateFormatType")); + + // 判断日期格式化类型是否为 "1",如果是,则表示按照年份进行日期格式化及分组统计总条数的操作。 if("1".equals(dateFormatType)){ + // 在参数Map中添加 "dateFormat" 键值对,其值为 "%Y",用于将日期格式化为只保留年份信息,以满足按年分组统计总条数的需求。 params.put("dateFormat", "%Y"); + // 如果日期格式化类型为 "2",表示按照月份进行日期格式化及分组统计总条数的操作。 }else if("2".equals(dateFormatType)){ + // 在参数Map中添加 "dateFormat" 键值对,其值为 "%Y-%m",用于将日期格式化为包含年份和月份的信息,便于按月分组统计总条数。 params.put("dateFormat", "%Y-%m"); + // 如果日期格式化类型为 "3",表示按照日期(天)进行日期格式化及分组统计总条数的操作。 }else if("3".equals(dateFormatType)){ + // 在参数Map中添加 "dateFormat" 键值对,其值为 "%Y-%m-%d",用于将日期格式化为包含完整的年、月、日信息,以实现按日分组统计总条数。 params.put("dateFormat", "%Y-%m-%d"); + // 如果日期格式化类型不是上述定义的 "1"、"2"、"3" 中的任何一个,说明传入的日期格式化类型不符合业务要求,是不正确的。 }else{ + // 返回一个表示错误状态的R对象,其中包含错误提示信息 "日期格式化类型不正确",告知客户端请求参数有误,无法正常执行统计操作。 R.error("日期格式化类型不正确"); } + + // 调用commonService的newSelectDateGroupCount方法,传递处理好的包含各种参数的Map对象,获取字典表按照日期分组统计总条数的结果数据, + // 返回的数据是一个包含多个Map的List集合,每个内层的Map可能对应一组分组统计总条数的相关信息。 List> result = commonService.newSelectDateGroupCount(params); + + // 使用R类型对象封装统计得到的结果数据,以 "data" 作为键值对中的键,将结果返回给客户端,通过R.ok()表示此次操作执行成功, + // 客户端接收到返回结果后可按照约定格式解析获取相应的分组统计总条数数据。 return R.ok().put("data", result); } + /** * 饼状图 * -- 饼状图 查询当前表 @@ -395,36 +582,70 @@ public class CommonController{ /** * 柱状图求和 */ + + // 此方法用于进行柱状图相关的数据求和操作,接收一个包含各种参数的Map对象,这些参数用于确定求和的具体条件、涉及的数据表等信息。 + // 在方法内部会对参数进行一系列处理,包括解析JSON字符串为Map、对特定字段按逗号进行分割处理等,为后续的求和操作做准备。 + // @RequestMapping注解指定了访问此接口的请求路径为"/barSum",当客户端发起对应路径的请求时,该方法会被触发执行相应的业务逻辑。 @RequestMapping("/barSum") public R barSum(@RequestParam Map params) { - logger.debug("barSum方法:,,Controller:{},,params:{}",this.getClass().getName(), com.alibaba.fastjson.JSONObject.toJSONString(params)); - Boolean isJoinTableFlag = false;//是否有级联表相关 - String one = "";//第一优先 - String two = "";//第二优先 + // 使用日志记录器记录DEBUG级别的日志信息,输出当前执行的方法名称(通过 this.getClass().getName() 获取类名)以及传入参数转换为JSON字符串后的内容, + // 方便在调试时查看方法的调用情况以及传入参数的具体情况,此处将参数转换为JSON字符串是为了更清晰完整地展示参数结构和内容。 + logger.debug("barSum方法:,,Controller:{},,params:{}",this.getClass().getName(),com.alibaba.fastjson.JSONObject.toJSONString(params)); + // 定义一个布尔变量,用于标记是否存在级联表相关的情况,初始化为false,表示默认没有级联表相关操作。 + Boolean isJoinTableFlag = false;//是否有级联表相关 + // 定义一个字符串变量,用于记录第一优先处理的字段相关标识,初始化为空字符串,后续会根据具体情况赋值。 + String one = "";//第一优先 + // 定义一个字符串变量,用于记录第二优先处理的字段相关标识,初始化为空字符串,同样会根据具体情况进行赋值。 + String two = "";//第二优先 - //处理thisTable和joinTable 处理内容是把json字符串转为Map并把带有,的切割为数组 - //当前表 + // 以下开始处理当前表(thisTable)和级联表(joinTable)相关的参数内容,主要操作是将JSON字符串形式的参数转换为Map类型,并对带有逗号的特定字段进行切割处理,转化为数组形式。 + + // 处理当前表(thisTable)相关参数。 + // 从传入的参数Map中获取名为 "thisTable" 的参数值(其原本为JSON字符串形式),将其转换为Map类型,以便后续方便操作其中的各个字段信息。 Map thisTable = JSON.parseObject(String.valueOf(params.get("thisTable")),Map.class); + // 将转换后的当前表相关的Map对象重新放回参数Map中,覆盖原来的JSON字符串形式,方便后续统一基于Map形式进行操作。 params.put("thisTable",thisTable); //级联表 + // 处理级联表(joinTable)相关参数。 + // 从传入的参数Map中获取名为 "joinTable" 的参数值(其为JSON字符串形式),并转换为字符串类型进行后续判断处理。 String joinTableString = String.valueOf(params.get("joinTable")); + // 判断级联表的字符串表示是否不为空(即存在级联表相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(joinTableString)) { + // 将级联表的JSON字符串形式的参数转换为Map类型,以便后续操作其中的字段信息。 Map joinTable = JSON.parseObject(joinTableString, Map.class); + // 将转换后的级联表相关的Map对象重新放回参数Map中,覆盖原来的JSON字符串形式,便于后续统一处理。 params.put("joinTable", joinTable); + // 将表示存在级联表相关的标志变量置为true,用于后续其他逻辑判断,表明当前操作涉及级联表。 isJoinTableFlag = true; } + // 以下是根据当前表(thisTable)和级联表(joinTable)中不同字段的情况,对相关字段进行处理,并确定第一优先和第二优先处理的字段标识。 + + // 处理当前表日期字段(date)相关情况。 + // 判断当前表的 "date" 字段值是否不为空(即有日期相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(String.valueOf(thisTable.get("date")))){//当前表日期 + // 将当前表的 "date" 字段值(原本为字符串形式,可能包含逗号分隔的多个日期值)按逗号进行分割,转化为字符串数组形式, + // 以便后续在求和等操作中能更方便地处理多个日期相关的数据情况,然后将处理后的数组重新放回当前表的Map中,覆盖原来的字符串值。 thisTable.put("date",String.valueOf(thisTable.get("date")).split(",")); + // 将第一优先处理的字段标识设置为 "thisDate0",表示当前表日期字段在后续操作中可能具有第一优先级(具体优先级作用取决于整体业务逻辑)。 one = "thisDate0"; } + + // 处理级联表日期字段(date)相关情况,前提是存在级联表相关(即 isJoinTableFlag 为true)。 if(isJoinTableFlag){//级联表日期 + // 从参数Map中获取级联表对应的Map对象,方便后续操作其中的日期字段信息。 Map joinTable = (Map) params.get("joinTable"); + // 判断级联表的 "date" 字段值是否不为空(即有日期相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(String.valueOf(joinTable.get("date")))){ + // 将级联表的 "date" 字段值按逗号进行分割,转化为字符串数组形式,便于后续处理多个日期相关的数据情况, + // 然后将处理后的数组重新放回级联表的Map中,覆盖原来的字符串值。 joinTable.put("date",String.valueOf(joinTable.get("date")).split(",")); + // 判断第一优先处理的字段标识是否为空,如果为空,则表示当前级联表日期字段在这种情况下具有第一优先级,将其标识设置为 "joinDate0"。 if(StringUtil.isEmpty(one)){ one ="joinDate0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识是否为空, + // 如果为空,则表示当前级联表日期字段在这种情况下具有第二优先级,将其标识设置为 "joinDate0"。 }else{ if(StringUtil.isEmpty(two)){ two ="joinDate0"; @@ -432,22 +653,38 @@ public class CommonController{ } } } + + // 处理当前表字符串字段(string)相关情况。 if(StringUtil.isNotEmpty(String.valueOf(thisTable.get("string")))){//当前表字符串 + // 将当前表的 "string" 字段值(原本为字符串形式,可能包含逗号分隔的多个字符串值)按逗号进行分割,转化为字符串数组形式, + // 方便后续在求和等操作中处理多个字符串相关的数据情况,然后将处理后的数组重新放回当前表的Map中,覆盖原来的字符串值。 thisTable.put("string",String.valueOf(thisTable.get("string")).split(",")); + // 判断第一优先处理的字段标识是否为空,如果为空,则表示当前表字符串字段在这种情况下具有第一优先级,将其标识设置为 "thisString0"。 if(StringUtil.isEmpty(one)){ one ="thisString0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识是否为空, + // 如果为空,则表示当前表字符串字段在这种情况下具有第二优先级,将其标识设置为 "thisString0"。 }else{ if(StringUtil.isEmpty(two)){ two ="thisString0"; } } } + + // 处理级联表字符串字段(string)相关情况,前提是存在级联表相关(即 isJoinTableFlag 为true)。 if(isJoinTableFlag){//级联表字符串 + // 从参数Map中获取级联表对应的Map对象,方便后续操作其中的字符串字段信息。 Map joinTable = (Map) params.get("joinTable"); + // 判断级联表的 "string" 字段值是否不为空(即有字符串相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(String.valueOf(joinTable.get("string")))){ + // 将级联表的 "string" 字段值按逗号进行分割,转化为字符串数组形式,便于后续处理多个字符串相关的数据情况, + // 然后将处理后的数组重新放回级联表的Map中,覆盖原来的字符串值。 joinTable.put("string",String.valueOf(joinTable.get("string")).split(",")); + // 判断第一优先处理的字段标识是否为空,如果为空,则表示当前级联表字符串字段在这种情况下具有第一优先级,将其标识设置为 "joinString0"。 if(StringUtil.isEmpty(one)){ one ="joinString0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识是否为空, + // 如果为空,则表示当前级联表字符串字段在这种情况下具有第二优先级,将其标识设置为 "joinString0"。 }else{ if(StringUtil.isEmpty(two)){ two ="joinString0"; @@ -455,22 +692,40 @@ public class CommonController{ } } } + + + // 处理当前表(thisTable)类型(types)字段相关情况。 + // 判断当前表的 "types" 字段值是否不为空(即有类型相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(String.valueOf(thisTable.get("types")))){//当前表类型 + // 将当前表的 "types" 字段值(原本为字符串形式,可能包含逗号分隔的多个类型值)按逗号进行分割,转化为字符串数组形式, + // 方便后续在柱状图相关操作(比如数据分类展示等)中能更好地处理多个类型相关的数据情况,然后将处理后的数组重新放回当前表的Map中,覆盖原来的字符串值。 thisTable.put("types",String.valueOf(thisTable.get("types")).split(",")); + // 判断第一优先处理的字段标识(one)是否为空,如果为空,则表示当前表类型字段在这种情况下具有第一优先级,将其标识设置为 "thisTypes0"。 if(StringUtil.isEmpty(one)){ one ="thisTypes0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识(two)是否为空, + // 如果为空,则表示当前表类型字段在这种情况下具有第二优先级,将其标识设置为 "thisTypes0"。 }else{ if(StringUtil.isEmpty(two)){ two ="thisTypes0"; } } } + + // 处理级联表(joinTable)类型(types)字段相关情况,前提是存在级联表相关(即 isJoinTableFlag 为true)。 if(isJoinTableFlag){//级联表类型 + // 从参数Map中获取级联表对应的Map对象,方便后续操作其中的类型字段信息。 Map joinTable = (Map) params.get("joinTable"); + // 判断级联表的 "types" 字段值是否不为空(即有类型相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(String.valueOf(joinTable.get("types")))){ + // 将级联表的 "types" 字段值按逗号进行分割,转化为字符串数组形式,便于后续处理多个类型相关的数据情况, + // 然后将处理后的数组重新放回级联表的Map中,覆盖原来的字符串值。 joinTable.put("types",String.valueOf(joinTable.get("types")).split(",")); + // 判断第一优先处理的字段标识(one)是否为空,如果为空,则表示当前级联表类型字段在这种情况下具有第一优先级,将其标识设置为 "joinTypes0"。 if(StringUtil.isEmpty(one)){ one ="joinTypes0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识(two)是否为空, + // 如果为空,则表示当前级联表类型字段在这种情况下具有第二优先级,将其标识设置为 "joinTypes0"。 }else{ if(StringUtil.isEmpty(two)){ two ="joinTypes0"; @@ -480,103 +735,198 @@ public class CommonController{ } } + // 调用 commonService(假设是已经注入并正确实现了对应业务逻辑的服务类)的 barSum 方法,传递处理好的包含各种参数的Map对象, + // 获取柱状图求和相关的结果数据,返回的数据类型是一个包含多个Map的List集合,每个内层的Map可能对应一组求和相关的统计结果信息,具体取决于业务逻辑的设计。 List> result = commonService.barSum(params); + // 创建一个用于存储报表 x 轴数据的 ArrayList,后续会将相应的数据添加到该列表中,用于在柱状图中展示 x 轴相关内容(比如分类名称等)。 List xAxis = new ArrayList<>();//报表x轴 + // 创建一个用于存储报表 y 轴数据的 ArrayList,由于 y 轴数据可能有多层结构(比如不同分组下对应不同的数据值等情况),所以这里的元素类型也是ArrayList, + // 后续会根据具体情况构建并添加相应的数据,用于在柱状图中展示 y 轴相关内容(比如不同分类对应的数值等)。 List> yAxis = new ArrayList<>();//y轴 + // 创建一个用于存储报表标题(legend,通常在图表中用于标识不同数据系列的名称)的 ArrayList,后续会将相应的标题名称添加到该列表中,用于在柱状图中展示图例相关内容。 List legend = new ArrayList<>();//标题 + // 判断第二优先处理的字段标识(two)是否为空,以此来区分数据是否包含第二列相关情况,进而采用不同的逻辑来处理结果数据并构建用于柱状图展示的数据结构。 + + // 如果不包含第二列(即 two 为空),表示数据结构相对简单,只有单一维度的数据情况,进行以下处理。 if(StringUtil.isEmpty(two)){//不包含第二列 + // 创建一个用于存储 y 轴单层数据的 ArrayList,后续会将具体的数据值添加到该列表中,作为 y 轴数据的唯一一层数据。 List yAxis0 = new ArrayList<>(); + // 将刚创建的 y 轴单层数据列表添加到 y 轴数据的外层列表中,构建出符合柱状图数据展示要求的 y 轴数据结构(这里只有一层数据情况)。 yAxis.add(yAxis0); + // 添加一个默认的标题名称 "数值" 到 legend 列表中,用于在柱状图中作为唯一的数据系列的图例标识,表示展示的是数值相关的数据。 legend.add("数值"); + // 遍历获取到的柱状图求和结果数据列表(result),对每个结果 Map 进行处理,提取相应的数据添加到 x 轴和 y 轴数据列表中。 for(Map map :result){ + // 获取第一优先处理的字段对应的值,并转换为字符串类型,该值将作为 x 轴上的分类标识等信息添加到 x 轴数据列表中。 String oneValue = String.valueOf(map.get(one)); + // 获取名为 "value" 的字段对应的值(推测是求和得到的数值,具体取决于业务逻辑),并转换为字符串类型,该值将作为 y 轴上对应分类的数值添加到 y 轴数据列表中。 String value = String.valueOf(map.get("value")); + // 将第一优先处理的字段对应的值添加到 x 轴数据列表中,用于在柱状图的 x 轴上展示分类相关信息。 xAxis.add(oneValue); + // 将求和得到的数值添加到 y 轴的单层数据列表中,用于在柱状图的 y 轴上展示对应分类的数值情况。 yAxis0.add(value); } + // 如果包含第二列(即 two 不为空),表示数据结构相对复杂,存在多层维度的数据情况,进行以下处理。 }else{//包含第二列 + // 创建一个 LinkedHashMap,用于存储更复杂的数据结构,键为第一优先处理的字段对应的值(通常是一种分类标识), + // 值为 HashMap,内层的 HashMap 键为第二优先处理的字段对应的值(另一种分类标识),值为具体的数值(比如求和得到的数值等), + // 通过这种结构可以方便地对具有两层分类的数据进行整理和后续在柱状图中的展示。 Map> dataMap = new LinkedHashMap<>(); + // 判断第二优先处理的字段标识(two)是否不为空(这里其实已经在前面判断过了,只是再次确认一下逻辑完整性),如果是,则进行以下循环处理。 if(StringUtil.isNotEmpty(two)){ + // 遍历获取到的柱状图求和结果数据列表(result),对每个结果 Map 进行处理,提取相应的数据填充到 dataMap 中,构建复杂的数据结构。 for(Map map :result){ + // 获取第一优先处理的字段对应的值,并转换为字符串类型,作为外层 dataMap 的键(一种分类标识)。 String oneValue = String.valueOf(map.get(one)); + // 获取第二优先处理的字段对应的值,并转换为字符串类型,作为内层 HashMap 的键(另一种分类标识)。 String twoValue = String.valueOf(map.get(two)); + // 获取名为 "value" 的字段对应的值(推测是求和得到的数值,具体取决于业务逻辑),并转换为字符串类型,作为内层 HashMap 的值(具体的数值)。 String value = String.valueOf(map.get("value")); + // 判断 legend 列表中是否已经包含了当前的第二优先处理的字段对应的值(即判断是否已经添加过该分类标识作为图例名称), + // 如果不包含,则将其添加到 legend 列表中,用于在柱状图中作为不同数据系列的图例标识,确保图例包含了所有的分类情况。 if(!legend.contains(twoValue)){ legend.add(twoValue);//添加完成后 就是最全的第二列的类型 } + // 判断 dataMap 中是否已经包含了当前的第一优先处理的字段对应的值(即判断是否已经有该外层分类标识对应的内层数据结构),如果包含,说明之前已经处理过同类型的外层分类,进行以下操作。 if(dataMap.containsKey(oneValue)){ + // 获取已经存在的对应外层分类标识下的内层 HashMap,然后将当前的第二优先处理的字段对应的值和数值添加到该内层 HashMap 中, + // 用于更新或补充该外层分类下不同内层分类对应的数值情况。 dataMap.get(oneValue).put(twoValue,value); + // 如果 dataMap 中不包含当前的第一优先处理的字段对应的值,说明是新的外层分类情况,进行以下操作。 }else{ + // 创建一个新的内层 HashMap,用于存储当前外层分类下不同内层分类对应的数值情况。 HashMap oneData = new HashMap<>(); + // 将当前的第二优先处理的字段对应的值和数值添加到新创建的内层 HashMap 中。 oneData.put(twoValue,value); + // 将新创建的内层 HashMap 作为值,以当前的第一优先处理的字段对应的值作为键,添加到 dataMap 中,构建出完整的两层分类数据结构。 dataMap.put(oneValue,oneData); } } } + + // 这段代码的主要目的是根据之前构建好的 legend(标题列表,用于标识不同数据系列)、dataMap(存储了不同分类对应的数据值的复杂数据结构)等数据, + // 进一步完善用于柱状图展示的 x 轴、y 轴数据结构,将其组装成最终符合要求的格式,以便后续返回给客户端用于前端展示。 + + // 根据 legend 的大小,为 y 轴数据结构(yAxis,是一个 List> 类型,外层列表对应不同的数据系列,内层列表对应每个系列的数据值)添加相应数量的内层列表。 + // 每个内层列表将用于存储对应数据系列(由 legend 中的元素标识)在各个分类(x 轴分类,后续会填充)下的数据值。 for(int i =0; i()); } + + // 获取 dataMap 的键集合(keySet),这里的键通常对应着 x 轴上的分类标识(比如不同的日期、类型等,取决于业务逻辑),用于后续遍历填充 x 轴和相应的 y 轴数据。 Set keys = dataMap.keySet(); + // 遍历 dataMap 的键集合,对每个键(即每个 x 轴分类标识)进行处理,填充 x 轴和对应的 y 轴数据。 for(String key:keys){ + // 将当前键(分类标识)添加到 x 轴数据列表(xAxis)中,用于在柱状图的 x 轴上展示分类信息。 xAxis.add(key); + // 根据当前键从 dataMap 中获取对应的内层 HashMap,该 HashMap 存储了当前分类下不同数据系列(由 legend 标识)对应的数值信息(如果有的话)。 HashMap map = dataMap.get(key); + // 遍历 legend 列表,对于每个数据系列标识(也就是 legend 中的每个元素),进行以下操作,以填充对应的 y 轴数据列表(yAxis 中的内层列表)。 for(int i =0; i data = yAxis.get(i); - if(StringUtil.isNotEmpty(map.get(legend.get(i)))){ + // 判断当前分类下(由外层循环的 key 确定)对应的数据系列(由 legend.get(i) 确定)在 map 中是否有对应的值(即是否存在相应的数值信息), + // 如果有值,则将该值添加到对应的 y 轴数据列表中,表示该分类下该数据系列对应的数值情况。 + if (StringUtil.isNotEmpty(map.get(legend.get(i)))) { data.add(map.get(legend.get(i))); - }else{ + // 如果当前分类下对应的数据系列在 map 中没有值,说明该分类下该数据系列不存在具体数值,按照默认情况添加 "0" 到对应的 y 轴数据列表中, + // 以保证数据结构的完整性,便于前端在展示柱状图时进行统一处理(比如显示为数值为 0 的柱子等情况)。 + } else { data.add("0"); } } } + + // 输出一个空行,可能用于调试时在控制台区分不同部分的日志信息等情况(实际意义需结合具体调试场景判断),这里对整体逻辑影响不大。 System.out.println(); } + + // 创建一个新的 HashMap,用于将整理好的 x 轴、y 轴以及 legend 数据封装在一起,方便后续统一作为结果返回给客户端,符合一定的响应格式要求。 Map resultMap = new HashMap<>(); + // 将整理好的 x 轴数据列表(xAxis)添加到 resultMap 中,键为 "xAxis",方便客户端根据键获取相应的数据用于柱状图的 x 轴展示。 resultMap.put("xAxis",xAxis); + // 将整理好的 y 轴数据结构(yAxis)添加到 resultMap 中,键为 "yAxis",客户端可据此获取数据用于柱状图的 y 轴展示,展示不同分类下各数据系列对应的数值情况。 resultMap.put("yAxis",yAxis); + // 将整理好的 legend 数据列表(用于标识不同数据系列的标题列表)添加到 resultMap 中,键为 "legend",客户端可利用其在柱状图中展示相应的图例信息。 resultMap.put("legend",legend); + // 使用 R 类型对象(可能是项目自定义的用于统一响应格式的类,例如包含了响应状态码、消息以及具体数据等信息)来封装最终的结果数据, + // 以 "data" 作为键值对中的键,将包含了 x 轴、y 轴和 legend 数据的 resultMap 放入其中,然后将整个封装好的 R 对象返回给客户端, + // 通过 R.ok() 表示此次操作执行成功,客户端接收到返回结果后可根据约定的格式解析并获取相应的数据用于柱状图的展示。 return R.ok().put("data", resultMap); - } - - /** - * 柱状图统计 - */ - @RequestMapping("/barCount") - public R barCount(@RequestParam Map params) { - logger.debug("barCount方法:,,Controller:{},,params:{}",this.getClass().getName(), com.alibaba.fastjson.JSONObject.toJSONString(params)); - Boolean isJoinTableFlag = false;//是否有级联表相关 - String one = "";//第一优先 - String two = "";//第二优先 - - //处理thisTable和joinTable 处理内容是把json字符串转为Map并把带有,的切割为数组 - //当前表 + } + + + // 以下是另一个方法 barCount 的相关代码注释,该方法与前面的 barSum 方法在功能和部分处理逻辑上有相似之处,都是用于柱状图相关的数据处理及统计操作。 + + // 此方法用于进行柱状图相关的统计操作,接收一个包含各种参数的Map对象,这些参数用于确定统计的具体条件、涉及的数据表等信息。 + // 在方法内部会对参数进行一系列处理,包括解析JSON字符串为Map、对特定字段按逗号进行分割处理等,为后续的统计操作做准备。 + // @RequestMapping注解指定了访问此接口的请求路径为"/barCount",当客户端发起对应路径的请求时,该方法会被触发执行相应的业务逻辑。 + @RequestMapping("/barCount") + public R barCount(@RequestParam Map params) { + // 使用日志记录器记录DEBUG级别的日志信息,输出当前执行的方法名称(通过 this.getClass().getName() 获取类名)以及传入参数转换为JSON字符串后的内容, + // 方便在调试时查看方法的调用情况以及传入参数的具体情况,此处将参数转换为JSON字符串是为了更清晰完整地展示参数结构和内容。 + logger.debug("barCount方法:,,Controller:{},,params:{}",this.getClass().getName(),com.alibaba.fastjson.JSONObject.toJSONString(params)); + + // 定义一个布尔变量,用于标记是否存在级联表相关的情况,初始化为false,表示默认没有级联表相关操作。 + Boolean isJoinTableFlag = false;//是否有级联表相关 + // 定义一个字符串变量,用于记录第一优先处理的字段相关标识,初始化为空字符串,后续会根据具体情况赋值。 + String one = "";//第一优先 + // 定义一个字符串变量,用于记录第二优先处理的字段相关标识,初始化为空字符串,同样会根据具体情况进行赋值。 + String two = "";//第二优先 + + // 以下开始处理当前表(thisTable)和级联表(joinTable)相关的参数内容,主要操作是将JSON字符串形式的参数转换为Map类型,并对带有逗号的特定字段进行切割处理,转化为数组形式。 + + // 处理当前表(thisTable)相关参数。 + // 从传入的参数Map中获取名为 "thisTable" 的参数值(其原本为JSON字符串形式),将其转换为Map类型,以便后续方便操作其中的各个字段信息。 Map thisTable = JSON.parseObject(String.valueOf(params.get("thisTable")),Map.class); + // 将转换后的当前表相关的Map对象重新放回参数Map中,覆盖原来的JSON字符串形式,方便后续统一基于Map形式进行操作。 params.put("thisTable",thisTable); - //级联表 + // 处理级联表(joinTable)相关参数。 + // 从传入的参数Map中获取名为 "joinTable" 的参数值(其为JSON字符串形式),并转换为字符串类型进行后续判断处理。 String joinTableString = String.valueOf(params.get("joinTable")); + // 判断级联表的字符串表示是否不为空(即存在级联表相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(joinTableString)) { + // 将级联表的JSON字符串形式的参数转换为Map类型,以便后续操作其中的字段信息。 Map joinTable = JSON.parseObject(joinTableString, Map.class); + // 将转换后的级联表相关的Map对象重新放回参数Map中,覆盖原来的JSON字符串形式,便于后续统一处理。 params.put("joinTable", joinTable); + // 将表示存在级联表相关的标志变量置为true,用于后续其他逻辑判断,表明当前操作涉及级联表。 isJoinTableFlag = true; } + // 以下是根据当前表(thisTable)和级联表(joinTable)中不同字段的情况,对相关字段进行处理,并确定第一优先和第二优先处理的字段标识。 + + // 处理当前表日期字段(date)相关情况。 + // 判断当前表的 "date" 字段值是否不为空(即有日期相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(String.valueOf(thisTable.get("date")))){//当前表日期 + // 将当前表的 "date" 字段值(原本为字符串形式,可能包含逗号分隔的多个日期值)按逗号进行分割,转化为字符串数组形式, + // 以便后续在统计等操作中能更方便地处理多个日期相关的数据情况,然后将处理后的数组重新放回当前表的Map中,覆盖原来的字符串值。 thisTable.put("date",String.valueOf(thisTable.get("date")).split(",")); + // 将第一优先处理的字段标识设置为 "thisDate0",表示当前表日期字段在后续操作中可能具有第一优先级(具体优先级作用取决于整体业务逻辑)。 one = "thisDate0"; } + + // 处理级联表日期字段(date)相关情况,前提是存在级联表相关(即 isJoinTableFlag 为true)。 if(isJoinTableFlag){//级联表日期 + // 从参数Map中获取级联表对应的Map对象,方便后续操作其中的日期字段信息。 Map joinTable = (Map) params.get("joinTable"); + // 判断级联表的 "date" 字段值是否不为空(即有日期相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(String.valueOf(joinTable.get("date")))){ + // 将级联表的 "date" 字段值按逗号进行分割,转化为字符串数组形式,便于后续处理多个日期相关的数据情况, + // 然后将处理后的数组重新放回级联表的Map中,覆盖原来的字符串值。 joinTable.put("date",String.valueOf(joinTable.get("date")).split(",")); + // 判断第一优先处理的字段标识是否为空,如果为空,则表示当前级联表日期字段在这种情况下具有第一优先级,将其标识设置为 "joinDate0"。 if(StringUtil.isEmpty(one)){ one ="joinDate0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识是否为空, + // 如果为空,则表示当前级联表日期字段在这种情况下具有第二优先级,将其标识设置为 "joinDate0"。 }else{ if(StringUtil.isEmpty(two)){ two ="joinDate0"; @@ -584,22 +934,38 @@ public class CommonController{ } } } + // 处理当前表字符串字段(string)相关情况。 if(StringUtil.isNotEmpty(String.valueOf(thisTable.get("string")))){//当前表字符串 + // 将当前表的 "string" 字段值(原本为字符串形式,可能包含逗号分隔的多个字符串值)按逗号进行分割,转化为字符串数组形式, + // 方便后续在统计等操作中处理多个字符串相关的数据情况,然后将处理后的数组重新放回当前表的Map中,覆盖原来的字符串值。 thisTable.put("string",String.valueOf(thisTable.get("string")).split(",")); + // 判断第一优先处理的字段标识是否为空,如果为空,则表示当前表字符串字段在这种情况下具有第一优先级,将其标识设置为 "thisString0"。 if(StringUtil.isEmpty(one)){ one ="thisString0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识是否为空, + // 如果为空,则表示当前表字符串字段在这种情况下具有第二优先级,将其标识设置为 "thisString0"。 }else{ if(StringUtil.isEmpty(two)){ two ="thisString0"; } } } + if(isJoinTableFlag){//级联表字符串 + // 处理级联表(joinTable)字符串(string)字段相关情况,前提是存在级联表相关(即 isJoinTableFlag 为 true)。 + // 从参数Map中获取级联表对应的Map对象,方便后续操作其中的字符串字段信息。 Map joinTable = (Map) params.get("joinTable"); + // 判断级联表的 "string" 字段值是否不为空(即有字符串相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(String.valueOf(joinTable.get("string")))){ + + // 将级联表的 "string" 字段值(原本为字符串形式,可能包含逗号分隔的多个字符串值)按逗号进行分割,转化为字符串数组形式, + // 便于后续在柱状图相关操作(比如数据分类展示等)中能更好地处理多个字符串相关的数据情况,然后将处理后的数组重新放回级联表的Map中,覆盖原来的字符串值。 joinTable.put("string",String.valueOf(joinTable.get("string")).split(",")); + // 判断第一优先处理的字段标识(one)是否为空,如果为空,则表示当前级联表字符串字段在这种情况下具有第一优先级,将其标识设置为 "joinString0"。 if(StringUtil.isEmpty(one)){ one ="joinString0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识(two)是否为空, + // 如果为空,则表示当前级联表字符串字段在这种情况下具有第二优先级,将其标识设置为 "joinString0"。 }else{ if(StringUtil.isEmpty(two)){ two ="joinString0"; @@ -607,22 +973,38 @@ public class CommonController{ } } } + +// 处理当前表(thisTable)类型(types)字段相关情况。 if(StringUtil.isNotEmpty(String.valueOf(thisTable.get("types")))){//当前表类型 + // 将当前表的 "types" 字段值(原本为字符串形式,可能包含逗号分隔的多个类型值)按逗号进行分割,转化为字符串数组形式, + // 方便后续在柱状图相关操作(比如数据分类展示等)中能更好地处理多个类型相关的数据情况,然后将处理后的数组重新放回当前表的Map中,覆盖原来的字符串值。 thisTable.put("types",String.valueOf(thisTable.get("types")).split(",")); + // 判断第一优先处理的字段标识(one)是否为空,如果为空,则表示当前表类型字段在这种情况下具有第一优先级,将其标识设置为 "thisTypes0"。 if(StringUtil.isEmpty(one)){ one ="thisTypes0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识(two)是否为空, + // 如果为空,则表示当前表类型字段在这种情况下具有第二优先级,将其标识设置为 "thisTypes0"。 }else{ if(StringUtil.isEmpty(two)){ two ="thisTypes0"; } } } + +// 处理级联表(joinTable)类型(types)字段相关情况,前提是存在级联表相关(即 isJoinTableFlag 为 true)。 if(isJoinTableFlag){//级联表类型 + // 从参数Map中获取级联表对应的Map对象,方便后续操作其中的类型字段信息。 Map joinTable = (Map) params.get("joinTable"); + // 判断级联表的 "types" 字段值是否不为空(即有类型相关参数传入),如果是,则进行以下处理。 if(StringUtil.isNotEmpty(String.valueOf(joinTable.get("types")))){ + // 将级联表的 "types" 字段值按逗号进行分割,转化为字符串数组形式,便于后续处理多个类型相关的数据情况, + // 然后将处理后的数组重新放回级联表的Map中,覆盖原来的字符串值。 joinTable.put("types",String.valueOf(joinTable.get("types")).split(",")); + // 判断第一优先处理的字段标识(one)是否为空,如果为空,则表示当前级联表类型字段在这种情况下具有第一优先级,将其标识设置为 "joinTypes0"。 if(StringUtil.isEmpty(one)){ one ="joinTypes0"; + // 如果第一优先处理的字段标识已经有值了,说明之前已经确定了其他更优先的字段,此时判断第二优先处理的字段标识(two)是否为空, + // 如果为空,则表示当前级联表类型字段在这种情况下具有第二优先级,将其标识设置为 "joinTypes0"。 }else{ if(StringUtil.isEmpty(two)){ two ="joinTypes0"; @@ -632,67 +1014,129 @@ public class CommonController{ } } + // 调用 commonService(假设是已经注入并正确实现了对应业务逻辑的服务类)的 barCount 方法,传递处理好的包含各种参数的Map对象, + // 获取柱状图统计相关的结果数据,返回的数据类型是一个包含多个Map的List集合,每个内层的Map可能对应一组统计相关的结果信息,具体取决于业务逻辑的设计。 List> result = commonService.barCount(params); + // 创建一个用于存储报表 x 轴数据的 ArrayList,后续会将相应的数据添加到该列表中,用于在柱状图中展示 x 轴相关内容(比如分类名称等)。 List xAxis = new ArrayList<>();//报表x轴 + // 创建一个用于存储报表 y 轴数据的 ArrayList,由于 y 轴数据可能有多层结构(比如不同分组下对应不同的数据值等情况),所以这里的元素类型也是ArrayList, + // 后续会根据具体情况构建并添加相应的数据,用于在柱状图中展示 y 轴相关内容(比如不同分类对应的数值等)。 List> yAxis = new ArrayList<>();//y轴 + // 创建一个用于存储报表标题(legend,通常在图表中用于标识不同数据系列的名称)的 ArrayList,后续会将相应的标题名称添加到该列表中,用于在柱状图中展示图例相关内容。 List legend = new ArrayList<>();//标题 +// 判断第二优先处理的字段标识(two)是否为空,以此来区分数据是否包含第二列相关情况,进而采用不同的逻辑来处理结果数据并构建用于柱状图展示的数据结构。 + +// 如果不包含第二列(即 two 为空),表示数据结构相对简单,只有单一维度的数据情况,进行以下处理。 if(StringUtil.isEmpty(two)){//不包含第二列 + // 创建一个用于存储 y 轴单层数据的 ArrayList,后续会将具体的数据值添加到该列表中,作为 y 轴数据的唯一一层数据。 List yAxis0 = new ArrayList<>(); + // 将刚创建的 y 轴单层数据列表添加到 y 轴数据的外层列表中,构建出符合柱状图数据展示要求的 y 轴数据结构(这里只有一层数据情况)。 yAxis.add(yAxis0); + // 添加一个默认的标题名称 "数值" 到 legend 列表中,用于在柱状图中作为唯一的数据系列的图例标识,表示展示的是数值相关的数据。 legend.add("数值"); + // 遍历获取到的柱状图统计结果数据列表(result),对每个结果 Map 进行处理,提取相应的数据添加到 x 轴和 y 轴数据列表中。 for(Map map :result){ + // 获取第一优先处理的字段对应的值,并转换为字符串类型,该值将作为 x 轴上的分类标识等信息添加到 x 轴数据列表中。 String oneValue = String.valueOf(map.get(one)); + // 获取名为 "value" 的字段对应的值(推测是统计得到的数值,具体取决于业务逻辑),并转换为字符串类型,该值将作为 y 轴上对应分类的数值添加到 y 轴数据列表中。 String value = String.valueOf(map.get("value")); + // 将第一优先处理的字段对应的值添加到 x 轴数据列表中,用于在柱状图的 x 轴上展示分类相关信息。 xAxis.add(oneValue); + // 将统计得到的数值添加到 y 轴的单层数据列表中,用于在柱状图的 y 轴上展示对应分类的数值情况。 yAxis0.add(value); } +// 如果包含第二列(即 two 不为空),表示数据结构相对复杂,存在多层维度的数据情况,进行以下处理。 }else{//包含第二列 + // 创建一个 LinkedHashMap,用于存储更复杂的数据结构,键为第一优先处理的字段对应的值(通常是一种分类标识), + // 值为 HashMap,内层的 HashMap 键为第二优先处理的字段对应的值(另一种分类标识),值为具体的数值(比如统计得到的数值等), + // 通过这种结构可以方便地对具有两层分类的数据进行整理和后续在柱状图中的展示。 Map> dataMap = new LinkedHashMap<>(); + // 判断第二优先处理的字段标识(two)是否不为空(这里其实已经在前面判断过了,只是再次确认一下逻辑完整性),如果是,则进行以下循环处理。 if(StringUtil.isNotEmpty(two)){ + // 遍历获取到的柱状图统计结果数据列表(result),对每个结果 Map 进行处理,提取相应的数据填充到 dataMap 中,构建复杂的数据结构。 for(Map map :result){ + // 获取第一优先处理的字段对应的值,并转换为字符串类型,作为外层 dataMap 的键(一种分类标识)。 String oneValue = String.valueOf(map.get(one)); + // 获取第二优先处理的字段对应的值,并转换为字符串类型,作为内层 HashMap 的键(另一种分类标识)。 String twoValue = String.valueOf(map.get(two)); + // 获取名为 "value" 的字段对应的值(推测是统计得到的数值,具体取决于业务逻辑),并转换为字符串类型,作为内层 HashMap 的值(具体的数值)。 String value = String.valueOf(map.get("value")); + // 判断 legend 列表中是否已经包含了当前的第二优先处理的字段对应的值(即判断是否已经添加过该分类标识作为图例名称), + // 如果不包含,则将其添加到 legend 列表中,用于在柱状图中作为不同数据系列的图例标识,确保图例包含了所有的分类情况。 if(!legend.contains(twoValue)){ - legend.add(twoValue);//添加完成后 就是最全的第二列的类型 + legend.add(twoValue);//添加完成后 就是最全的第二列的类型 } + // 判断 dataMap 中是否已经包含了当前的第一优先处理的字段对应的值(即判断是否已经有该外层分类标识对应的内层数据结构),如果包含,说明之前已经处理过同类型的外层分类,进行以下操作。 if(dataMap.containsKey(oneValue)){ + // 获取已经存在的对应外层分类标识下的内层 HashMap,然后将当前的第二优先处理的字段对应的值和数值添加到该内层 HashMap 中, + // 用于更新或补充该外层分类下不同内层分类对应的数值情况。 dataMap.get(oneValue).put(twoValue,value); + // 如果 dataMap 中不包含当前的第一优先处理的字段对应的值,说明是新的外层分类情况,进行以下操作。 }else{ + // 创建一个新的内层 HashMap,用于存储当前外层分类下不同内层分类对应的数值情况。 HashMap oneData = new HashMap<>(); + // 将当前的第二优先处理的字段对应的值和数值添加到新创建的内层 HashMap 中。 oneData.put(twoValue,value); + // 将新创建的内层 HashMap 作为值,以当前的第一优先处理的字段对应的值作为键,添加到 dataMap 中,构建出完整的两层分类数据结构。 dataMap.put(oneValue,oneData); } } } + // 以下代码是基于前面已经构建好的 legend(图例相关数据列表)、dataMap(存储特定数据结构的映射表)等数据, + // 进一步完善用于柱状图展示的 x 轴(xAxis)和 y 轴(yAxis)数据结构,使其符合最终在前端展示柱状图的要求。 + + // 根据 legend 列表的大小,为 y 轴数据结构(yAxis,是一个 List> 类型,外层列表对应不同的数据系列,内层列表对应每个系列的数据值)添加相应数量的内层列表。 + // 每个内层列表将用于存储对应数据系列(由 legend 中的元素标识)在各个分类(x 轴分类,后续会填充)下的数据值,以此构建出 y 轴多层结构的初始框架。 for(int i =0; i()); } + // 获取 dataMap 的键集合(keySet),这里的键通常对应着 x 轴上的分类标识(比如不同的日期、类型等,取决于业务逻辑), + // 后续将通过遍历这些键来填充 x 轴数据列表(xAxis)以及对应的 y 轴各内层列表数据。 Set keys = dataMap.keySet(); + + // 遍历 dataMap 的键集合,对每个键(即每个 x 轴分类标识)进行处理,填充 x 轴和对应的 y 轴数据,以构建完整的柱状图展示数据结构。 for(String key:keys){ + // 将当前键(分类标识)添加到 x 轴数据列表(xAxis)中,用于在柱状图的 x 轴上展示分类信息,使 x 轴能体现出不同的分类情况。 xAxis.add(key); + + // 根据当前键从 dataMap 中获取对应的内层 HashMap,该 HashMap 存储了当前分类下不同数据系列(由 legend 标识)对应的数值信息(如果有的话), + // 后续将依据这个 HashMap 来填充 y 轴对应的数据。 HashMap map = dataMap.get(key); + + // 遍历 legend 列表,对于每个数据系列标识(也就是 legend 中的每个元素),进行以下操作,以填充对应的 y 轴数据列表(yAxis 中的内层列表)。 + // 这样就能确保每个数据系列在每个 x 轴分类下都有对应的数据值(若不存在实际值则按默认情况处理)。 for(int i =0; i data = yAxis.get(i); + + // 判断当前分类下(由外层循环的 key 确定)对应的数据系列(由 legend.get(i) 确定)在 map 中是否有对应的值(即是否存在相应的数值信息), + // 如果有值,则将该值添加到对应的 y 轴数据列表中,表示该分类下该数据系列对应的数值情况,用于在柱状图中准确展示相应数据。 if(StringUtil.isNotEmpty(map.get(legend.get(i)))){ data.add(map.get(legend.get(i))); + // 如果当前分类下对应的数据系列在 map 中没有值,说明该分类下该数据系列不存在具体数值,按照默认情况添加 "0" 到对应的 y 轴数据列表中, + // 这样可以保证数据结构的完整性,便于前端在展示柱状图时进行统一处理(比如显示为数值为 0 的柱子等情况)。 }else{ data.add("0"); } } } + + // 输出一个空行,可能用于调试时在控制台区分不同部分的日志信息等情况(实际意义需结合具体调试场景判断),这里对整体逻辑影响不大。 System.out.println(); } + // 创建一个HashMap用于封装整理好的x轴、y轴以及legend数据,方便后续统一作为结果返回给客户端。 Map resultMap = new HashMap<>(); resultMap.put("xAxis",xAxis); resultMap.put("yAxis",yAxis); resultMap.put("legend",legend); + // 使用R类型对象封装最终结果数据,以"data"为键值对中的键,将包含相关数据的resultMap放入其中,返回成功响应给客户端。 return R.ok().put("data", resultMap); } }