diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/agentcenter/AgentTaskController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/agentcenter/AgentTaskController.java new file mode 100644 index 0000000..66342ed --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/agentcenter/AgentTaskController.java @@ -0,0 +1,50 @@ +package com.ruoyi.web.controller.agentcenter; + +import java.util.List; +import javax.servlet.http.HttpServletResponse; + +import com.ruoyi.common.utils.DateUtils; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.agentcenter.domain.TAgentTask; +import com.ruoyi.agentcenter.service.ITAgentTaskService; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.common.core.page.TableDataInfo; + +/** + * 任务清单Controller + * + * @author zhao + * @date 2023-05-06 + */ +@RestController +@RequestMapping("/agentcenter/task") +public class AgentTaskController extends BaseController +{ + @Autowired + private ITAgentTaskService tAgentTaskService; + + /** + * 获取任务清单列表(按镇村分组) + */ + @PreAuthorize("@ss.hasPermi('agentcenter:task:list')") + @GetMapping(value = "/taskList") + public TableDataInfo taskList(TAgentTask task) + { + startPage(); + task.setEndAt(DateUtils.getDate()); + return getDataTable(tAgentTaskService.getTownTaskList(task)); + } +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/agentcenter/TAgentTaskController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/agentcenter/TAgentTaskController.java deleted file mode 100644 index 0ea4cc9..0000000 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/agentcenter/TAgentTaskController.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.ruoyi.web.controller.agentcenter; - -import java.util.List; -import javax.servlet.http.HttpServletResponse; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.ruoyi.common.annotation.Log; -import com.ruoyi.common.core.controller.BaseController; -import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.enums.BusinessType; -import com.ruoyi.agentcenter.domain.TAgentTask; -import com.ruoyi.agentcenter.service.ITAgentTaskService; -import com.ruoyi.common.utils.poi.ExcelUtil; -import com.ruoyi.common.core.page.TableDataInfo; - -/** - * 任务清单Controller - * - * @author zhao - * @date 2023-05-06 - */ -@RestController -@RequestMapping("/agentcenter/task") -public class TAgentTaskController extends BaseController -{ - @Autowired - private ITAgentTaskService tAgentTaskService; - - /** - * 查询任务清单列表 - */ - @PreAuthorize("@ss.hasPermi('agentcenter:task:list')") - @GetMapping("/list") - public TableDataInfo list(TAgentTask tAgentTask) - { - startPage(); - List list = tAgentTaskService.selectTAgentTaskList(tAgentTask); - return getDataTable(list); - } - - /** - * 导出任务清单列表 - */ - @PreAuthorize("@ss.hasPermi('agentcenter:task:export')") - @Log(title = "任务清单", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, TAgentTask tAgentTask) - { - List list = tAgentTaskService.selectTAgentTaskList(tAgentTask); - ExcelUtil util = new ExcelUtil(TAgentTask.class); - util.exportExcel(response, list, "任务清单数据"); - } - - /** - * 获取任务清单详细信息 - */ - @PreAuthorize("@ss.hasPermi('agentcenter:task:query')") - @GetMapping(value = "/get/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) - { - return success(tAgentTaskService.selectTAgentTaskById(id)); - } - - /** - * 新增任务清单 - */ - @PreAuthorize("@ss.hasPermi('agentcenter:task:add')") - @Log(title = "任务清单", businessType = BusinessType.INSERT) - @PostMapping(value = "/add") - public AjaxResult add(@RequestBody TAgentTask tAgentTask) - { - tAgentTask.setCreateBy(getUsername()); - return toAjax(tAgentTaskService.insertTAgentTask(tAgentTask)); - } - - /** - * 修改任务清单 - */ - @PreAuthorize("@ss.hasPermi('agentcenter:task:edit')") - @Log(title = "任务清单", businessType = BusinessType.UPDATE) - @PutMapping(value = "/edit") - public AjaxResult edit(@RequestBody TAgentTask tAgentTask) - { - tAgentTask.setUpdateBy(getUsername()); - return toAjax(tAgentTaskService.updateTAgentTask(tAgentTask)); - } - - /** - * 删除任务清单 - */ - @PreAuthorize("@ss.hasPermi('agentcenter:task:remove')") - @Log(title = "任务清单", businessType = BusinessType.DELETE) - @DeleteMapping(value = "/remove/{id}") - public AjaxResult remove(@PathVariable Long id) - { - return toAjax(tAgentTaskService.deleteTAgentTaskById(id)); - } -} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/agentcenter/AgentCenterController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AgentCenterController.java similarity index 97% rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/agentcenter/AgentCenterController.java rename to ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AgentCenterController.java index 307b0cb..c5bc3a7 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/agentcenter/AgentCenterController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/api/AgentCenterController.java @@ -1,12 +1,12 @@ -package com.ruoyi.web.controller.agentcenter; +package com.ruoyi.web.controller.api; import com.nsgk.agentcentersdk.api.NSApiResult; import com.nsgk.agentcentersdk.api.NSSDK; import com.nsgk.agentcentersdk.api.NSSDKServer; import com.nsgk.agentcentersdk.core.NSReportObject; -import com.nsgk.agentcentersdk.message.NSContractionMessage; import com.nsgk.agentcentersdk.err.NSErrno; import com.nsgk.agentcentersdk.err.NSException; +import com.nsgk.agentcentersdk.message.NSContractionMessage; import com.ruoyi.agentcenter.object.Session; import com.ruoyi.agentcenter.service.IAgentCenter; import com.ruoyi.common.config.RuoYiConfig; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/misc/DeptController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/misc/DeptController.java new file mode 100644 index 0000000..88e3443 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/misc/DeptController.java @@ -0,0 +1,45 @@ +package com.ruoyi.web.controller.misc; + +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.domain.entity.SysDept; +import com.ruoyi.system.service.ISysDeptService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * 杂项::部门 + * + * @author zhao + */ +@RestController +@RequestMapping("/misc/dept") +public class DeptController extends BaseController +{ + @Autowired + private ISysDeptService deptService; + + /** + * 获取部门树 + */ + @GetMapping("/tree") + public AjaxResult list(SysDept dept) + { + return success(deptService.getDeptTree(dept)); + } + + /** + * 获取市级树 + */ + @GetMapping("/cityTree") + public AjaxResult cityTree(SysDept dept) + { + return success(deptService.getCityTree(dept)); + } + +} diff --git a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/domain/TAgentTask.java b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/domain/TAgentTask.java index 06ac46b..09fcd02 100644 --- a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/domain/TAgentTask.java +++ b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/domain/TAgentTask.java @@ -30,7 +30,7 @@ public class TAgentTask extends BaseEntity private Long id; /** 所属中心 字典 agent_center */ - @Excel(name = "所属中心 字典 agent_center") + @Excel(name = "所属中心", dictType = "agent_center") private String agentCenter; /** 县代码 */ @@ -94,15 +94,15 @@ public class TAgentTask extends BaseEntity private Integer finishCount; /** 任务状态 字典 agent_status */ - @Excel(name = "任务状态 字典 agent_status") + @Excel(name = "任务状态", dictType = "agent_status") private String agentStatus; /** 分配用户(用user_name) */ - @Excel(name = "分配用户(用user_name)") + @Excel(name = "分配用户") private String distriUser; /** 分配人(用nick_name) */ - @Excel(name = "分配人(用nick_name)") + @Excel(name = "分配人") private String distriNick; /** 分配时间 */ @@ -115,11 +115,11 @@ public class TAgentTask extends BaseEntity private String endAt; /** 记账用户(用user_name) */ - @Excel(name = "记账用户(用user_name)") + @Excel(name = "记账用户") private String handleUser; /** 记账会计(用nick_name) */ - @Excel(name = "记账会计(用nick_name)") + @Excel(name = "记账会计") private String handleNick; /** 记账备注 */ @@ -132,11 +132,11 @@ public class TAgentTask extends BaseEntity private Date handleDate; /** 审核用户(用user_name) */ - @Excel(name = "审核用户(用user_name)") + @Excel(name = "审核用户") private String auditUser; /** 审核人(用nick_name) */ - @Excel(name = "审核人(用nick_name)") + @Excel(name = "审核人") private String auditNick; /** 审核时间 */ @@ -145,11 +145,11 @@ public class TAgentTask extends BaseEntity private Date auditDate; /** 评价用户(用user_name) */ - @Excel(name = "评价用户(用user_name)") + @Excel(name = "评价用户") private String appraiseUser; /** 评价人(用nick_name) */ - @Excel(name = "评价人(用nick_name)") + @Excel(name = "评价人") private String appraiseNick; /** 任务评分 */ @@ -160,5 +160,12 @@ public class TAgentTask extends BaseEntity @Excel(name = "评价备注") private String appraiseRemark; + /** 是否审核 */ + @Excel(name = "是否审核", dictType = "sys_yes_no") + private String isAudit; + + /** 是否评价 */ + @Excel(name = "是否评价", dictType = "sys_yes_no") + private String isAppraise; } diff --git a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/mapper/TAgentTaskMapper.java b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/mapper/TAgentTaskMapper.java index fcb6cef..d040f89 100644 --- a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/mapper/TAgentTaskMapper.java +++ b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/mapper/TAgentTaskMapper.java @@ -2,6 +2,8 @@ package com.ruoyi.agentcenter.mapper; import java.util.List; import com.ruoyi.agentcenter.domain.TAgentTask; +import com.ruoyi.agentcenter.vo.AgentTaskTownGroup; +import com.ruoyi.agentcenter.vo.AgentTaskVillageGroup; /** * 任务清单Mapper接口 @@ -101,4 +103,7 @@ public interface TAgentTaskMapper public int selectTAgentTaskExists(TAgentTask tAgentTask); public int updateTAgentTaskCount(TAgentTask tAgentTask); + + public List getAgentTaskGroupByTown(TAgentTask tAgentTask); + public List getAgentTaskGroupByVillage(TAgentTask tAgentTask); } diff --git a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/service/ITAgentTaskService.java b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/service/ITAgentTaskService.java index 4943a88..5ec9ffb 100644 --- a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/service/ITAgentTaskService.java +++ b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/service/ITAgentTaskService.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.function.Consumer; import com.ruoyi.agentcenter.domain.TAgentTask; +import com.ruoyi.agentcenter.vo.AgentTaskTownGroup; /** * 任务清单Service接口 @@ -111,4 +112,6 @@ public interface ITAgentTaskService public TAgentTask getTAgentTask(String orgCode, String year, String month); public int syncTAgentTaskCount(TAgentTask tAgentTask); + + public List getTownTaskList(TAgentTask tAgentTask); } diff --git a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/service/impl/TAgentTaskServiceImpl.java b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/service/impl/TAgentTaskServiceImpl.java index 859cb35..77e24a0 100644 --- a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/service/impl/TAgentTaskServiceImpl.java +++ b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/service/impl/TAgentTaskServiceImpl.java @@ -1,10 +1,16 @@ package com.ruoyi.agentcenter.service.impl; +import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.function.Consumer; +import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; +import com.ruoyi.agentcenter.vo.AgentTaskTownGroup; +import com.ruoyi.agentcenter.vo.AgentTaskVillageGroup; import com.ruoyi.common.core.domain.entity.SysDept; +import com.ruoyi.common.utils.ContainerUtils; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DeptUtils; import com.ruoyi.system.mapper.SysDeptMapper; @@ -273,4 +279,32 @@ public class TAgentTaskServiceImpl implements ITAgentTaskService ; return updateTAgentTaskCount(updateTask); } + + @Override + public List getTownTaskList(TAgentTask tAgentTask) + { + List agentTaskGroupByTown = tAgentTaskMapper.getAgentTaskGroupByTown(tAgentTask); + if(CollectionUtil.isNotEmpty(agentTaskGroupByTown)) + { + List townCodeList = ContainerUtils.mapToList(agentTaskGroupByTown, AgentTaskTownGroup::getTownCode); + + List villageGroups = tAgentTaskMapper.getAgentTaskGroupByVillage(new TAgentTask().putParam("townCodeList", townCodeList)); + Map> villageMap = ContainerUtils.groupingBy(villageGroups, AgentTaskVillageGroup::getTownCode); + + List orgCodeList = ContainerUtils.mapToList(villageGroups, AgentTaskVillageGroup::getOrgCode); + + TAgentTask agentTaskCond = new TAgentTask(); + agentTaskCond.putParam("orgCodeList", orgCodeList); + List tAgentTasks = tAgentTaskMapper.selectTAgentTaskList(agentTaskCond); + Map> bookGroup = ContainerUtils.groupingBy(tAgentTasks, TAgentTask::getOrgCode); + + agentTaskGroupByTown.forEach((town) -> { + town.setVillageList(villageMap.getOrDefault(town.getTownCode(), new ArrayList<>())); + town.getVillageList().forEach((village) -> { + village.setTaskList(bookGroup.getOrDefault(village.getOrgCode(), new ArrayList<>())); + }); + }); + } + return agentTaskGroupByTown; + } } diff --git a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/vo/AgentTaskTownGroup.java b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/vo/AgentTaskTownGroup.java new file mode 100644 index 0000000..e57535b --- /dev/null +++ b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/vo/AgentTaskTownGroup.java @@ -0,0 +1,22 @@ +package com.ruoyi.agentcenter.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.List; + +@Data +@Accessors(chain = true) +public class AgentTaskTownGroup +{ + private Long num; + private Long numProcessFinish; + private Long numApprovalFinish; + private Long numExcept; + private String townName; + private String townCode; + private String orderYear; + private String orderMonth; + + private List villageList; +} diff --git a/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/vo/AgentTaskVillageGroup.java b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/vo/AgentTaskVillageGroup.java new file mode 100644 index 0000000..036af46 --- /dev/null +++ b/ruoyi-agentcenter/src/main/java/com/ruoyi/agentcenter/vo/AgentTaskVillageGroup.java @@ -0,0 +1,30 @@ +package com.ruoyi.agentcenter.vo; + +import com.ruoyi.agentcenter.domain.TAgentTask; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Date; +import java.util.List; + +@Data +@Accessors(chain = true) +public class AgentTaskVillageGroup +{ + private Long num; + private Long numProcessFinish; + private Long numApprovalFinish; + private Long numExcept; + private String townCode; + + private String orgName; + private String orgCode; + private Long bookId; + private String bookName; + private Date distriDate; + private Date handleDate; + private String endAt; + private String handleNick; + + private List taskList; +} diff --git a/ruoyi-agentcenter/src/main/resources/mapper/agentcenter/TAgentTaskMapper.xml b/ruoyi-agentcenter/src/main/resources/mapper/agentcenter/TAgentTaskMapper.xml index cf80301..3997d13 100644 --- a/ruoyi-agentcenter/src/main/resources/mapper/agentcenter/TAgentTaskMapper.xml +++ b/ruoyi-agentcenter/src/main/resources/mapper/agentcenter/TAgentTaskMapper.xml @@ -1,9 +1,9 @@ + PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> - + @@ -34,10 +34,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + @@ -45,13 +47,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, agent_center, county_code, county_name, town_code, town_name, org_code, org_name, book_id, book_name, order_year, order_month, voucher_count, contrac_count, asset_count, all_count, finish_count, agent_status, distri_user, distri_nick, distri_date, end_at, handle_user, handle_nick, handle_remark, handle_date, audit_user, audit_nick, audit_date, appraise_user, appraise_nick, appraise_score, appraise_remark, create_by, create_time, update_by, update_time from t_agent_task + select id, agent_center, county_code, county_name, town_code, town_name, org_code, org_name, book_id, book_name, order_year, order_month, voucher_count, contrac_count, asset_count, all_count, finish_count, agent_status, distri_user, distri_nick, distri_date, end_at, handle_user, handle_nick, handle_remark, handle_date, audit_user, audit_nick, audit_date, is_audit, appraise_user, appraise_nick, appraise_score, appraise_remark, is_appraise, create_by, create_time, update_by, update_time from t_agent_task - - - + - - + insert into t_agent_task @@ -125,15 +131,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" audit_user, audit_nick, audit_date, + is_audit, appraise_user, appraise_nick, appraise_score, appraise_remark, + is_appraise, create_by, create_time, update_by, update_time, - + #{agentCenter}, #{countyCode}, @@ -163,15 +171,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{auditUser}, #{auditNick}, #{auditDate}, + #{isAudit}, #{appraiseUser}, #{appraiseNick}, #{appraiseScore}, #{appraiseRemark}, + #{isAppraise}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, - + @@ -206,10 +216,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" audit_user, audit_nick, audit_date, + is_audit, appraise_user, appraise_nick, appraise_score, appraise_remark, + is_appraise, create_by, create_time, update_by, @@ -246,10 +258,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{item.auditUser}, #{item.auditNick}, #{item.auditDate}, + #{item.isAudit}, #{item.appraiseUser}, #{item.appraiseNick}, #{item.appraiseScore}, #{item.appraiseRemark}, + #{item.isAppraise}, #{item.createBy}, #{item.createTime}, #{item.updateBy}, @@ -258,7 +272,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - update t_agent_task @@ -290,15 +303,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" audit_user = #{auditUser}, audit_nick = #{auditNick}, audit_date = #{auditDate}, + is_audit = #{isAudit}, appraise_user = #{appraiseUser}, appraise_nick = #{appraiseNick}, appraise_score = #{appraiseScore}, appraise_remark = #{appraiseRemark}, + is_appraise = #{isAppraise}, create_by = #{createBy}, create_time = #{createTime}, update_by = #{updateBy}, update_time = #{updateTime}, - `${col}` = #{val}, where id = #{id} @@ -336,34 +350,32 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" audit_user = #{item.auditUser}, audit_nick = #{item.auditNick}, audit_date = #{item.auditDate}, + is_audit = #{item.isAudit}, appraise_user = #{item.appraiseUser}, appraise_nick = #{item.appraiseNick}, appraise_score = #{item.appraiseScore}, appraise_remark = #{item.appraiseRemark}, + is_appraise = #{item.isAppraise}, create_by = #{item.createBy}, create_time = #{item.createTime}, update_by = #{item.updateBy}, update_time = #{item.updateTime}, - `${col}` = #{val}, where id = #{item.id} - delete from t_agent_task where id = #{id} - - delete from t_agent_task where id in + delete from t_agent_task where id in #{id} - + SELECT + COUNT(*) as num, + IFNULL(SUM(IF(agent_status = '3', 1, 0)), 0) as num_process_finish, + IFNULL(SUM(IF(is_audit = 'Y', 1, 0)), 0) as num_approval_finish, + IFNULL(SUM(IF(agent_status != '3' AND end_at < #{endAt}, 1, 0)), 0) as num_except, + town_name, town_code, + order_year, order_month + FROM + t_agent_task + + and agent_center = #{agentCenter} + and county_code = #{countyCode} + and order_year = #{orderYear} + and order_month = #{orderMonth} + + GROUP BY town_code + ORDER BY town_code + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java index 15bf66b..86eacc4 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java @@ -7,6 +7,7 @@ import java.util.Map; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; +import com.ruoyi.common.utils.translation.TranslateUtils; /** * Entity基类 @@ -115,4 +116,76 @@ public class BaseEntity implements Serializable { this.params = params; } + /* + * keepRawField为true, 保存原值到params + * */ + public void translate(boolean... keepRawField) { + boolean b = null != keepRawField && keepRawField.length > 0 && keepRawField[0]; + TranslateUtils.translateEntity(this, b); + } + + @SuppressWarnings("unchecked") + public T putParam(String name, Object value) { + getParams().put(name, value); + return (T) this; + } + + @SuppressWarnings("unchecked") + public T putParams(Object... args) { + for (int i = 0; i < args.length; i += 2) { + String name = (String) args[i]; + Object value = args[i + 1]; + getParams().put(name, value); + } + return (T) this; + } + + @SuppressWarnings("unchecked") + public T removeParam(String... name) { + if (params != null && null != name && name.length > 0) { + for (String s : name) { + params.remove(s); + } + } + return (T) this; + } + + @SuppressWarnings("unchecked") + public T removeParams() { + if (params != null) + params.clear(); + return (T) this; + } + + public Object obtainParam(String name) { + if (params == null) + return null; + return params.get(name); + } + + public Object obtainParam(String name, Object defValue) { + if (params == null) + return defValue; + return params.getOrDefault(name, defValue); + } + + @SuppressWarnings("unchecked") + public T obtainParamT(String name) { + if (params == null) + return null; + return (T) params.get(name); + } + + @SuppressWarnings("unchecked") + public T obtainParamT(String name, T defValue) { + if (params == null) + return defValue; + return (T) params.getOrDefault(name, defValue); + } + + public boolean containsParam(String name) { + if (params == null) + return false; + return params.containsKey(name); + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java index 0d0e06a..c02826c 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java @@ -24,6 +24,8 @@ public class SysDept extends BaseEntity { private static final long serialVersionUID = 1L; + public static final long ROOT_DEPT_ID = 100; + /** 部门ID */ private Long deptId; @@ -69,6 +71,10 @@ public class SysDept extends BaseEntity /** 账套数 */ private Integer bookCount; + // 级联递归查询 + private Long rootId; + private Integer orgCodeLength; + public String getRemoteUrl() { return remoteUrl; @@ -275,4 +281,24 @@ public class SysDept extends BaseEntity return 0; return orgCode.length(); } + + public Long getRootId() + { + return rootId; + } + + public void setRootId(Long rootId) + { + this.rootId = rootId; + } + + public Integer getOrgCodeLength() + { + return orgCodeLength; + } + + public void setOrgCodeLength(Integer orgCodeLength) + { + this.orgCodeLength = orgCodeLength; + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ContainerUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ContainerUtils.java new file mode 100644 index 0000000..14a73b1 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ContainerUtils.java @@ -0,0 +1,240 @@ +package com.ruoyi.common.utils; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.NumberUtil; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public final class ContainerUtils +{ + public static List unique(Function getIdFunc, Collection...args) + { + List list = new ArrayList<>(); + Arrays.stream(args).filter(CollectionUtil::isNotEmpty).forEach(list::addAll); + return unique(list, getIdFunc); + } + + public static List unique_override(Function getIdFunc, Collection...args) + { + List list = new ArrayList<>(); + Arrays.stream(args).filter(CollectionUtil::isNotEmpty).forEach(list::addAll); + return unique_override(list, getIdFunc); + } + + // keep + public static List unique(Collection collection, Function getIdFunc) + { + return new ArrayList<>(collection.stream().collect(Collectors.toMap(getIdFunc, x -> x, (a, b) -> a, LinkedHashMap::new)).values()); + } + + public static List unique_override(Collection collection, Function getIdFunc) + { + return new ArrayList<>(collection.stream().collect(Collectors.toMap(getIdFunc, x -> x, (a, b) -> b, LinkedHashMap::new)).values()); + } + + public static List mapToList(Collection collection, Function mapFunc, boolean...unique) + { + Stream rStream = collection.stream().map(mapFunc); + if(null != unique && unique.length > 0 && ConvertUtils.FALSE(unique[0])) + rStream = rStream.distinct(); + return rStream.collect(Collectors.toList()); + } + + public static List subList(List list, int start, Integer...end) + { + int num = list.size(); + if(num == 0) + return new ArrayList<>(); + if(start < 0) + start = num + start; + if(start < 0 || start >= num) + return new ArrayList<>(); + int e = list.size(); + if(null != end && end.length > 0) + e = end[0]; + if(e < 0) + e = list.size() + e; + if(e < 0 || e > num) + return new ArrayList<>(); + return list.subList(start, e); + } + + public static List filterToList(Collection collection, Predicate filterFunc) + { + return collection.stream().filter(filterFunc).collect(Collectors.toList()); + } + + public static List mapToUniqueList(Collection collection, Function mapFunc) + { + return collection.stream().map(mapFunc).distinct().collect(Collectors.toList()); + } + + public static Map> groupingBy(Collection collection, Function mapFunc) + { + return collection.stream().collect(Collectors.groupingBy(mapFunc)); + } + + public static Map> groupingBy(Collection collection, Function mapFunc, Function mapValueFunc) + { + return collection.stream().collect(Collectors.groupingBy(mapFunc, Collectors.mapping(mapValueFunc, Collectors.toList()))); + } + + // keep + public static Map toMap(Collection collection, Function mapFunc) + { + return collection.stream().collect(Collectors.toMap(mapFunc, x -> x, (a, b) -> a)); + } + + public static Map toMap_override(Collection collection, Function mapFunc) + { + return collection.stream().collect(Collectors.toMap(mapFunc, x -> x, (a, b) -> b)); + } + + // keep + public static Map toMap(Collection collection, Function mapFunc, Function valFunc) + { + return collection.stream().collect(Collectors.toMap(mapFunc, valFunc, (a, b) -> a)); + } + + public static Map toMap_override(Collection collection, Function mapFunc, Function valFunc) + { + return collection.stream().collect(Collectors.toMap(mapFunc, valFunc, (a, b) -> b)); + } + + // keep + public static Map toLinkedMap(Collection collection, Function mapFunc) + { + return collection.stream().collect(Collectors.toMap(mapFunc, x -> x, (a, b) -> a, LinkedHashMap::new)); + } + + public static Map toLinkedMap_override(Collection collection, Function mapFunc) + { + return collection.stream().collect(Collectors.toMap(mapFunc, x -> x, (a, b) -> b, LinkedHashMap::new)); + } +/* + *//** + * ListTriple::negativeList -> 集合a独有的差集 + * ListTriple::zeroList -> 集合a和集合b共有的交集 + * ListTriple::positiveList -> 集合b独有的差集 + *//* + public static ListTriple intersection_difference(List a, List b, boolean...distinct *//* = false: 差集去重 *//*) + { + if(CollectionUtil.isEmpty(a) && CollectionUtil.isEmpty(b)) + return ListTriple.empty_triple(); + if(CollectionUtil.isEmpty(a) && CollectionUtil.isNotEmpty(b)) + return ListTriple.make_triple(b, (x) -> 1); + if(CollectionUtil.isNotEmpty(a) && CollectionUtil.isEmpty(b)) + return ListTriple.make_triple(a, (x) -> -1); + ListTriple triple = ListTriple.empty_triple(); + List intersection = a.stream().filter(b::contains).distinct().collect(Collectors.toList()); + triple.zeroList.addAll(intersection); + if(null != distinct && distinct.length > 0 && distinct[0]) + { + triple.negativeList.addAll(a.stream().filter((x) -> !intersection.contains(x)).distinct().collect(Collectors.toList())); + triple.positiveList.addAll(b.stream().filter((x) -> !intersection.contains(x)).distinct().collect(Collectors.toList())); + } + else + { + triple.negativeList.addAll(a.stream().filter((x) -> !intersection.contains(x)).collect(Collectors.toList())); + triple.positiveList.addAll(b.stream().filter((x) -> !intersection.contains(x)).collect(Collectors.toList())); + } + return triple; + }*/ + + public static T get(Collection list, int index) + { + if(CollectionUtil.isEmpty(list)) + return null; + int size = list.size(); + int i = index < 0 ? size + index : index; + if(i < 0 || i >= size) + return null; + if(list instanceof List) + return ((List) list).get(i); + else + { + Iterator itor = list.iterator(); + int c = 0; + while(itor.hasNext()) + { + T val = itor.next(); + if(c == i) + return val; + c++; + } + } + return null; + } + + public static boolean contains_ptr(Collection list, T target) + { + if(CollectionUtil.isEmpty(list)) + return false; + return list.stream().anyMatch((x) -> x == target); + } + + public static int indexOf_ptr(List list, T target) + { + if(CollectionUtil.isEmpty(list)) + return -1; + for(int i = 0; i < list.size(); i++) + { + if(list.get(i) == target) + return i; + } + return -1; + } + + public static List combine(Collection...src) + { + if(null != src && src.length > 0) + { + return Arrays.stream(src) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + return new ArrayList<>(); + } + + public static List combine(List> src) + { + if(CollectionUtil.isNotEmpty(src)) + { + return src.stream() + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } + + return new ArrayList<>(); + } + + public static BigDecimal reduce_s(Collection list, Function getDecimalFunc, BigDecimal initValue) + { + BigDecimal init = null != initValue ? initValue : BigDecimal.ZERO; + if(CollectionUtil.isEmpty(list)) + return init; + return list.stream().map(getDecimalFunc).reduce(init, NumberUtil::add); + } + + public static BigDecimal reduce_s(Collection list, Function getDecimalFunc) + { + return reduce_s(list, getDecimalFunc, BigDecimal.ZERO); + } + + private ContainerUtils() {} +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ConvertUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ConvertUtils.java new file mode 100644 index 0000000..05cdf61 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ConvertUtils.java @@ -0,0 +1,30 @@ +package com.ruoyi.common.utils; + +public final class ConvertUtils +{ + // null = true + public static boolean TRUE(Boolean b) + { + return null == b || b; + } + + // null = false + public static boolean FALSE(Boolean b) + { + if(null == b) + return false; + return b; + } + + public static String toString_s(Object obj) + { + if(null == obj) + return ""; + if(obj instanceof String) + return (String)obj; + else + return obj.toString(); + } + + private ConvertUtils() {} +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeUtils.java new file mode 100644 index 0000000..8e03337 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeUtils.java @@ -0,0 +1,143 @@ +package com.ruoyi.common.utils; + +import cn.hutool.core.collection.CollectionUtil; +import lombok.Builder; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +// zhao: 此TreeUtils不需要外部的容器包装类, 只需要配置`id`, `parentId`的getter和`children`的setter等 +public final class TreeUtils +{ + // 从列表构建树 + public static List/* 树 */ makeTree(List list/* = 列表 */, ConfigInterface config, Object...parentIdArgs) + { + Object parentId = parentIdArgs.length > 0 ? parentIdArgs[0] : null; + return list.stream() + .filter((x) -> config.idEquals(parentId, config.getParentId(x))) + .peek((x) -> config.setChildren(x, makeTree(list, config, config.getId(x)))) + .collect(Collectors.toList()); + } + + // 获取列表的所有叶子节点 + public static List/* 列表 */ treeLeafs(List list/* = 列表 */, ConfigInterface config) + { + return list.stream().filter((x) -> list.stream() + .filter((y) -> !config.idEquals(config.getId(x), config.getId(y))) + .noneMatch((y) -> config.idEquals(config.getId(x), config.getParentId(y))) + ) + .collect(Collectors.toList()); + } + + // 获取树的所有节点 + public static List/* 列表 */ makeList(List tree/* = 树 */, ConfigInterface config) + { + List res = new ArrayList<>(); + foreach(tree, res::add, config); + return res; + } + + // 从上到下遍历树节点 + public static void recursion(T node/* = 树节点 */, Consumer func, ConfigInterface config) + { + if(null == node) + return; + func.accept(node); + foreach(config.getChildren(node), func, config); + } + + // 从上到下遍历树节点列表 + public static void foreach(List tree/* = 树 */, Consumer func, ConfigInterface config) + { + if(CollectionUtil.isEmpty(tree)) + return; + for(T child : tree) + recursion(child, func, config); + } + + // 从下到上遍历树节点 + public static void recursionReverse(T node/* = 树节点 */, Consumer func, ConfigInterface config) + { + if(null == node) + return; + foreachReverse(config.getChildren(node), func, config); + func.accept(node); + } + + // 从下到上遍历树节点列表 + public static void foreachReverse(List tree/* = 树 */, Consumer func, ConfigInterface config) + { + if(CollectionUtil.isEmpty(tree)) + return; + for(T child : tree) + recursionReverse(child, func, config); + } + + public static interface ConfigInterface + { + public default boolean idEquals(Object a, Object b) // 比较ID/父ID是否想的, 默认Object::equals + { + if(null == a && null == b) + return true; + if(null == a || null == b) + return false; + return a.equals(b); + } + public Object getId(T item); // 获取T的ID + public Object getParentId(T item); // 获取T的父ID + public void setChildren(T item, List children); // 设置T的children列表 + public List getChildren(T object); // 获取T的children列表 + } + + @Data + @Builder + public static class Config implements ConfigInterface // 简单的可实例化的T的配置类 + { + public Function getIdFunc; // makeTree必需, 返回I的ID + public Function getParentIdFunc; // makeTree必需, 返回I的父ID + public BiConsumer> setChildrenFunc; // makeTree必需, 设置T的children + public BiPredicate idEqualsFunc; // 非必需, 比较ID/父ID是否想的, 默认使用Object::equals + + public Function> getChildrenFunc; // 遍历时必需, 返回T的children列表 + + public boolean idEquals(Object a, Object b) + { + if(null != idEqualsFunc) + return idEqualsFunc.test(a, b); + if(null == a && null == b) + return true; + if(null == a || null == b) + return false; + return a.equals(b); + } + + public Object getId(T item) + { + return getIdFunc.apply(item); + } + + public Object getParentId(T item) + { + return getParentIdFunc.apply(item); + } + + public void setChildren(T item, List children) + { + if(CollectionUtil.isNotEmpty(children)) + setChildrenFunc.accept(item, children); + } + + public List getChildren(T object) + { + return getChildrenFunc.apply(object); + } + } + + private TreeUtils() {} +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/ExtractGeneratedSource.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/ExtractGeneratedSource.java new file mode 100644 index 0000000..e8d236b --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/ExtractGeneratedSource.java @@ -0,0 +1,360 @@ +package com.ruoyi.common.utils.dev; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.IoUtil; +import com.ruoyi.common.utils.StringUtils; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.File; +import java.io.InputStream; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +@Data +@Accessors(chain = true) +public class ExtractGeneratedSource +{ + private String zipPath; + private String javaProjectPath; + private String webProjectPath; + private String module; + private Map fileMap = new LinkedHashMap<>(); + + private ZipFile zipFile; + + public void Set(String zipPath, String javaProjectPath, String webProjectPath, String module) + { + this.zipPath = zipPath; + this.javaProjectPath = javaProjectPath; + this.webProjectPath = webProjectPath; + this.module = module; + } + + public void Reset() + { + if(null != zipFile) + { + IoUtil.close(zipFile); + zipFile = null; + } + fileMap.clear(); + Set(null, null, null, null); + } + + public boolean Test(String[] res) + { + StringBuilder sb = new StringBuilder(); + boolean r = true; + List files; + Map map = new LinkedHashMap<>(); + + Function f = (x) -> { + String str = GetExtractPath(x); + map.put(x, str); + return x + " -> " + str; + }; + + files = ListFileInZip("main/java/com/ruoyi/.*/domain/.*\\.java"); + r = r && CollectionUtil.isNotEmpty(files); + sb.append("domain.java:\n") + .append("\t"); + if(CollectionUtil.isNotEmpty(files)) + sb.append(files.stream().map(f).collect(Collectors.joining("\n\t"))); + else + sb.append("缺失!"); + sb.append("\n\n"); + + files = ListFileInZip("main/java/com/ruoyi/.*/service/.*\\.java"); + r = r && CollectionUtil.isNotEmpty(files); + sb.append("service.java:\n") + .append("\t"); + if(CollectionUtil.isNotEmpty(files)) + sb.append(files.stream().map(f).collect(Collectors.joining("\n\t"))); + else + sb.append("缺失!"); + sb.append("\n\n"); + +// files = ListFileInZip("main/java/com/ruoyi/.*/service/impl/.*\\.java"); +// r = r && CollectionUtil.isNotEmpty(files); +// sb.append("service_impl.java:\n") +// .append("\t") +// .append(files.stream().map(f).collect(Collectors.joining("\n\t"))) +// ; +// sb.append("\n\n"); + + files = ListFileInZip("main/java/com/ruoyi/.*/mapper/.*\\.java"); + r = r && CollectionUtil.isNotEmpty(files); + sb.append("mapper.java:\n") + .append("\t"); + if(CollectionUtil.isNotEmpty(files)) + sb.append(files.stream().map(f).collect(Collectors.joining("\n\t"))); + else + sb.append("缺失!"); + sb.append("\n\n"); + + files = ListFileInZip("main/java/com/ruoyi/.*/controller/.*\\.java"); + r = r && CollectionUtil.isNotEmpty(files); + sb.append("controller.java:\n") + .append("\t"); + if(CollectionUtil.isNotEmpty(files)) + sb.append(files.stream().map(f).collect(Collectors.joining("\n\t"))); + else + sb.append("缺失!"); + sb.append("\n\n"); + + files = ListFileInZip("main/resources/mapper/.*/.*\\.xml"); + r = r && CollectionUtil.isNotEmpty(files); + sb.append("MyBatis.xml:\n") + .append("\t"); + if(CollectionUtil.isNotEmpty(files)) + sb.append(files.stream().map(f).collect(Collectors.joining("\n\t"))); + else + sb.append("缺失!"); + sb.append("\n\n"); + + files = ListFileInZip("vue/.*\\.vue"); + r = r && CollectionUtil.isNotEmpty(files); + sb.append("Vue:\n") + .append("\t"); + if(CollectionUtil.isNotEmpty(files)) + sb.append(files.stream().map(f).collect(Collectors.joining("\n\t"))); + else + sb.append("缺失!"); + sb.append("\n\n"); + + files = ListFileInZip("vue/.*\\.js"); + r = r && CollectionUtil.isNotEmpty(files); + sb.append("JavaScript:\n") + .append("\t"); + if(CollectionUtil.isNotEmpty(files)) + sb.append(files.stream().map(f).collect(Collectors.joining("\n\t"))); + else + sb.append("缺失!"); + sb.append("\n"); + + if(null != res && res.length > 0) + res[0] = sb.toString(); + fileMap.clear(); + if(r) + fileMap.putAll(map); + return r; + } + + public boolean IsValid() + { + return StringUtils.isNotEmpty(zipPath) + && StringUtils.isNotEmpty(javaProjectPath) + && StringUtils.isNotEmpty(webProjectPath) + ; + } + + public boolean Begin() + { + try + { + zipFile = new ZipFile(zipPath); + return true; + } + catch(Exception e) + { + e.printStackTrace(); + return false; + } + } + + public boolean Extract(BiFunction ifExists) + { + if(CollectionUtil.isEmpty(fileMap)) + return false; + for(Map.Entry entry : fileMap.entrySet()) + { + String src = entry.getKey(); + String dst = entry.getValue(); + File d = new File(dst); + if(d.exists()) + { + if(null != ifExists) + { + int ife = ifExists.apply(src, dst); + if(ife == 0) + continue; + if(ife < 0) + return false; + } + } + if(!Copy(src, dst)) + return false; + } + return true; + } + + private boolean Copy(String src, String dst) + { + File d = new File(dst); + d.deleteOnExit(); + if(mkdirs(d.getParent()) < 0) + return false; + byte[] source = ReadFileInZip(src); + if(null == source) + return false; + return null != FileUtil.writeBytes(source, d); + } + + public void End() + { + } + + private String GuessModuleName(String zipPath) + { + if(IsJava(zipPath)) + { + int i = "main/java/com/ruoyi/".length(); + int e = zipPath.indexOf("/", i); + return zipPath.substring(i, e); + } + else if(IsMybatis(zipPath)) + { + int i = "main/resources/mapper/".length(); + int e = zipPath.indexOf("/", i); + return zipPath.substring(i, e); + } + return null; + } + + private String GetModuleName(String zipPath) + { + if(StringUtils.isNotEmpty(module)) + return module; + return GuessModuleName(zipPath); + } + + private String GetExtractPath(String zipPath) + { + File file = new File(zipPath); + String fileName = file.getName(); + if(IsJava(zipPath)) + { + if(IsController(zipPath)) + { + String name = GuessModuleName(zipPath); + return getJavaProjectPath() + "/ruoyi-admin/src/main/java/com/ruoyi/web/controller/" + name + "/" + fileName; + } + else + { + String moduleName = GetModuleName(zipPath); + return getJavaProjectPath() + "/ruoyi-" + moduleName + "/src/" + zipPath; + } + } + else if(IsMybatis(zipPath)) + { + String moduleName = GetModuleName(zipPath); + return getJavaProjectPath() + "/ruoyi-" + moduleName + "/src/" + zipPath; + } + else if(IsVue(zipPath) || IsJavaScript(zipPath)) + { + return webProjectPath + "/ruoyi-ui/src" + zipPath.substring("vue".length()); + } + return null; + } + + private boolean IsJava(String zipPath) + { + return zipPath.endsWith(".java"); + } + + private boolean IsController(String zipPath) + { + return zipPath.endsWith("Controller.java"); + } + + private boolean IsMybatis(String zipPath) + { + return zipPath.endsWith(".xml"); + } + + private boolean IsVue(String zipPath) + { + return zipPath.endsWith(".vue"); + } + + private boolean IsJavaScript(String zipPath) + { + return zipPath.endsWith(".js"); + } + + private List ListFileInZip(String regexp) + { + return zipFile.stream() + .map(ZipEntry::getName) + .filter((x) -> { + return (Pattern.matches(regexp, x)); + }).collect(Collectors.toList()); + } + + private byte[] ReadFileInZip(String path) + { + ZipEntry entry = zipFile.getEntry(path); + if(null == entry) + return null; + + InputStream is = null; + + try + { + is = zipFile.getInputStream(entry); + return IoUtil.readBytes(is); + } + catch(Exception e) + { + e.printStackTrace(); + return null; + } + finally + { + IoUtil.close(is); + } + } + + private int mkdirs(String path) + { + File file = new File(path); + if(file.exists()) + { + if(file.isDirectory()) + return 0; + else + return -1; + } + return file.mkdirs() ? 1 : -2; + } + + private String AppendPath(String basePath, String filePath) + { + String path = basePath + File.separator + filePath; + File file = new File(path); + try + { + return file.getCanonicalPath(); + } + catch(Exception e) + { + e.printStackTrace(); + return path; + } + } + + public static void main(String[] args) + { + ExtractGeneratedSourceGUI program = new ExtractGeneratedSourceGUI(); + program.setVisible(true); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/ExtractGeneratedSourceGUI.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/ExtractGeneratedSourceGUI.java new file mode 100644 index 0000000..efbcf2f --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/ExtractGeneratedSourceGUI.java @@ -0,0 +1,143 @@ +package com.ruoyi.common.utils.dev; + +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.dev.gui.FileField; +import com.ruoyi.common.utils.dev.gui.InputField; + +import javax.swing.*; +import java.awt.*; + +public class ExtractGeneratedSourceGUI extends JFrame +{ + private ExtractGeneratedSource engine; + private FileField zipPath; + private FileField javaProjectPath; + private FileField webProjectPath; + private InputField module; + private JTextPane result; + private JButton writeBtn; + private boolean canWrite; + + public ExtractGeneratedSourceGUI() + { + super(); + engine = new ExtractGeneratedSource(); + Setup(); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setTitle("代码解压器"); + pack(); + } + + private void Reset() + { + engine.Reset(); + zipPath.Reset(); + javaProjectPath.Reset(); + module.Reset(); + webProjectPath.Reset(); + canWrite = false; + writeBtn.setEnabled(false); + } + + private void Setup() + { + JMenuBar menuBar = new JMenuBar(); + setJMenuBar(menuBar); + JMenu fileMenu = new JMenu("文件"); + JMenuItem menuItem = new JMenuItem("清空"); + menuItem.addActionListener(x -> Reset()); + fileMenu.add(menuItem); + menuItem = new JMenuItem("退出"); + menuItem.addActionListener(x -> System.exit(0)); + fileMenu.add(menuItem); + JMenu otherMenu = new JMenu("其他"); + menuItem = new JMenuItem("关于"); + menuItem.addActionListener(x -> JOptionPane.showMessageDialog(this, "解压生成的代码压缩包", "关于", JOptionPane.INFORMATION_MESSAGE)); + otherMenu.add(menuItem); + menuBar.add(fileMenu); + menuBar.add(otherMenu); + zipPath = new FileField("源码zip文件(可拖拽)"); + javaProjectPath = new FileField("后端项目根目录(可拖拽)"); + webProjectPath = new FileField("前端项目根目录(可拖拽)"); + String path; + path = System.getenv("RUOYI_SOURCE_DIRECTORY_PATH"); + if(StringUtils.isNotEmpty(path)) + zipPath.SetLastPath(path); + path = System.getenv("RUOYI_JAVA_PROJECT_PATH"); + if(StringUtils.isNotEmpty(path)) + javaProjectPath.SetPath(path); + path = System.getenv("RUOYI_WEB_PROJECT_PATH"); + if(StringUtils.isNotEmpty(path)) + webProjectPath.SetPath(path); + module = new InputField("模块"); + module.SetToolTipText("例如. home(为空则自动从zip中获取)"); + zipPath.SetFilter(".zip"); + javaProjectPath.SetMode(JFileChooser.DIRECTORIES_ONLY); + webProjectPath.SetMode(JFileChooser.DIRECTORIES_ONLY); + Box formPanel = Box.createVerticalBox(); + formPanel.setAutoscrolls(true); + formPanel.add(zipPath); + formPanel.add(javaProjectPath); + formPanel.add(webProjectPath); + formPanel.add(module); + result = new JTextPane(); + JScrollPane scrollPane = new JScrollPane(result); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + result.setFont(Font.getFont(Font.MONOSPACED)); + formPanel.add(scrollPane); + BorderLayout mainLayout = new BorderLayout(); + JPanel panel = new JPanel(); + panel.setLayout(mainLayout); + panel.add(formPanel, BorderLayout.CENTER); + Box toolbar = Box.createHorizontalBox(); + toolbar.add(Box.createHorizontalGlue()); + writeBtn = new JButton("复制"); + writeBtn.addActionListener(e -> Copy()); + writeBtn.setEnabled(false); + toolbar.add(writeBtn); + JButton startBtn = new JButton("测试"); + startBtn.addActionListener(e -> Test()); + toolbar.add(startBtn); + JButton clearBtn = new JButton("清空"); + clearBtn.addActionListener(e -> Reset()); + toolbar.add(clearBtn); + panel.add(toolbar, BorderLayout.SOUTH); + setContentPane(panel); + } + + private void Test() + { + engine.Set(zipPath.Path(), javaProjectPath.Path(), webProjectPath.Path(), module.Text()); + if(!engine.IsValid()) + { + JOptionPane.showMessageDialog(this, "必须设置源码zip和后端/前端项目目录", "警告", JOptionPane.ERROR_MESSAGE); + return; + } + engine.Begin(); + String[] res = {null}; + canWrite = engine.Test(res); + result.setText(res[0]); + writeBtn.setEnabled(canWrite); + } + + private void Copy() + { + if(canWrite) + { + boolean r = engine.Extract((src, dst) -> { + int res = JOptionPane.showConfirmDialog(this, "是否覆盖已存在文件: " + dst + "(原文件: " + src + ")", "警告", JOptionPane.YES_NO_CANCEL_OPTION); + if(res == JOptionPane.YES_OPTION) + return 1; + else if(res == JOptionPane.NO_OPTION) + return 0; + else// if(res == JOptionPane.CANCEL_OPTION) + return -1; + }); + if(r) + JOptionPane.showMessageDialog(this, "复制文件成功!", "成功", JOptionPane.INFORMATION_MESSAGE); + else + JOptionPane.showMessageDialog(this, "复制文件失败!", "错误", JOptionPane.ERROR_MESSAGE); + } + engine.End(); + } +} \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/Konsole.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/Konsole.java new file mode 100644 index 0000000..334e863 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/Konsole.java @@ -0,0 +1,301 @@ +package com.ruoyi.common.utils.dev; + +import java.util.Objects; + +// Unix \033[字背景颜色;字体颜色m字符串\033[0m +// 高亮+闪烁+红色前景+蓝色背景 +// 32位 |设置8位 0 0 0 0 0 启用背景色 背景高亮 字体高亮|字体风格8位|字体色8位|背景色8位 +public class Konsole { + private static final String RESET = "\033[0m"; // Text Reset + private static final int COLOR_OFFSET = 8; + private static final int COLOR_MASK = 0xFF00; + private static final int BG_COLOR_OFFSET = 0; + private static final int BG_COLOR_MASK = 0xFF; + private static final int FONT_STYLE_OFFSET = 16; + private static final int FONT_STYLE_MASK = 0xFF0000; + private static final int STYLE_OFFSET = 24; + private static final int STYLE_MASK = 0x7F000000; + + // 1. 原始值: 需要SetXXX(值)设置, MakeStyle + public static final int FONT_BRIGHT = 1; + public static final int BG_BRIGHT = 1 << 1; + public static final int BG_ENABLED = 1 << 2; + + public static final int NORMAL = 0; // 3:斜体 4:下划线 5:闪烁 6:默认 7:白底 8:透明 9:删除线 + public static final int BOLD = 1; + public static final int FAINT = 2; + public static final int ITALIC = 3; + public static final int UNDERLINE = 4; + public static final int FLASH = 5; + public static final int DEFAULT = 6; + public static final int WHITE_BACKGROUND = 7; + public static final int TRANSLUCENT = 8; + public static final int STRIKETHROUGH = 9; + public static final int DOUBLE_UNDER_LINE = 21; + + public static final int BLACK = 30; // BLACK + public static final int RED = 31; // RED + public static final int GREEN = 32; // GREEN + public static final int YELLOW = 33; // YELLOW + public static final int BLUE = 34; // BLUE + public static final int PURPLE = 35; // PURPLE + public static final int CYAN = 36; // CYAN + public static final int WHITE = 37; // WHITE + + // 2. 预置值: 可以 | 或拼接 + public static final int S_FONT_BRIGHT = FONT_BRIGHT << STYLE_OFFSET; + public static final int S_BG_BRIGHT = BG_BRIGHT << STYLE_OFFSET; + public static final int S_BG_ENABLED = BG_BRIGHT << STYLE_OFFSET; + + public static final int FS_NORMAL = NORMAL; + public static final int FS_BOLD = BOLD << FONT_STYLE_OFFSET; + public static final int FS_FAINT = FAINT << FONT_STYLE_OFFSET; + public static final int FS_ITALIC = ITALIC << FONT_STYLE_OFFSET; + public static final int FS_UNDERLINE = UNDERLINE << FONT_STYLE_OFFSET; + public static final int FS_FLASH = FLASH << FONT_STYLE_OFFSET; + public static final int FS_DEFAULT = DEFAULT << FONT_STYLE_OFFSET; + public static final int FS_WHITE_BACKGROUND = WHITE_BACKGROUND << FONT_STYLE_OFFSET; + public static final int FS_TRANSLUCENT = TRANSLUCENT << FONT_STYLE_OFFSET; + public static final int FS_STRIKETHROUGH = STRIKETHROUGH << FONT_STYLE_OFFSET; + public static final int FS_DOUBLE_UNDER_LINE = DOUBLE_UNDER_LINE << STYLE_OFFSET; + + public static final int FC_BLACK = BLACK << COLOR_OFFSET; + public static final int FC_RED = RED << COLOR_OFFSET; + public static final int FC_GREEN = GREEN << COLOR_OFFSET; + public static final int FC_YELLOW = YELLOW << COLOR_OFFSET; + public static final int FC_BLUE = BLUE << COLOR_OFFSET; + public static final int FC_PURPLE = PURPLE << COLOR_OFFSET; + public static final int FC_CYAN = CYAN << COLOR_OFFSET; + public static final int FC_WHITE = WHITE << COLOR_OFFSET; + + public static final int BC_BLACK = BLACK; + public static final int BC_RED = RED; + public static final int BC_GREEN = GREEN; + public static final int BC_YELLOW = YELLOW; + public static final int BC_BLUE = BLUE; + public static final int BC_PURPLE = PURPLE; + public static final int BC_CYAN = CYAN; + public static final int BC_WHITE = WHITE; + + public static final int FC_BRIGHT_BLACK = (BLACK + 60) << COLOR_OFFSET; + public static final int FC_BRIGHT_RED = (RED + 60) << COLOR_OFFSET; + public static final int FC_BRIGHT_GREEN = (GREEN + 60) << COLOR_OFFSET; + public static final int FC_BRIGHT_YELLOW = (YELLOW + 60) << COLOR_OFFSET; + public static final int FC_BRIGHT_BLUE = (BLUE + 60) << COLOR_OFFSET; + public static final int FC_BRIGHT_PURPLE = (PURPLE + 60) << COLOR_OFFSET; + public static final int FC_BRIGHT_CYAN = (CYAN + 60) << COLOR_OFFSET; + public static final int FC_BRIGHT_WHITE = (WHITE + 60) << COLOR_OFFSET; + + public static final int BC_BRIGHT_BLACK = BLACK + 70; + public static final int BC_BRIGHT_RED = RED + 70; + public static final int BC_BRIGHT_GREEN = GREEN + 70; + public static final int BC_BRIGHT_YELLOW = YELLOW + 70; + public static final int BC_BRIGHT_BLUE = BLUE + 70; + public static final int BC_BRIGHT_PURPLE = PURPLE + 70; + public static final int BC_BRIGHT_CYAN = CYAN + 70; + public static final int BC_BRIGHT_WHITE = WHITE + 70; + + public int style; + + public Konsole(int style) { + this.style = style; + } + + public Konsole SetFontColor(int color) { + this.style = SetAttribute(color, COLOR_OFFSET, COLOR_MASK); + return this; + } + + public Konsole SetFontStyle(int style) { + this.style = SetAttribute(style, FONT_STYLE_OFFSET, FONT_STYLE_MASK); + return this; + } + + public Konsole SetBGColor(int color) { + this.style = SetAttribute(color, BG_COLOR_OFFSET, BG_COLOR_MASK); + return this; + } + + public Konsole SetStyleConfig(int style, boolean enabled) { + if(enabled) + this.style = style << STYLE_OFFSET | (this.style & ~STYLE_MASK); + else + this.style = (this.style & ~STYLE_MASK) & ~(style << STYLE_OFFSET); + return this; + } + + public int Style() { + return style; + } + + public Konsole Style(int style) { + this.style = style; + return this; + } + + private int SetAttribute(int color, int offset, int mask) { + int newColor = color << offset; + return (this.style & ~mask) | newColor; + } + + private static int GetAttribute(int style, int offset, int mask) { + return (style & mask) >> offset; + } + + @Override + public String toString() { + return GetEscString(this.style); + } + + public String Output(String str) + { + StringBuilder sb = new StringBuilder(); + sb.append(GetEscString(style)); + sb.append(str); + sb.append(RESET); + return sb.toString(); + } + + public static String MakeText(String str, int style) + { + StringBuilder sb = new StringBuilder(); + sb.append(GetEscString(style)); + sb.append(str); + sb.append(RESET); + return sb.toString(); + } + + public static int MakeStyle(int fontColor, int fontStyle, int bgColor, int style) + { + return (fontColor << COLOR_OFFSET) | (fontStyle << FONT_STYLE_OFFSET) | (bgColor << BG_COLOR_OFFSET) << (style << STYLE_OFFSET); + } + + public static int GenStyle(int... mask) + { + int style = 0; + for (int j : mask) style |= j; + return style; + } + + private static String GetEscString(int style) { + if (style == 0) return RESET; + StringBuilder sb = new StringBuilder(); + sb.append("\033["); + sb.append(GenStyleStr(style)); + sb.append("m"); + return sb.toString(); + } + + private static String GenStyleStr(int style) { + int enableBG = GetAttribute(style, 2, STYLE_MASK); + int fontColor = GetAttribute(style, COLOR_OFFSET, COLOR_MASK); + int fontStyle = GetAttribute(style, FONT_STYLE_OFFSET, FONT_STYLE_MASK); + + StringBuilder sb = new StringBuilder(); + if(fontStyle != 0) + sb.append(fontStyle).append(";"); + if(fontColor != 0) + { + int hlFont = GetAttribute(style, 0, STYLE_MASK); + fontColor = GenColor(fontColor, hlFont != 0 ? 90 - 30 : 0); + sb.append(fontColor).append(";"); + } + if(enableBG != 0) + { + int bgColor = GetAttribute(style, BG_COLOR_OFFSET, BG_COLOR_MASK); + if(bgColor != 0) + { + int hlBG = GetAttribute(style, 1, STYLE_MASK); + bgColor = GenColor(bgColor, hlBG != 0 ? 100 - 30 : 40 - 30); + sb.append(bgColor).append(";"); + } + } + + if(sb.length() > 0 && sb.lastIndexOf(";") == sb.length() - 1) + sb.deleteCharAt(sb.length() - 1); + + return sb.toString(); + } + + private static int GenColor(int color, int base) + { + return color + base; + } + + public static final int STDOUT = 1; + public static final int STDERR = 2; + public static class out + { + public static void println(int style, Object obj) + { + System.out.println(MakeText(Objects.toString(obj), style)); + } + + public static void print(int style, Object obj) + { + System.out.print(MakeText(Objects.toString(obj), style)); + } + + public static void printf(int style, String fmt, Object...args) + { + if(null == fmt) + println(style, fmt); + else + println(style, String.format(fmt, args)); + } + } + + public static class err + { + public static void println(int style, Object obj) + { + System.err.println(MakeText(Objects.toString(obj), style)); + } + + public static void print(int style, Object obj) + { + System.err.print(MakeText(Objects.toString(obj), style)); + } + + public static void printf(int style, String fmt, Object...args) + { + if(null == fmt) + println(style, fmt); + else + println(style, String.format(fmt, args)); + } + } + + public static void cout(int style, Object obj) + { + out.println(style, obj); + } + + public static void cerr(int style, Object obj) + { + err.println(style, obj); + } + + public static void printf(int style, String fmt, Object...args) + { + out.printf(style, fmt, args); + } + + public static void fprintf(int file, int style, String fmt, Object...args) + { + if(file == STDERR) + err.printf(style, fmt, args); + else + out.printf(style, fmt, args); + } + + public static String sprintf(int style, String fmt, Object...args) + { + return MakeText(null != fmt ? String.format(fmt, args) : "null", style); + } + + public static void main(String[] args) { + System.out.println("\033[0;7;31;44m TEXT \033[0m"); + System.out.println(MakeText("TEXT", FS_UNDERLINE | FC_BLUE | S_BG_BRIGHT | S_BG_ENABLED | BC_CYAN | S_FONT_BRIGHT)); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/SQLQueryFuncGen.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/SQLQueryFuncGen.java new file mode 100644 index 0000000..dd0b01c --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/SQLQueryFuncGen.java @@ -0,0 +1,394 @@ +package com.ruoyi.common.utils.dev; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.StringUtils; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.File; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Scanner; + +@Data +@Accessors(chain = true) +public class SQLQueryFuncGen +{ + private String workPath; + private String queryId; + private String entity; + private String module; + private String packageName; + private String comment; + private Map parameterType; + private String returnType; + private String mapper_java; + private String service_java; + private String serviceImpl_java; + private final static String PARAM_DEFAULT_NAME = "cond"; + + public String GetParameterType() + { + return GenParameterStr(1); + } + + public void SetParameterType(String type) + { + parameterType = ParseParameterType(type); + } + + public String GetReturnType() + { + return returnType; + } + + public void SetReturnType(String type) + { + this.returnType = ParseReturnType(type); + } + + public SQLQueryFuncGen() + { + workPath = System.getProperty("user.dir").replaceAll(File.pathSeparator, "/"); + } + + private String In(String label) + { + Konsole.out.print(Konsole.FC_BLUE, label); + Scanner scanner = new Scanner(System.in); + String str = scanner.nextLine(); + if(StrUtil.isEmpty(str)) + return ""; + return str.trim(); + } + + private String WaitIn(String label) + { + String str; + do + { + str = In(label); + } + while(StrUtil.isEmpty(str)); + return str; + } + + private String ParseReturnType(String type) + { + if(StrUtil.isEmpty(type)) + return "void" ; // entity; + if(type.equalsIgnoreCase("List")) + return String.format("List<%s>", entity); + if(type.equalsIgnoreCase("Map")) + return "Map"; + if(type.equalsIgnoreCase("List")) + return "List>"; + return type; + } + + private String ReadReturnType(String label) + { + String type = In(label); + return ParseReturnType(type); + + } + + private void GuessType(String type, Map res) + { + String name = null; + String newType = null; + if(type.equalsIgnoreCase("List")) + { + name = StrUtil.lowerFirst(entity) + "List"; + newType = String.format("List<%s>", entity); + } + else if(type.equalsIgnoreCase("Map")) + { + name = "map"; + newType = "Map"; + } + else if(type.equalsIgnoreCase("ID")) + { + name = "id"; + newType = "Long"; + } + else if(type.equalsIgnoreCase("Long")) + { + name = "num"; + newType = "Long"; + } + else if(type.equalsIgnoreCase("int")) + { + name = "i"; + newType = "int"; + } + else if(type.equalsIgnoreCase("BigDecimal")) + { + name = "num"; + newType = "BigDecimal"; + } + else if(type.equalsIgnoreCase("String")) + { + name = "name"; + newType = "String"; + } + else if(type.equalsIgnoreCase("List")) + { + name = "mapList"; + newType = "List>"; + } + else if(type.equalsIgnoreCase("void")) + { + name = ""; + newType = ""; + } + else + { + if(!type.contains(" ")) + { + name = StrUtil.lowerFirst(type); + newType = type; + } + else + { + String[] arr = type.split(" "); + for(String s : arr) + { + GuessType(s.trim(), res); + } + } + } + if(StrUtil.isNotEmpty(name)) + { + int i = 0; + String newName = name; + while(res.containsKey(newName)) + newName = name + (++i); + res.put(newName, newType); + } + } + + private Map ReadParameterType(String label) + { + String type = In(label); + return ParseParameterType(type); + } + + private Map ParseParameterType(String type) + { + Map res = new LinkedHashMap<>(); + if(StrUtil.isEmpty(type)) + { + /*res.put(PARAM_DEFAULT_NAME, entity); + return res;*/ + return null; + } + GuessType(type, res); + return res; + } + + private String GenParameterStr(int type) + { + if(null == parameterType) + return ""; + List list = new ArrayList<>(); + parameterType.forEach((k, v) -> { + String str = ""; + if((type & 1) != 0) + str += v; + if((type & 2) != 0) + str += (str.isEmpty() ? k : (" " + k)); + list.add(str); + }); + return CollectionUtil.join(list, ", "); + } + + public void ScanFilePath() + { + String modulePath = String.format("%s/ruoyi-%s/src/main/java/com/ruoyi/%s", workPath, module, StringUtils.isNotEmpty(packageName) ? packageName : module); + String mapperPath = modulePath + "/" + "mapper"; + String servicePath = modulePath + "/" + "service"; + String serviceImplPath = modulePath + "/" + "service/impl"; + String mapperName = entity + "Mapper"; + String serviceName = "I" + entity + "Service"; + String serviceImplName = entity + "ServiceImpl"; + mapper_java = mapperPath + "/" + mapperName + ".java"; + service_java = servicePath + "/" + serviceName + ".java"; + serviceImpl_java = serviceImplPath + "/" + serviceImplName + ".java"; + } + + private void PrintSummary() + { + Konsole.cout(Konsole.FC_GREEN, "Configure: "); + Konsole.cout(Konsole.FC_CYAN, "Mybatis query ID: " + queryId); + Konsole.cout(Konsole.FC_CYAN, "Entity class: " + entity); + Konsole.cout(Konsole.FC_CYAN, "Module name: " + module); + Konsole.cout(Konsole.FC_CYAN, "Package name: " + packageName); + Konsole.cout(Konsole.FC_CYAN, "Return type: " + returnType); + Konsole.cout(Konsole.FC_CYAN, "Parameter type: " + parameterType); + Konsole.cout(Konsole.FC_CYAN, "Parameter type string: " + GenParameterStr(1 | 2)); + Konsole.cout(Konsole.FC_CYAN, "Mapper file: " + mapper_java); + Konsole.cout(Konsole.FC_CYAN, "Service type: " + service_java); + Konsole.cout(Konsole.FC_CYAN, "Service implement type: " + serviceImpl_java); + Konsole.cout(Konsole.FC_CYAN, "Comment: \n" + GenComment()); + Konsole.cout(Konsole.FC_CYAN, "Function define: \n" + GenFuncDef()); + Konsole.cout(Konsole.FC_CYAN, "Function declare: \n" + GenFuncDecl()); + } + + public boolean IsValid() + { + return StrUtil.isNotEmpty(queryId) + && StrUtil.isNotEmpty(entity) + && StrUtil.isNotEmpty(module) + && StrUtil.isNotEmpty(queryId) + // && StrUtil.isNotEmpty(returnType) + // && CollectionUtil.isNotEmpty(parameterType) + ; + } + + private boolean CheckFile() + { + File file = new File(mapper_java); + if(!file.isFile()) return false; + file = new File(service_java); + if(!file.isFile()) return false; + file = new File(serviceImpl_java); + if(!file.isFile()) return false; + return true; + } + + private String GenFuncDef() + { + String str = String.format("\tpublic %s %s(%s);", returnType, queryId, GenParameterStr(1 | 2)); + return str; + } + + private String GenFuncDecl() + { + String mapperProp = StrUtil.lowerFirst(entity) + "Mapper"; + + String str = String.format("\t@Override\n\tpublic %s %s(%s)\n\t{\n\t\treturn %s.%s(%s);\n\t}" + , returnType, queryId, GenParameterStr(1 | 2), mapperProp, queryId, GenParameterStr(2)); + return str; + } + + public String GenMapperCode() + { + StringBuilder sb = new StringBuilder(); + String commentStr = GenComment(); + if(StrUtil.isNotEmpty(commentStr)) + commentStr += "\n"; + String funcDef = commentStr + GenFuncDef(); + sb.append(funcDef); + return sb.toString(); + } + + public String GenServiceCode() + { + return GenMapperCode(); + } + + public String GenServiceImplCode() + { + StringBuilder sb = new StringBuilder(); + String commentStr = GenComment(); + if(StrUtil.isNotEmpty(commentStr)) + commentStr += "\n"; + String funcDecl = commentStr + GenFuncDecl(); + sb.append(funcDecl); + return sb.toString(); + } + + private boolean AppendFile(String content, String path) + { + File file = new File(path); + String source = FileUtil.readUtf8String(file); + StringBuilder sb = new StringBuilder(source); + int index = sb.lastIndexOf("}"); + if(index == -1) + return false; + sb.insert(index, "\n" + content + "\n"); + String newSource = sb.toString(); + FileUtil.writeUtf8String(newSource, file); + return true; + } + + public String GenComment() + { + if(StrUtil.isEmpty(comment)) + return ""; + StringBuilder sb = new StringBuilder(); + sb.append("\t/**\n") + .append("\t * ").append(comment).append("\n") + .append("\t *\n"); + if(null != parameterType) + { + parameterType.forEach((k, v) -> { + sb.append("\t * @param ").append(k).append(" ").append(v).append("\n"); + }); + } + sb.append("\t * @return 结果 ").append(returnType).append("\n") + .append("\t */"); + + return sb.toString(); + } + + public boolean Write() + { + Konsole.cout(Konsole.FC_GREEN, "Start......"); + if(!CheckFile()) + { + Konsole.cerr(Konsole.BC_YELLOW | Konsole.S_BG_ENABLED, "File not exists!"); + return false; + } + Konsole.cout(Konsole.FC_GREEN, String.format("Handle mapper(%s)......", mapper_java)); + AppendFile(GenMapperCode(), mapper_java); + Konsole.cout(Konsole.FC_GREEN, String.format("Handle service(%s)......", service_java)); + AppendFile(GenServiceCode(), service_java); + Konsole.cout(Konsole.FC_GREEN, String.format("Handle serviceImpl(%s)......", serviceImpl_java)); + AppendFile(GenServiceImplCode(), serviceImpl_java); + Konsole.cout(Konsole.FC_GREEN, "Done!"); + return true; + } + + public void Reset() + { + queryId = ""; + entity = ""; + module = ""; + packageName = ""; + comment = ""; + parameterType = null; + returnType = ""; + mapper_java = ""; + service_java = ""; + serviceImpl_java = ""; + } + + private boolean Run() + { + queryId = WaitIn("Please input Mybatis query id: "); + entity = WaitIn("Please input entity class: "); + module = WaitIn("Please input module: "); + packageName = WaitIn("Please input package name(If empty, using `module`): "); + returnType = ReadReturnType("Please input return type: "); + parameterType = ReadParameterType("Please input parameter type: "); + comment = In("Please input comment: "); + ScanFilePath(); + PrintSummary(); + return Write(); + } + + public static void main(String[] args) + { + SQLQueryFuncGenGUI frame = new SQLQueryFuncGenGUI(); + frame.setVisible(true); + + /*SQLQueryFuncGen gen = new SQLQueryFuncGen(); + gen.Run();*/ + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/SQLQueryFuncGenGUI.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/SQLQueryFuncGenGUI.java new file mode 100644 index 0000000..6f01de4 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/SQLQueryFuncGenGUI.java @@ -0,0 +1,173 @@ +package com.ruoyi.common.utils.dev; + +import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.utils.dev.gui.InputField; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class SQLQueryFuncGenGUI extends JFrame +{ + private SQLQueryFuncGen engine; + private InputField queryId; + private InputField entity; + private InputField module; + private InputField packageName; + private InputField comment; + private InputField parameterType; + private InputField returnType; + private JTextPane result; + private JButton writeBtn; + private ActionListener inputListener = new ActionListener() + { + @Override + public void actionPerformed(ActionEvent e) + { + writeBtn.setEnabled(false); + result.setText(""); + } + }; + + public SQLQueryFuncGenGUI() + { + super(); + engine = new SQLQueryFuncGen(); + Setup(); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setTitle("Mybatis查询代码生成器"); + pack(); + } + + private void Setup() + { + JMenuBar menuBar = new JMenuBar(); + setJMenuBar(menuBar); + JMenu fileMenu = new JMenu("文件"); + JMenuItem menuItem = new JMenuItem("清空"); + menuItem.addActionListener(x -> Reset()); + fileMenu.add(menuItem); + menuItem = new JMenuItem("退出"); + menuItem.addActionListener(x -> System.exit(0)); + fileMenu.add(menuItem); + JMenu otherMenu = new JMenu("其他"); + menuItem = new JMenuItem("关于"); + menuItem.addActionListener(x -> JOptionPane.showMessageDialog(this, "通过Mybatis查询ID自动生成mapper/service/serviceImpl源码", "关于", JOptionPane.INFORMATION_MESSAGE)); + otherMenu.add(menuItem); + menuBar.add(fileMenu); + menuBar.add(otherMenu); + queryId = new InputField("Mybatis查询ID: "); + entity = new InputField("实体类名(短): "); + module = new InputField("模块: "); + packageName = new InputField("包名: "); + parameterType = new InputField("参数类型: "); + returnType = new InputField("返回类型: "); + comment = new InputField("注释: "); + queryId.AddActionListener(inputListener); + entity.AddActionListener(inputListener); + module.AddActionListener(inputListener); + packageName.AddActionListener(inputListener); + comment.AddActionListener(inputListener); + parameterType.AddActionListener(inputListener); + returnType.AddActionListener(inputListener); + queryId.SetToolTipText("例如. selectTHomeapplyYdjfsqList"); + entity.SetToolTipText("例如. THomeapplyYdjfsq"); + module.SetToolTipText("例如. house"); + packageName.SetToolTipText("例如. home(如果和模块名称相同则可为空)"); + comment.SetToolTipText("例如. 查询宅基地申请列表"); + parameterType.SetToolTipText("例如. THomeapplyYdjfsq"); + returnType.SetToolTipText("例如. List"); + Box formPanel = Box.createVerticalBox(); + formPanel.setAutoscrolls(true); + formPanel.add(queryId); + formPanel.add(entity); + formPanel.add(module); + formPanel.add(packageName); + formPanel.add(parameterType); + formPanel.add(returnType); + formPanel.add(comment); + result = new JTextPane(); + JScrollPane scrollPane = new JScrollPane(result); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + result.setFont(Font.getFont(Font.MONOSPACED)); + formPanel.add(scrollPane); + BorderLayout mainLayout = new BorderLayout(); + JPanel panel = new JPanel(); + panel.setLayout(mainLayout); + panel.add(formPanel, BorderLayout.CENTER); + Box toolbar = Box.createHorizontalBox(); + toolbar.add(Box.createHorizontalGlue()); + writeBtn = new JButton("写入"); + writeBtn.addActionListener(e -> Write()); + writeBtn.setEnabled(false); + toolbar.add(writeBtn); + JButton startBtn = new JButton("生成"); + startBtn.addActionListener(e -> Gen()); + toolbar.add(startBtn); + JButton clearBtn = new JButton("清空"); + clearBtn.addActionListener(e -> Reset()); + toolbar.add(clearBtn); + panel.add(toolbar, BorderLayout.SOUTH); + setContentPane(panel); + } + + public String PreviewSourceCode() + { + engine.ScanFilePath(); + if(!engine.IsValid()) + { + JOptionPane.showMessageDialog(this, "缺失必要的信息!", "错误", JOptionPane.ERROR_MESSAGE); + return ""; + } + StringBuilder sb = new StringBuilder(); + sb.append(engine.getMapper_java()).append(": \n"); + sb.append(engine.GenMapperCode()).append("\n\n"); + sb.append(engine.getService_java()).append(": \n"); + sb.append(engine.GenServiceCode()).append("\n\n"); + sb.append(engine.getServiceImpl_java()).append(": \n"); + sb.append(engine.GenServiceImplCode()).append("\n\n"); + return sb.toString(); + } + + private void Reset() + { + engine.Reset(); + queryId.Reset(); + entity.Reset(); + module.Reset(); + packageName.Reset(); + comment.Reset(); + parameterType.Reset(); + returnType.Reset(); + result.setText(""); + writeBtn.setEnabled(false); + } + + private void Write() + { + if(engine.Write()) + { + JOptionPane.showMessageDialog(this, "写入源码文件成功!", "成功", JOptionPane.INFORMATION_MESSAGE); + } + else + { + JOptionPane.showMessageDialog(this, "写入源码文件失败!", "错误", JOptionPane.ERROR_MESSAGE); + } + } + + private void Gen() + { + engine.setQueryId(queryId.Text()); + engine.setEntity(entity.Text()); + engine.setModule(module.Text()); + engine.setPackageName(packageName.Text()); + engine.setComment(comment.Text()); + engine.SetParameterType(parameterType.Text()); + engine.SetReturnType(returnType.Text()); + String code = PreviewSourceCode(); + result.setText(code); + writeBtn.setEnabled(StrUtil.isNotEmpty(code)); + } +} + diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/gui/FileField.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/gui/FileField.java new file mode 100644 index 0000000..8894e4f --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/gui/FileField.java @@ -0,0 +1,220 @@ +package com.ruoyi.common.utils.dev.gui; + +import com.ruoyi.common.utils.StringUtils; + +import javax.swing.*; +import javax.swing.filechooser.FileFilter; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.io.File; +import java.util.List; + +public class FileField extends Box +{ + private String lastPath; + private String path; + private final JTextField textField; + private String filter; + private String name; + private int mode = JFileChooser.FILES_ONLY; + private FileFilter fileFilter = new FileFilter() + { + @Override + public boolean accept(File f) + { + if(f.isFile()) + { + if(StringUtils.isNotEmpty(filter)) + { + return f.getName().endsWith(filter); + } + } + return true; + } + + @Override + public String getDescription() + { + if(StringUtils.isNotEmpty(filter)) + { + return "*" + filter; + } + return null; + } + }; + + public FileField(String name) + { + super(BoxLayout.X_AXIS); + this.name = name; + textField = new JTextField(); + lastPath = System.getProperty("user.dir"); + Setup(); + } + + private void Setup() + { + JLabel l = new JLabel(name); + JButton button = new JButton("选择"); + Dimension labelMinimumSize = l.getMinimumSize(); + Dimension compMinimumSize = textField.getMinimumSize(); + Dimension buttonMinimumSize = button.getMinimumSize(); + labelMinimumSize.width = 128; + l.setHorizontalAlignment(SwingConstants.RIGHT); + l.setMinimumSize(labelMinimumSize); + l.setPreferredSize(labelMinimumSize); + l.setMaximumSize(labelMinimumSize); + compMinimumSize.width = 256; + textField.setMinimumSize(compMinimumSize); + Dimension compPreferredSize = textField.getPreferredSize(); + compPreferredSize.width = 256; + textField.setPreferredSize(compPreferredSize); + buttonMinimumSize.width = 64; + button.setHorizontalAlignment(SwingConstants.CENTER); + button.setMinimumSize(buttonMinimumSize); + button.setPreferredSize(buttonMinimumSize); + button.setMaximumSize(buttonMinimumSize); + this.add(l); + this.add(textField); + this.add(button); + this.setMinimumSize(new Dimension(labelMinimumSize.width + compMinimumSize.width, Math.max(labelMinimumSize.height, compMinimumSize.height))); + this.setMaximumSize(new Dimension(Integer.MAX_VALUE, Math.max(labelMinimumSize.height, compMinimumSize.height))); + button.addActionListener((x) -> OpenFileChooser()); + + textField.setDragEnabled(true); + new DropTarget(textField, DnDConstants.ACTION_COPY_OR_MOVE, new DropTargetAdapter() + { + @Override + public void drop(DropTargetDropEvent dt) + { + try + { + if(dt.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) + { + dt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); + List files = (List)dt.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); + File first = files.get(0); + switch(mode) + { + case JFileChooser.FILES_ONLY: + if(first.isFile()) + { + if(fileFilter.accept(first)) + SetPath(first); + return; + } + break; + case JFileChooser.DIRECTORIES_ONLY: + if(!first.isFile()) + { + SetPath(first); + return; + } + break; + case JFileChooser.FILES_AND_DIRECTORIES: + if(!first.isFile() || fileFilter.accept(first)) + SetPath(first); + return; + } + return; + } + } + catch(Exception e) + { + e.printStackTrace(); + } + dt.rejectDrop(); + } + }); + } + + private void OpenFileChooser() + { + JFileChooser jFileChooser = new JFileChooser(lastPath); + jFileChooser.setDialogTitle("选择" + name); + jFileChooser.addActionListener((x) -> { + File currentDirectory = jFileChooser.getCurrentDirectory(); + if(null != currentDirectory) + lastPath = currentDirectory.getAbsolutePath(); + + if(JFileChooser.APPROVE_SELECTION.equals(x.getActionCommand())) + { + File selectedFile = jFileChooser.getSelectedFile(); + SetPath(selectedFile); + } + }); + jFileChooser.setFileSelectionMode(mode); + jFileChooser.setFileFilter(fileFilter); + jFileChooser.showOpenDialog(this); + } + + public void SetLastPath(String path) + { + if(StringUtils.isEmpty(path)) + lastPath = System.getProperty("user.dir"); + else + { + File file = new File(path); + if(file.exists()) + { + if(!file.isDirectory()) + file = file.getParentFile(); + try + { + lastPath = file.getCanonicalPath(); + } + catch(Exception e) + { + e.printStackTrace(); + lastPath = file.getAbsolutePath(); + } + } + else + lastPath = System.getProperty("user.dir"); + } + } + + private void SetPath(File selectedFile) + { + if(null != selectedFile) + { + path = selectedFile.getAbsolutePath(); + lastPath = selectedFile.getParent(); + } + else + { + path = null; + } + textField.setText(null != path ? path : ""); + } + + public void SetPath(String path) + { + SetPath(StringUtils.isNotEmpty(path) ? new File(path) : null); + } + + public void Reset() + { + path = null; + textField.setText(""); + } + + public String Path() + { + return textField.getText(); + } + + public void SetFilter(String filter) + { + this.filter = filter; + } + + public void SetMode(int mode) + { + this.mode = mode; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/gui/InputField.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/gui/InputField.java new file mode 100644 index 0000000..8b39bcf --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/gui/InputField.java @@ -0,0 +1,69 @@ +package com.ruoyi.common.utils.dev.gui; + +import javax.swing.*; +import java.awt.*; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.event.ActionListener; + +public class InputField extends Box +{ + private final JTextField textField; + private final JLabel label; + + public InputField(String text) + { + super(BoxLayout.X_AXIS); + textField = new JTextField(); + label = new JLabel(text); + Setup(); + } + + private void Setup() + { + Dimension labelMinimumSize = label.getMinimumSize(); + Dimension compMinimumSize = textField.getMinimumSize(); + labelMinimumSize.width = 128; + label.setHorizontalAlignment(SwingConstants.RIGHT); + label.setMinimumSize(labelMinimumSize); + label.setPreferredSize(labelMinimumSize); + label.setMaximumSize(labelMinimumSize); + compMinimumSize.width = 256; + textField.setMinimumSize(compMinimumSize); + Dimension compPreferredSize = textField.getPreferredSize(); + compPreferredSize.width = 256; + textField.setPreferredSize(compPreferredSize); + this.add(label); + this.add(textField); + this.setMinimumSize(new Dimension(labelMinimumSize.width + compMinimumSize.width, Math.max(labelMinimumSize.height, compMinimumSize.height))); + this.setMaximumSize(new Dimension(Integer.MAX_VALUE, Math.max(labelMinimumSize.height, compMinimumSize.height))); + } + + public void SetToolTipText(String str) + { + label.setToolTipText(str); + textField.setToolTipText(str); + } + + public void AddActionListener(ActionListener l) + { + textField.addActionListener(l); + } + + public void Reset() + { + textField.setText(""); + } + + public String Text() + { + return textField.getText(); + } + + public JTextField TextField() + { + return textField; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/MybatisStdOutputLog.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/MybatisStdOutputLog.java new file mode 100644 index 0000000..a73683e --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/MybatisStdOutputLog.java @@ -0,0 +1,113 @@ +package com.ruoyi.common.utils.dev.mybatis; + +import com.ruoyi.common.utils.dev.Konsole; +import org.apache.ibatis.logging.Log; + +import static java.lang.System.out; +import static java.lang.System.err; + +public class MybatisStdOutputLog implements Log { + private String mapperStatement; + private boolean disable = false; + + private final static boolean ENABLE_OUTPUT = true; + + static final int SQL_START_STYLE = Konsole.GenStyle(Konsole.FC_BLACK, Konsole.FS_BOLD, Konsole.BC_YELLOW, Konsole.S_BG_ENABLED); + static final int SQL_STATEMENT_STYLE = Konsole.GenStyle(Konsole.FC_BLUE, Konsole.FS_BOLD); + static final int SQL_PARAMETER_STYLE = Konsole.GenStyle(Konsole.FC_CYAN, Konsole.FS_BOLD); + static final int SQL_RESULT_STYLE = Konsole.GenStyle(Konsole.FC_PURPLE, Konsole.FS_BOLD, Konsole.BC_YELLOW, Konsole.S_BG_ENABLED); + static final int SQL_ROWS_STYLE = Konsole.GenStyle(Konsole.FC_GREEN); + static final int SQL_COLUMNS_STYLE = Konsole.GenStyle(Konsole.FC_YELLOW, Konsole.FS_BOLD); + static final int SQL_STYLE = Konsole.GenStyle(Konsole.FC_RED); + + // 不输出的查询 + private static final String[] UnhandleClass = { + "org.activiti.engine.impl.persistence.entity.JobEntityImpl.selectJobsToExecute", + "org.activiti.engine.impl.persistence.entity.TimerJobEntityImpl.selectTimerJobsToExecute", + "org.activiti.engine.impl.persistence.entity.JobEntityImpl.selectExpiredJobs", + }; + + public MybatisStdOutputLog(String clazz) { + SetMapperStatement(clazz); + } + + private void SetMapperStatement(String clazz) + { + mapperStatement = clazz; + for(String unhandleClass : UnhandleClass) + { + if(unhandleClass.equals(mapperStatement)) + disable = true; + } + } + + public boolean isDebugEnabled() { + return ENABLE_OUTPUT && !disable; + } + + public boolean isTraceEnabled() { + return ENABLE_OUTPUT && !disable; + } + + public void error(String s, Throwable e) { + SQLQueue.Exception(mapperStatement, s, e); + } + + public void error(String s) { + SQLQueue.Error(mapperStatement, s); + } + + public void debug(String s) { + SQLQueue.Debug(mapperStatement, s); + } + + public void trace(String s) { + SQLQueue.Trace(mapperStatement, s); + } + + public void warn(String s) { + SQLQueue.Warning(mapperStatement, s); + } + + static void cout(String str) + { + out.println(str); + } + + static void cerr(String str) + { + err.println(str); + } + + static void clog(String str) + { + } + + static void cout() + { + out.println(); + } + + static void cerr() + { + err.println(); + } + + static void clog() + { + } + + static void cout(String str, int style) + { + out.println(Konsole.MakeText(str, style)); + } + + static void cerr(String str, int style) + { + err.println(Konsole.MakeText(str, style)); + } + + static void clog(String str, int style) + { + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/SQLQuery.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/SQLQuery.java new file mode 100644 index 0000000..cc55541 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/SQLQuery.java @@ -0,0 +1,275 @@ +package com.ruoyi.common.utils.dev.mybatis; + +import java.util.ArrayList; +import java.util.List; + +import static java.lang.System.out; + +public class SQLQuery +{ + private static class Error + { + public final String log; + public final Throwable e; + + public Error(String log, Throwable e) + { + this.log = log; + this.e = e; + } + } + + private String mapper; + private String sql; + private String parms; + private String columns; + private long result; + private final List warnings; + private final List rows; + private final List errors; + private long counter; + private long takeTime; + private long readRows; + private long startTime; + private long effect; + + private static final int OUTPUT_ROWS = 5; // -1: not limit, 0: disable, positive number: max + private static final Object LOCK = new Object(); + + public SQLQuery() + { + warnings = new ArrayList<>(); + rows = new ArrayList<>(); + errors = new ArrayList<>(); + Clear(); + } + + public void Clear() + { + sql = ""; + parms = ""; + columns = ""; + result = -1; + readRows = 0; + takeTime = 0; + effect = -1; + startTime = System.currentTimeMillis(); + warnings.clear(); + rows.clear(); + errors.clear(); + } + + public void Mapper(String mapper) + { + this.mapper = mapper; + } + + public void Debug(String mapper, String log) + { + Add(mapper, log); + } + + public void Trace(String mapper, String log) + { + Add(mapper, log); + } + + public void Warning(String mapper, String log) + { + warnings.add(log); + Mapper(mapper); + } + + public void Error(String mapper, String log) + { + AddError(log, null); + Mapper(mapper); + } + + public void Exception(String mapper, String log, Throwable e) + { + AddError(log, e); + Mapper(mapper); + } + + private void AddError(String log, Throwable e) + { + errors.add(new Error(log, e)); + } + + private void AddOther(String log) + { + // other.add(log); + } + + private void SetResult(String log) + { + String s = log.substring("<== Total: ".length()); + int index = s.lastIndexOf("<-- ["); + if(index >= 0) + s = s.substring(0, index); + s = s.trim(); + try + { + result = Long.parseLong(s); + } + catch(Exception e) + { + e.printStackTrace(); + } + if(result <= 0 || result == readRows) + EndQuery(); + } + + private void SetEffect(String log) + { + String s = log.substring("<== Updates: ".length()); + try + { + effect = Long.parseLong(s); + } + catch(Exception e) + { + e.printStackTrace(); + } + EndQuery(); + } + + private void EndQuery() + { + long l = System.currentTimeMillis(); + takeTime = l - startTime; + + Output(); + } + + private void AddRow(String log) + { + if(OUTPUT_ROWS < 0 || readRows < OUTPUT_ROWS) + rows.add(log.substring("<== Row: ".length())); + readRows++; + if(readRows == result) + EndQuery(); + } + + public void Output() + { + if(null == sql || sql.isEmpty()) + return; + synchronized(LOCK) { + MybatisStdOutputLog.cout(); + String action = "查询"; + if(effect >= 0) + action = "更新"; + + // SQL + MybatisStdOutputLog.cout("[Mybatis " + action + " ] " + Thread.currentThread().getName() + ": " + counter + " -> " + mapper, MybatisStdOutputLog.SQL_START_STYLE); + MybatisStdOutputLog.cout(sql, MybatisStdOutputLog.SQL_STATEMENT_STYLE); + if(null != parms && !parms.isEmpty()) + MybatisStdOutputLog.cout(parms, MybatisStdOutputLog.SQL_PARAMETER_STYLE); + + SQLStatement sqlStatement = new SQLStatement(sql, parms); + String parsedSql = sqlStatement.Parse(); + if(null != parsedSql) + MybatisStdOutputLog.cout(/*"编译SQL: \n" + */parsedSql, MybatisStdOutputLog.SQL_STYLE); + + // Select query + if(result >= 0) + { + MybatisStdOutputLog.cout("结果行数: " + result, MybatisStdOutputLog.SQL_RESULT_STYLE); + MybatisStdOutputLog.cout(columns, MybatisStdOutputLog.SQL_COLUMNS_STYLE); + int size = rows.size(); + if(OUTPUT_ROWS != 0 && size > 0) + { + for(int i = 0; i < size; i++) + { + MybatisStdOutputLog.cout(String.format("%5d", i) + ": " + rows.get(i), MybatisStdOutputLog.SQL_ROWS_STYLE); + } + long remain = readRows - size; + if(remain > 0) + MybatisStdOutputLog.cout("更多 : " + remain + "条数据......", MybatisStdOutputLog.SQL_ROWS_STYLE); + } + } + // Update + if(effect >= 0) + { + MybatisStdOutputLog.cout("影响行数: " + effect, MybatisStdOutputLog.SQL_RESULT_STYLE); + } + + // Warning + if(!warnings.isEmpty()) + { + MybatisStdOutputLog.cout("警告: " + warnings.size(), MybatisStdOutputLog.SQL_RESULT_STYLE); + for(int i = 0; i < warnings.size(); i++) + { + MybatisStdOutputLog.cout(String.format("%2d", i) + ": " + warnings.get(i), MybatisStdOutputLog.SQL_ROWS_STYLE); + } + } + + // Error / Exception + if(!errors.isEmpty()) + { + MybatisStdOutputLog.cout("错误: " + errors.size(), MybatisStdOutputLog.SQL_RESULT_STYLE); + for(int i = 0; i < errors.size(); i++) + { + Error error = errors.get(i); + MybatisStdOutputLog.cout(String.format("%2d", i) + ": " + error.log, MybatisStdOutputLog.SQL_ROWS_STYLE); + error.e.printStackTrace(out); + } + } + //MybatisStdOutputLog.cout("[Mybatis 结束 ] " + Thread.currentThread().getName() + ": " + counter + " -> Time(" + takeTime + " ms) " + mapper + " ---------------------------------------------------------", MybatisStdOutputLog.SQL_START_STYLE); + MybatisStdOutputLog.cout(""); + } + Clear(); + } + + private void Add(String mapper, String log) + { + if(log.startsWith("==>")) { + if(log.startsWith("==> Preparing: ")) + { + counter++; + Mapper(mapper); + sql = log.substring("==> Preparing: ".length()); + } + else if(log.startsWith("==> Parameters: ")) + { + parms = log.substring("==> Parameters: ".length()); + int index = parms.lastIndexOf("<-- ["); + if(index >= 0) + parms = parms.substring(0, index); + parms = parms.trim(); + } + else + { + AddOther(log); + } + } + else if(log.startsWith("<==")) { + if(log.startsWith("<== Columns: ")) + { + columns = log.substring("<== Columns: ".length()); + } + else if(log.startsWith("<== Total: ")) + { + SetResult(log); + } + else if(log.startsWith("<== Row: ")) + { + AddRow(log); + } + else if(log.startsWith("<== Updates: ")) + { + SetEffect(log); + } + else + { + AddOther(log); + } + } + else + { + AddOther(log); + } + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/SQLQueue.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/SQLQueue.java new file mode 100644 index 0000000..7889cb4 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/SQLQueue.java @@ -0,0 +1,55 @@ +package com.ruoyi.common.utils.dev.mybatis; + +public class SQLQueue +{ + private static final ThreadLocal _state = new ThreadLocal<>(); + + private static SQLQuery SQLQUERY() + { + SQLQuery sqlQuery = _state.get(); + if(null == sqlQuery) + { + sqlQuery = new SQLQuery(); + _state.set(sqlQuery); + } + return sqlQuery; + } + + public static void Error(String mapper, String log) + { + if(log == null || log.isEmpty()) + return; + SQLQUERY().Error(mapper, log); + } + + public static void Debug(String mapper, String log) + { + if(log == null || log.isEmpty()) + return; + SQLQUERY().Debug(mapper, log); + } + + public static void Trace(String mapper, String log) + { + if(log == null || log.isEmpty()) + return; + SQLQUERY().Trace(mapper, log); + } + + public static void Warning(String mapper, String log) + { + if(log == null || log.isEmpty()) + return; + SQLQUERY().Warning(mapper, log); + } + + public static void Exception(String mapper, String log, Throwable e) + { + if(log == null || log.isEmpty()) + return; + if(null != e) + SQLQUERY().Exception(mapper, log, e); + else + SQLQUERY().Error(mapper, log); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/SQLStatement.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/SQLStatement.java new file mode 100644 index 0000000..b105f1d --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/dev/mybatis/SQLStatement.java @@ -0,0 +1,143 @@ +package com.ruoyi.common.utils.dev.mybatis; + +import java.math.BigDecimal; +import java.text.NumberFormat; + +public class SQLStatement +{ + public final String sql; + public final String arguments; + + public SQLStatement(String sql, String arguments) + { + this.sql = sql; + this.arguments = arguments; + } + + public String Parse() + { + String str; + if(null == arguments || arguments.isEmpty()) + str = sql; + else + { + String[] args = ParseArguments(); + str = ReplacePlaceholder(args); + } + return Format(str); + } + + private String[] ParseArguments() + { + String[] split = (arguments + ", ").split("\\(\\w+\\), "); + return split; + } + + private String ReplacePlaceholder(String[] args) + { + try + { + int lastIndex = 0; + int i = 0; + StringBuilder sb = new StringBuilder(); + int length = sql.length(); + while(lastIndex < length) + { + int index = sql.indexOf('?', lastIndex); + if(i < args.length && index >= 0) + { + String str = sql.substring(lastIndex, index); + sb.append(str); + sb.append(ToStr(args[i++])); + lastIndex = index + 1; + } + else + { + String str = sql.substring(lastIndex); + sb.append(str); + lastIndex = length; + } + } + return sb.toString(); + } + catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + + private String ReplacePlaceholder_rev(String[] args) + { + try + { + int lastIndex = sql.length() - 1; + int i = args.length - 1; + StringBuilder sb = new StringBuilder(); + while(lastIndex >= 0) + { + int index = sql.lastIndexOf('?', lastIndex); + if(i >= 0 && index >= 0) + { + String str = sql.substring(index + 1, lastIndex + 1); + sb.insert(0, str); + sb.insert(0, "'" + args[i--] + "'"); + lastIndex = index - 1; + } + else + { + String str = sql.substring(0, lastIndex + 1); + sb.insert(0, str); + lastIndex = -1; + } + } + return sb.toString(); + } + catch(Exception e) + { + e.printStackTrace(); + return null; + } + } + + private String Format(String sql) + { + if(null == sql) + return null; + sql = sql.trim(); + if(!sql.endsWith(";")) + sql = sql + ";"; + return sql; + } + + private static String ToStr(String arg) + { + if(arg == null) + return "null"; + else if(arg.isEmpty()) + return "''"; + else if(IsNum(arg)) + return arg; + else + return "'" + arg + "'"; + } + + // 10 + private static boolean IsNum(String str) + { + if(null == str || str.isEmpty()) + return false; + try + { + boolean matches = str.matches("^[\\d.-]*$"); + if(!matches) + return false; + Double.parseDouble(str); + return true; + } + catch(Exception e) + { + return false; + } + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/translation/Translate.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/translation/Translate.java new file mode 100644 index 0000000..3173f42 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/translation/Translate.java @@ -0,0 +1,62 @@ +package com.ruoyi.common.utils.translation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 额外字典翻译字段注解, 用来代替无法使用Excel注解的情况, 优先级大于Excel注解 + * 优先级(5种): + * sql [+ referenceProperty]: 单条SQL语句: 建议加上LIMIT 1, 多条时取第一条, 必须指定占位符?. 例如: @Translate(sql = "SELECT * FROM t_finance_book WHERE id = ? LIMIT 1") + * table + tableKeyColumn + tableValueColumn [+ referenceProperty]: 拼接为 SELECT `tableValueColumn` FROM `table` WHERE `tableKeyColumn` = ? LIMIT 1. 例如: @Translate(table = "t_finance_book", tableValueColumn = "book_name", tableKeyColumn = "id") + * + * dictSql + tableKeyColumn + tableValueColumn: 执行查询SQL后, 取tableKeyColumn(), tableValueColumn()作为字典键值. 例如: @Translate(dictSql = "SELECT * FROM t_finance_book", tableValueColumn = "book_name", tableKeyColumn = "id") + * readConverterExp + * dictType + * + * 前两种方式使用待翻译字段值直查 + * 后三种都是加载对应键值字典, 然后用待翻译字段值匹配. 如果都指定了, 会按优先级混合在一起, 优先级高的覆盖优先级低的 + * + * 关于referenceProperty + * 如果带翻译字段为Long的其他表ID, 如: + * private Long bookId; + * 如果需要翻译bookId + * 一种方法是将bookId设为String类型 + * 还有一种方法是声明String类型的属性辅助翻译bookId, 该新属性不需要原来本身就有bookId的值, 如 + * @Translate(table = "t_finance_book", tableKeyColumn = "id", tableValueColumn = "book_name", referenceProperty = "bookId") // 引用bookId属性的值 + * // @Translate(sql = "SELECT * FROM t_finance_book WHERE id = ? LIMIT 1", referenceProperty = "bookId") // 也可以写成这样 + * private String bookName; // bookName的值不需要读取, 只写入 + * private Long typeId; + * @Translate(dictType = "dict_xxx_type", referenceProperty = "typeId") // 引用typeId属性的值 + * private String typeName; // typeName的值不需要读取, 只写入 + * + * @author zhao + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Translate +{ + /** + * 如果是字典类型,请设置字典的type值 (如: sys_user_sex) + */ + public String dictType() default ""; + + /** + * 读取内容转表达式 (如: 0=男,1=女,2=未知) + */ + public String readConverterExp() default ""; + + // 查询数据库字典, 字段必须为String, 不能为Long/Integer等数字型 + // 方式1: SQL, ?号占位 + public String sql() default ""; + // 方式2: 表名 + 对应列名 + 名称列 + // 拼接为 SELECT tableValueColumn() FROM table() WHERE tableKeyColumn() = ? LIMIT 1 + public String table() default ""; // 表名 + public String tableKeyColumn() default "id"; // 键的列名 + public String tableValueColumn() default "name"; // 值的列名 + public String referenceProperty() default ""; // 引用其他类成员属性 + // 方式3: SQL + 对应列名 + 名称列: 无占位符, 从数据库加载键值对 + // 执行查询SQL后, 取tableKeyColumn(), tableValueColumn()作为字典键值 + public String dictSql() default ""; +} \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/translation/TranslateUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/translation/TranslateUtils.java new file mode 100644 index 0000000..24b3634 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/translation/TranslateUtils.java @@ -0,0 +1,66 @@ +package com.ruoyi.common.utils.translation; + +import com.ruoyi.common.core.domain.BaseEntity; + +import java.util.List; +import java.util.Map; + +/** + * zhao: 字段自动字典翻译 + * 需要翻译的字段必须使用Translate注解或Excel注解标记 + * 优先级: + * 注解: Translate优先级大于Excel. 只会使用Translate或Excel其中的一种, 不会混合 + * 注解属性: readConverterExp优先级大于dictType. readConverterExp和dictType的键值对最终会混合在一起 + * 字段类型: + * 如果是String类型, 必须赋值注解的dictType或readConverterExp + * 如果是其他复合类型/List, 无需赋值dictType或readConverterExp, 仅标记注解即可, 此时将递归翻译(注意不要循环嵌套对象) + * + * 数据库表数据字典: 仅Translate注解支持 + * 字段必须为String类型 + */ +public final class TranslateUtils +{ + private TranslateUtils() {} + + public static void translateList(List list, Object...args) + { + new Translator().translateList(list, args); + } + + public static void translate(Object obj, Object...args) + { + new Translator().translate(obj, args); + } + + public static void translateMapList(List> list, Map dictMap) + { + new Translator().translateMapList(list, dictMap); + } + + public static void translateMap(Map map, Map dictMap) + { + new Translator().translateMap(map, dictMap); + } + + public static void translateObjectList(List list) + { + new Translator().translateObjectList(list); + } + + public static void translateObject(T object) + { + new Translator().translateObject(object); + } + + public static void translateEntityList(List list, boolean...keepRawField) + { + boolean b = null != keepRawField && keepRawField.length > 0 ? keepRawField[0] : false; + new Translator().translateEntityList(list, b); + } + + public static void translateEntity(T object, boolean...keepRawField) + { + boolean b = null != keepRawField && keepRawField.length > 0 ? keepRawField[0] : false; + new Translator().translateEntity(object, b); + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/translation/Translator.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/translation/Translator.java new file mode 100644 index 0000000..ee1b9e5 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/translation/Translator.java @@ -0,0 +1,578 @@ +package com.ruoyi.common.utils.translation; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.util.StrUtil; +import com.ruoyi.common.annotation.Excel; +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.domain.entity.SysDictData; +import com.ruoyi.common.utils.DictUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.reflect.ReflectUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public final class Translator +{ + private static final String KEY_SQL_KEY = "$__SQL__"; + + private final List handledObjects = new ArrayList<>(); + + public Translator() {} + + public void translateList(List list, Object...args) + { + if(CollectionUtil.isEmpty(list)) + return; + if(startTranslate(list)) + list.forEach((x) -> translate(x, args)); + } + + @SuppressWarnings("unchecked") + public void translate(Object obj, Object...args) + { + if(null == obj) + return; + if(obj instanceof BaseEntity) + { + Object o = DEF_PARM(args); + boolean b = o instanceof Boolean ? (Boolean)o : false; + translateEntity((BaseEntity)obj, b); + } + else if(obj instanceof Map) + { + Object o = DEF_PARM(args); + Map dictMap = o instanceof Map ? (Map)args[0] : null; + translateMap((Map)obj, dictMap); + } + else if(obj instanceof List) + { + translateList((List)obj, args); + } + else + { + translateObject(obj); + } + } + + public void translateEntityList(List list, boolean keepRawField) + { + if(CollectionUtil.isEmpty(list)) + return; + list.forEach((x) -> translateEntity(x, keepRawField)); + } + + public void translateEntity(T object, boolean keepRawField) + { + if(null == object) + return; + translateEntity_r(object, object.getClass(), keepRawField); + } + + public void translateMapList(List> list, Map dictMap) + { + if(CollectionUtil.isEmpty(list)) + return; + list.forEach((x) -> translateMap(x, dictMap)); + } + + public void translateMap(Map map, Map dictMap) + { + if(CollectionUtil.isEmpty(map) || CollectionUtil.isEmpty(dictMap)) + return; + if(!startTranslate(map)) + return; + dictMap.forEach((k, v) -> { + if(!map.containsKey(k)) + return; + Object o = map.get(k); + if(null == o) + return; + Class clazz = o.getClass(); + if(clazz.equals(String.class)) + { + String str = (String)o; + if(StringUtils.isEmpty(str)) + return; + map.put(k, getDictLabelElseOriginValue(v, str)); + } + else if(canRecursionClassObjectField(clazz)) + translate(o, dictMap); + }); + } + + // 判断是否翻译对象属性 + private boolean canRecursionClassObjectField(Class clazz) + { +/* if(Object.class.equals(clazz)) // is Object class + return false; + if(!Object.class.isAssignableFrom(clazz)) // is internal class, e.g. int long boolean + return false; + if(clazz.getPackage().getName().startsWith("java.lang")) // class in java.lang.**, e.g. Long Integer + return false; + return true;*/ + return BaseEntity.class.isAssignableFrom(clazz) // BaseEntity + || List.class.isAssignableFrom(clazz) // List + || Map.class.isAssignableFrom(clazz) // Map + ; + } + + public void translateObjectList(List list) + { + if(CollectionUtil.isEmpty(list)) + return; + list.forEach(this::translateObject); + } + + public void translateObject(T object) + { + if(null == object) + return; + translateObject_r(object, object.getClass()); + } + + private void translateObject_r(T object, Class clazz) + { + if(!startTranslate(object)) + return; + Field[] declaredFields = clazz.getDeclaredFields(); + for(Field field : declaredFields) + { + boolean trans = hasTranslateFlag(field); // check translate flag + if(!trans) + continue; + translateField(field, object); + } + Class superclass = getSuperClass(clazz); + if(null != superclass) + translateObject_r(object, superclass); + } + + private void translateEntity_r(T object, Class clazz, boolean keepRawField) + { + if(!startTranslate(object)) + return; + + Field[] declaredFields = clazz.getDeclaredFields(); + for(Field field : declaredFields) + { + boolean trans = hasTranslateFlag(field); // check translate flag + if(!trans) + continue; + translateField(field, object, keepRawField); + } + Class superclass = getSuperClass(clazz); + if(null != superclass) + translateEntity_r(object, superclass, keepRawField); + } + + // 解析readConverterExp + private Map parseReadConverterExp(String str) + { + Map dict = new LinkedHashMap<>(); + if(StringUtils.isNotEmpty(str)) + { + List split = StrUtil.split(str, ',', true, true); + split.forEach((x) -> { + List arr = StrUtil.split(x, '=', 2, true, true); + if(CollectionUtil.isEmpty(arr)) + return; + dict.put(arr.get(0), arr.size() > 1 ? arr.get(1) : null); + }); + } + return dict; + } + + // 读取数据库数据作为字典 + private Map loadDBDict(String sql, String keyColumn, String nameColumn) + { + Map dict = new LinkedHashMap<>(); + if(StringUtils.isNotEmpty(sql) && StringUtils.isNotEmpty(keyColumn) && StringUtils.isNotEmpty(nameColumn)) + { + JdbcTemplate jdbcTemplate = SpringUtils.getBean(JdbcTemplate.class); + try + { + List> list = jdbcTemplate.queryForList(sql); + if(CollectionUtil.isNotEmpty(list)) + { + for(Map map : list) + { + String key = toString_s(map.get(keyColumn)); + if(StringUtils.isEmpty(key)) + continue; + dict.put(key, toString_s(map.get(nameColumn))); + } + } + } + catch(Exception e) + { + e.printStackTrace(); + } + } + return dict; + } + + // 生成查询SQL + private String genRelationSQL(String table, String keyColumn, String nameColumn) + { + if(StringUtils.isNotEmpty(table) && StringUtils.isNotEmpty(keyColumn) && StringUtils.isNotEmpty(nameColumn)) + { + return String.format("SELECT `%s` FROM `%s` WHERE `%s` = ? LIMIT 1", nameColumn, table, keyColumn); + } + return null; + } + + // 直接取SQL值 + private String readDBValue(String sql, String id) + { + if(StringUtils.isNotEmpty(sql) && StringUtils.isNotEmpty(id)) + { + JdbcTemplate jdbcTemplate = SpringUtils.getBean(JdbcTemplate.class); + try + { + List> list = jdbcTemplate.queryForList(sql, id); + if(CollectionUtil.isNotEmpty(list)) + { + Map map = list.get(0); + return toString_s(map.get(map.keySet().iterator().next())); + } + } + catch(Exception e) + { + e.printStackTrace(); + } + } + return null; + } + + // 检查是否需要翻译 + private boolean hasTranslateFlag(Field field) + { + // 静态/不可重赋值 不翻译 + int modifiers = field.getModifiers(); + if(Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) + return false; + + return null != field.getAnnotation(Translate.class) || null != field.getAnnotation(Excel.class); + } + + // 获取翻译来源 + // 返回: dictType对应的字典键值对和readConverterExp解析后的键值对的组合 + // 优先级: Translate > Excel | readConverterExp > dictType + private Map getTranslateDict(Field field) + { + Map dict = new LinkedHashMap<>(); + String str; + + Translate translate = field.getAnnotation(Translate.class); // First check Translate annotation + if(null != translate) + { + // 1. SQL 直查 + str = translate.sql(); + if(StringUtils.isNotEmpty(str)) + { + dict.put(KEY_SQL_KEY, str); + } + // 2. table + tableKeyColumn + tableValueColumn 直查 + str = translate.table(); + if(StringUtils.isNotEmpty(str)) + { + str = genRelationSQL(str, translate.tableKeyColumn(), translate.tableValueColumn()); + dict.put(KEY_SQL_KEY, str); + } + + // 3. dict缓存 + str = translate.dictType(); + if(StringUtils.isNotEmpty(str)) + { + dict.putAll(dictCacheValueLabelMap(str)); + } + // 4. readConverterExp配置 + str = translate.readConverterExp(); + if(StringUtils.isNotEmpty(str)) + { + dict.putAll(parseReadConverterExp(str)); + } + // 5. 数据库任意表数据 + str = translate.dictSql(); + if(StringUtils.isNotEmpty(str)) + { + dict.putAll(loadDBDict(str, translate.tableKeyColumn(), translate.tableValueColumn())); + } + } + if(StringUtils.isNotEmpty(dict)) + return dict; + + Excel excel = field.getAnnotation(Excel.class); // And then check Excel annotation + if(null != excel) + { + str = excel.dictType(); + if(StringUtils.isNotEmpty(str)) + { + dict.putAll(dictCacheValueLabelMap(str)); + } + str = excel.readConverterExp(); + if(StringUtils.isNotEmpty(str)) + { + dict.putAll(parseReadConverterExp(str)); + } + } + return dict; + } + + private boolean translateField(Field field, Object object) + { + if(field.getType().equals(String.class)) + return translateField_String(field, object); + else + return translateField_Object(field, object); + } + + private boolean translateField_Object(Field field, Object object) + { + if(field.getType().equals(String.class)) + return false; + + if(!canRecursionClassObjectField(field.getType())) + return false; + + Object val = null; + if(!field.isAccessible()) + field.setAccessible(true); + try + { + val = field.get(object); + } + catch(IllegalAccessException e) + { + e.printStackTrace(); + } + if(null != val) + { + translate(val); + return true; + } + return false; + } + + private boolean translateField_String(Field field, Object object) + { + boolean trans = false; + + if(!field.getType().equals(String.class)) + return false; + + Map dict = getTranslateDict(field); + if(CollectionUtil.isEmpty(dict)) + return false; + + if(!field.isAccessible()) + field.setAccessible(true); + try + { + Object val = getField(object, field); + if(null != val) + { + String str = (String)val; + if(StringUtils.isNotEmpty(str)) + { + if(dict.containsKey(KEY_SQL_KEY)) + { + String dbVal = readDBValue(dict.get(KEY_SQL_KEY), str); + if(StringUtils.isNotEmpty(dbVal)) + { + field.set(object, dbVal); + trans = true; + } + } + if(!trans && dict.containsKey(str)) + { + field.set(object, dict.get(str)); + trans = true; + } + } + } + } + catch(IllegalAccessException e) + { + e.printStackTrace(); + return false; + } + return trans; + } + + private boolean translateField(Field field, T entity, boolean keepRawField) + { + if(field.getType().equals(String.class)) + return translateField_String(field, entity, keepRawField); + else + return translateField_Object(field, entity, keepRawField); + } + + private boolean translateField_Object(Field field, T entity, boolean keepRawField) + { + if(field.getType().equals(String.class)) + return false; + + if(!canRecursionClassObjectField(field.getType())) + return false; + + Object val = null; + try + { + val = getField(entity, field); + } + catch(IllegalAccessException e) + { + e.printStackTrace(); + } + if(null != val) + { + translate(val, keepRawField); + return true; + } + return false; + } + + private boolean translateField_String(Field field, T entity, boolean keepRawField) + { + boolean trans = false; + + if(!field.getType().equals(String.class)) + return false; + + Map dict = getTranslateDict(field); + if(CollectionUtil.isEmpty(dict)) + return false; + + try + { + Object val = getField(entity, field); + if(keepRawField) + entity.getParams().put(field.getName(), val); // backup raw value to params + if(null != val) + { + String str = (String)val; + if(StringUtils.isNotEmpty(str)) + { + if(dict.containsKey(KEY_SQL_KEY)) + { + String dbVal = readDBValue(dict.get(KEY_SQL_KEY), str); + if(StringUtils.isNotEmpty(dbVal)) + { + field.set(entity, dbVal); + trans = true; + } + } + if(!trans && dict.containsKey(str)) + { + field.set(entity, dict.get(str)); + trans = true; + } + } + } + } + catch(IllegalAccessException e) + { + e.printStackTrace(); + return false; + } + return trans; + } + + private Object getField(Object obj, Field field) throws IllegalAccessException + { + if(!field.isAccessible()) + field.setAccessible(true); + Translate annotation = field.getAnnotation(Translate.class); + if(null != annotation) + { + String refProp = annotation.referenceProperty(); + if(StringUtils.isNotEmpty(refProp)) + { + Field refField = ReflectUtils.getAccessibleField(obj, refProp); + if(null != refField) + return toString_s(refField.get(obj)); // 转换为String + } + } + return field.get(obj); + } + + private Class getSuperClass(Class clazz) + { + if(null == clazz) + return null; + Class superclass = clazz.getSuperclass(); // translate parent class + if(null != superclass && !superclass.equals(Object.class)) // check is top or is Object + return superclass; + return null; + } + + // 允许翻译则返回true + private boolean startTranslate(Object o) + { + if(null == o) + return false; + if(o instanceof String) // String类型总是重新翻译 + return true; + if(contains_ptr(handledObjects, o)) // 其他类型防止循环递归 + { + return false; + } + handledObjects.add(o); + return true; + } + + public void Reset() + { + handledObjects.clear(); + } + + + public static boolean contains_ptr(Collection list, T target) + { + if(CollectionUtil.isEmpty(list)) + return false; + return list.stream().anyMatch((x) -> x == target); + } + + public static String toString_s(Object obj) + { + if(null == obj) + return ""; + if(obj instanceof String) + return (String)obj; + else + return obj.toString(); + } + + public static T DEF_PARM(T...args) + { + return null != args && args.length > 0 ? args[0] : null; + } + + + public static Map dictCacheValueLabelMap(String key) + { + List dictCache = DictUtils.getDictCache(key); + if(CollectionUtil.isEmpty(dictCache)) + return new LinkedHashMap<>(); // safety + return dictCache.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel, (a, b) -> a, LinkedHashMap::new)); + } + + public static String getDictLabelElseOriginValue(String dictType, String dictValue) + { + if(StringUtils.isEmpty(dictValue)) + return dictValue; + String res = DictUtils.getDictLabel(dictType, dictValue); + return StringUtils.isEmpty(res) ? dictValue : res; + } +} diff --git a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm index 7274018..78ff03e 100644 --- a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm @@ -16,6 +16,8 @@ import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.enums.BusinessType; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; import ${packageName}.domain.${ClassName}; import ${packageName}.service.I${ClassName}Service; import com.ruoyi.common.utils.poi.ExcelUtil; @@ -30,6 +32,7 @@ import com.ruoyi.common.core.page.TableDataInfo; * @author ${author} * @date ${datetime} */ +@Api(tags = "${functionName}") @RestController @RequestMapping("/${moduleName}/${businessName}") public class ${ClassName}Controller extends BaseController @@ -40,6 +43,7 @@ public class ${ClassName}Controller extends BaseController /** * 查询${functionName}列表 */ + @ApiOperation("查询${functionName}列表") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')") @GetMapping("/list") #if($table.crud || $table.sub) @@ -60,6 +64,7 @@ public class ${ClassName}Controller extends BaseController /** * 导出${functionName}列表 */ + @ApiOperation("导出${functionName}列表") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')") @Log(title = "${functionName}", businessType = BusinessType.EXPORT) @PostMapping("/export") @@ -73,6 +78,7 @@ public class ${ClassName}Controller extends BaseController /** * 获取${functionName}详细信息 */ + @ApiOperation("获取${functionName}详细信息") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')") @GetMapping(value = "/get/{${pkColumn.javaField}}") public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField}) @@ -83,9 +89,10 @@ public class ${ClassName}Controller extends BaseController /** * 新增${functionName} */ + @ApiOperation("新增${functionName}") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')") @Log(title = "${functionName}", businessType = BusinessType.INSERT) - @PostMapping(value = "/add") + @PostMapping("/add") public AjaxResult add(@RequestBody ${ClassName} ${className}) { ${className}.setCreateBy(getUsername()); @@ -95,9 +102,10 @@ public class ${ClassName}Controller extends BaseController /** * 修改${functionName} */ + @ApiOperation("修改${functionName}") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')") @Log(title = "${functionName}", businessType = BusinessType.UPDATE) - @PutMapping(value = "/edit") + @PostMapping("/edit") public AjaxResult edit(@RequestBody ${ClassName} ${className}) { ${className}.setUpdateBy(getUsername()); @@ -107,11 +115,12 @@ public class ${ClassName}Controller extends BaseController /** * 删除${functionName} */ + @ApiOperation("删除${functionName}") @PreAuthorize("@ss.hasPermi('${permissionPrefix}:remove')") @Log(title = "${functionName}", businessType = BusinessType.DELETE) - @DeleteMapping(value = "/remove/{${pkColumn.javaField}}") - public AjaxResult remove(@PathVariable ${pkColumn.javaType} ${pkColumn.javaField}) + @PostMapping("/remove/{${pkColumn.javaField}s}") + public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) { - return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField})); + return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s)); } } diff --git a/ruoyi-generator/src/main/resources/vm/java/domain.java.vm b/ruoyi-generator/src/main/resources/vm/java/domain.java.vm index ce4e055..bd51c17 100644 --- a/ruoyi-generator/src/main/resources/vm/java/domain.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/domain.java.vm @@ -3,8 +3,6 @@ package ${packageName}.domain; #foreach ($import in $importList) import ${import}; #end -import lombok.Data; -import lombok.experimental.Accessors; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import com.ruoyi.common.annotation.Excel; @@ -25,8 +23,6 @@ import com.ruoyi.common.core.domain.TreeEntity; #elseif($table.tree) #set($Entity="TreeEntity") #end -@Data -@Accessors(chain = true) public class ${ClassName} extends ${Entity} { private static final long serialVersionUID = 1L; @@ -59,6 +55,24 @@ public class ${ClassName} extends ${Entity} private List<${subClassName}> ${subclassName}List; #end +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + public void set${AttrName}($column.javaType $column.javaField) + { + this.$column.javaField = $column.javaField; + } + + public $column.javaType get${AttrName}() + { + return $column.javaField; + } +#end +#end #if($table.sub) public List<${subClassName}> get${subClassName}List() @@ -72,4 +86,20 @@ public class ${ClassName} extends ${Entity} } #end + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) +#foreach ($column in $columns) +#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]")) +#set($AttrName=$column.javaField) +#else +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#end + .append("${column.javaField}", get${AttrName}()) +#end +#if($table.sub) + .append("${subclassName}List", get${subClassName}List()) +#end + .toString(); + } } diff --git a/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm b/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm index ed144a7..39419f3 100644 --- a/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm @@ -46,14 +46,6 @@ public interface ${ClassName}Mapper */ public int insert${ClassName}Batch(List<${ClassName}> list); - /** - * 批量修改 ${functionName} - * - * @param list ${functionName} - * @return 结果 - */ - public int update${ClassName}Batch(List<${ClassName}> list); - /** * 修改${functionName} * @@ -62,6 +54,14 @@ public interface ${ClassName}Mapper */ public int update${ClassName}(${ClassName} ${className}); + /** + * 批量修改 ${functionName} + * + * @param list ${functionName} + * @return 结果 + */ + public int update${ClassName}Batch(List<${ClassName}> list); + /** * 删除${functionName} * @@ -105,7 +105,6 @@ public interface ${ClassName}Mapper public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField}); #end - // Harm /** * 条件单条查询${functionName} * diff --git a/ruoyi-generator/src/main/resources/vm/java/service.java.vm b/ruoyi-generator/src/main/resources/vm/java/service.java.vm index f2063d6..1221a27 100644 --- a/ruoyi-generator/src/main/resources/vm/java/service.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/service.java.vm @@ -74,8 +74,7 @@ public interface I${ClassName}Service * @return 结果 */ public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField}); - - // Harm + /** * 条件单条查询${functionName} * diff --git a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm index 026aa1f..b2801d7 100644 --- a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm @@ -9,8 +9,6 @@ import com.ruoyi.common.utils.DateUtils; #end import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.apache.commons.collections4.ListUtils; #if($table.sub) import java.util.ArrayList; import com.ruoyi.common.utils.StringUtils; @@ -19,6 +17,8 @@ import ${packageName}.domain.${subClassName}; import ${packageName}.mapper.${ClassName}Mapper; import ${packageName}.domain.${ClassName}; import ${packageName}.service.I${ClassName}Service; +import org.springframework.transaction.annotation.Transactional; +import org.apache.commons.collections4.ListUtils; /** * ${functionName}Service业务层处理 @@ -93,7 +93,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service public int insert${ClassName}Batch(List<${ClassName}> list){ List> splists = ListUtils.partition(list, 50); splists.forEach(splist->{ - ${className}Mapper.insert${ClassName}Batch(splist); + ${className}Mapper.insert${ClassName}Batch(splist); }); return 1; } @@ -133,7 +133,7 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service public int update${ClassName}Batch(List<${ClassName}> list) { List> splists = ListUtils.partition(list, 50); splists.forEach(splist->{ - ${className}Mapper.update${ClassName}Batch(splist); + ${className}Mapper.update${ClassName}Batch(splist); }); return 1; } @@ -200,7 +200,6 @@ public class ${ClassName}ServiceImpl implements I${ClassName}Service } #end - // Harm /** * 单条条件查询${functionName} * diff --git a/ruoyi-generator/src/main/resources/vm/js/api.js.vm b/ruoyi-generator/src/main/resources/vm/js/api.js.vm index 4e876b4..b756fbc 100644 --- a/ruoyi-generator/src/main/resources/vm/js/api.js.vm +++ b/ruoyi-generator/src/main/resources/vm/js/api.js.vm @@ -1,13 +1,5 @@ import request from '@/utils/request' -/* ${functionName} JSON -{ -#foreach ($column in $columns) - "${column.javaField}": "${column.columnComment}"#if($velocityCount != $columns.size()),#end // ${column.javaType} -#end -} -*/ - // 查询${functionName}列表 export function list${BusinessName}(query) { return request({ @@ -20,7 +12,7 @@ export function list${BusinessName}(query) { // 查询${functionName}详细 export function get${BusinessName}(${pkColumn.javaField}) { return request({ - url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, + url: '/${moduleName}/${businessName}/get/' + ${pkColumn.javaField}, method: 'get' }) } @@ -28,7 +20,7 @@ export function get${BusinessName}(${pkColumn.javaField}) { // 新增${functionName} export function add${BusinessName}(data) { return request({ - url: '/${moduleName}/${businessName}', + url: '/${moduleName}/${businessName}/add', method: 'post', data: data }) @@ -37,8 +29,8 @@ export function add${BusinessName}(data) { // 修改${functionName} export function update${BusinessName}(data) { return request({ - url: '/${moduleName}/${businessName}', - method: 'put', + url: '/${moduleName}/${businessName}/edit', + method: 'post', data: data }) } @@ -46,7 +38,7 @@ export function update${BusinessName}(data) { // 删除${functionName} export function del${BusinessName}(${pkColumn.javaField}) { return request({ - url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField}, - method: 'delete' + url: '/${moduleName}/${businessName}/remove/' + ${pkColumn.javaField}, + method: 'post' }) } diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm index a4c64a0..4819c2a 100644 --- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm +++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm @@ -453,7 +453,7 @@ export default { this.reset(); this.getTreeselect(); if (row != null) { - this.form.${treeParentCode} = row.${treeCode}; + this.form.${treeParentCode} = row.${treeParentCode}; } get${BusinessName}(row.${pkColumn.javaField}).then(response => { this.form = response.data; diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm index 6296014..70f39ea 100644 --- a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm +++ b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm @@ -1,3 +1,39 @@ +#macro(GET_CHAR_COLUMN_LENGTH $column)## * 如果表列是char/varchar, 获取其最大字符长度, 否则为空字符串 * 参数: 列 * 结果保存在变量名为 $_char_column_length 字符串型 +#set($_char_column_length="") +#if($column.columnType.startsWith("char") || $column.columnType.startsWith("varchar")) +#set($startLeft=$column.columnType.indexOf("(")) +#if($startLeft != -1) +#set($endRight=$column.columnType.indexOf(")", $startLeft)) +#if($endRight != -1) +#set($startLeft=$startLeft+1) +#set($_char_column_length=$column.columnType.substring($startLeft, $endRight)) +#end +#end +#end +#end## GET_CHAR_COLUMN_LENGTH +#macro(COLUMN_IS_NUMBER $column)## * 检查表列是否是数字型 * 参数: 列 * 结果保存在变量名为 $_column_is_number bool型 +#set($_column_is_number=$column.columnType.startsWith("decimal") || $column.columnType.startsWith("tinyint") || $column.columnType.startsWith("mediumint") || $column.columnType.startsWith("int") || $column.columnType.startsWith("bigint") || $column.columnType.startsWith("smallint")) +#end## COLUMN_IS_NUMBER +#macro(GET_NUMBER_COLUMN_MIN_AND_PRECISION $column)## * 如果表列是数字型, 获取其最小值和浮点数部分精度, 否则为空字符串 * 参数: 列 * 最小值结果保存在变量名为 $_number_column_min 字符串型 * 浮点数部分精度结果保存在变量名为 $_number_column_precision 字符串型 +#set($_number_column_min="") +#set($_number_column_precision="") +#if($column.columnType.contains("unsigned")) +#set($_number_column_min="0") +#end +#set($startLeft=$column.columnType.indexOf("(")) +#if($startLeft != -1) +#set($endRight=$column.columnType.indexOf(")", $startLeft)) +#if($endRight != -1) +#set($startLeft=$startLeft+1) +#set($internalText=$column.columnType.substring($startLeft, $endRight)) +#set($splitIndex=$internalText.indexOf(",")) +#if($splitIndex != -1) +#set($splitIndex=$splitIndex+1) +#set($_number_column_precision=$internalText.substring($splitIndex)) +#end +#end +#end +#end## GET_NUMBER_COLUMN_MIN_AND_PRECISION