first commit
This commit is contained in:
27
ruoyi-modules/pom.xml
Normal file
27
ruoyi-modules/pom.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>xinnengyuan</artifactId>
|
||||
<groupId>org.dromara</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<modules>
|
||||
<module>ruoyi-generator</module>
|
||||
<module>ruoyi-job</module>
|
||||
<module>ruoyi-system</module>
|
||||
<module>ruoyi-workflow</module>
|
||||
<module>ruoyi-app</module>
|
||||
</modules>
|
||||
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<description>
|
||||
ruoyi-modules 业务模块
|
||||
</description>
|
||||
|
||||
</project>
|
112
ruoyi-modules/ruoyi-app/pom.xml
Normal file
112
ruoyi-modules/ruoyi-app/pom.xml
Normal file
@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>ruoyi-app</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-translation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- OSS功能模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-oss</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- excel-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SMS功能模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-sms</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-tenant</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-idempotent</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-sensitive</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-encrypt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-sse</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-jts</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,52 @@
|
||||
package org.dromara.app.system.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.dromara.app.system.domain.dto.menu.AppMenuCreateReq;
|
||||
import org.dromara.app.system.domain.dto.menu.AppMenuUpdateReq;
|
||||
import org.dromara.app.system.service.AppMenuService;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* app菜单信息
|
||||
*
|
||||
* @author lilemy
|
||||
* @date 2025-07-23 15:13
|
||||
*/
|
||||
@Validated
|
||||
@RestController
|
||||
@RequestMapping("/app/system/menu")
|
||||
public class AppMenuController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private AppMenuService appMenuService;
|
||||
|
||||
/**
|
||||
* 新增app菜单信息
|
||||
*/
|
||||
@SaCheckPermission("contractor:contractorToolRecord:add")
|
||||
@Log(title = "app菜单信息", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated @RequestBody AppMenuCreateReq req) {
|
||||
return toAjax(appMenuService.insertByReq(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改app菜单信息
|
||||
*/
|
||||
@SaCheckPermission("contractor:contractorToolRecord:edit")
|
||||
@Log(title = "app菜单信息", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated @RequestBody AppMenuUpdateReq req) {
|
||||
return toAjax(appMenuService.updateByReq(req));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package org.dromara.app.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* app菜单
|
||||
*
|
||||
* @TableName app_menu
|
||||
*/
|
||||
@Data
|
||||
@TableName(value = "app_menu")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class AppMenu extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
private String menuName;
|
||||
|
||||
/**
|
||||
* 父菜单ID
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer orderNum;
|
||||
|
||||
/**
|
||||
* 路由地址
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 组件路径
|
||||
*/
|
||||
private String component;
|
||||
|
||||
/**
|
||||
* 路由参数
|
||||
*/
|
||||
private String queryParam;
|
||||
|
||||
/**
|
||||
* 菜单类型(M目录 C菜单 F按钮)
|
||||
*/
|
||||
private String menuType;
|
||||
|
||||
/**
|
||||
* 显示状态(0显示 1隐藏)
|
||||
*/
|
||||
private String visible;
|
||||
|
||||
/**
|
||||
* 菜单状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 权限标识
|
||||
*/
|
||||
private String perms;
|
||||
|
||||
/**
|
||||
* 菜单图标
|
||||
*/
|
||||
private String icon;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
@Serial
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package org.dromara.app.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* app角色
|
||||
*
|
||||
* @TableName app_role
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "app_role")
|
||||
@Data
|
||||
public class AppRole extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 角色权限字符串
|
||||
*/
|
||||
private String roleKey;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer orderNum;
|
||||
|
||||
/**
|
||||
* 数据范围(1:全部数据权限 2:自定数据权限)
|
||||
*/
|
||||
private String dataScope;
|
||||
|
||||
/**
|
||||
* 角色状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
@Serial
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package org.dromara.app.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* app角色和菜单关联
|
||||
*
|
||||
* @TableName app_role_menu
|
||||
*/
|
||||
@TableName(value = "app_role_menu")
|
||||
@Data
|
||||
public class AppRoleMenu implements Serializable {
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
@TableId(type = IdType.INPUT)
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 菜单ID
|
||||
*/
|
||||
private Long menuId;
|
||||
|
||||
@Serial
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package org.dromara.app.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* app用户和角色关联
|
||||
*
|
||||
* @TableName app_user_role
|
||||
*/
|
||||
@TableName(value = "app_user_role")
|
||||
@Data
|
||||
public class AppUserRole implements Serializable {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableId(type = IdType.INPUT)
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
@Serial
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package org.dromara.app.system.domain.dto.menu;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025-07-23 14:53
|
||||
*/
|
||||
@Data
|
||||
public class AppMenuCreateReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 5959650762623651138L;
|
||||
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
@NotBlank(message = "菜单名称不能为空")
|
||||
private String menuName;
|
||||
|
||||
/**
|
||||
* 父菜单ID
|
||||
*/
|
||||
@NotNull(message = "父菜单不能为空")
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer orderNum;
|
||||
|
||||
/**
|
||||
* 路由地址
|
||||
*/
|
||||
@NotBlank(message = "路由地址不能为空")
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 组件路径
|
||||
*/
|
||||
private String component;
|
||||
|
||||
/**
|
||||
* 路由参数
|
||||
*/
|
||||
private String queryParam;
|
||||
|
||||
/**
|
||||
* 菜单类型(M目录 C菜单 F按钮)
|
||||
*/
|
||||
@NotBlank(message = "菜单类型不能为空")
|
||||
private String menuType;
|
||||
|
||||
/**
|
||||
* 显示状态(0显示 1隐藏)
|
||||
*/
|
||||
private String visible;
|
||||
|
||||
/**
|
||||
* 菜单状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 权限标识
|
||||
*/
|
||||
private String perms;
|
||||
|
||||
/**
|
||||
* 菜单图标
|
||||
*/
|
||||
private String icon;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package org.dromara.app.system.domain.dto.menu;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025-07-23 14:55
|
||||
*/
|
||||
@Data
|
||||
public class AppMenuQueryReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 430846650497878659L;
|
||||
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
private String menuName;
|
||||
|
||||
/**
|
||||
* 菜单类型(M目录 C菜单 F按钮)
|
||||
*/
|
||||
private String menuType;
|
||||
|
||||
/**
|
||||
* 显示状态(0显示 1隐藏)
|
||||
*/
|
||||
private String visible;
|
||||
|
||||
/**
|
||||
* 菜单状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package org.dromara.app.system.domain.dto.menu;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025-07-23 14:54
|
||||
*/
|
||||
@Data
|
||||
public class AppMenuUpdateReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = -2001348573190432371L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@NotNull(message = "菜单ID不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
@NotBlank(message = "菜单名称不能为空")
|
||||
private String menuName;
|
||||
|
||||
/**
|
||||
* 父菜单ID
|
||||
*/
|
||||
@NotNull(message = "父菜单不能为空")
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
@NotNull(message = "显示顺序不能为空")
|
||||
private Integer orderNum;
|
||||
|
||||
/**
|
||||
* 路由地址
|
||||
*/
|
||||
@NotBlank(message = "路由地址不能为空")
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 组件路径
|
||||
*/
|
||||
private String component;
|
||||
|
||||
/**
|
||||
* 路由参数
|
||||
*/
|
||||
private String queryParam;
|
||||
|
||||
/**
|
||||
* 菜单类型(M目录 C菜单 F按钮)
|
||||
*/
|
||||
@NotBlank(message = "菜单类型不能为空")
|
||||
private String menuType;
|
||||
|
||||
/**
|
||||
* 显示状态(0显示 1隐藏)
|
||||
*/
|
||||
private String visible;
|
||||
|
||||
/**
|
||||
* 菜单状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 权限标识
|
||||
*/
|
||||
private String perms;
|
||||
|
||||
/**
|
||||
* 菜单图标
|
||||
*/
|
||||
private String icon;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.dromara.app.system.domain.dto.role;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025-07-23 14:55
|
||||
*/
|
||||
@Data
|
||||
public class AppRoleCreateReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = -282693316523798371L;
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.dromara.app.system.domain.dto.role;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025-07-23 14:55
|
||||
*/
|
||||
@Data
|
||||
public class AppRoleQueryReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = -7355276515541220943L;
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.dromara.app.system.domain.dto.role;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025-07-23 14:55
|
||||
*/
|
||||
@Data
|
||||
public class AppRoleUpdateReq implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 6996190784775829966L;
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package org.dromara.app.system.domain.vo.menu;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025-07-23 14:50
|
||||
*/
|
||||
@Data
|
||||
public class AppMenuVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 466794582748236105L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 菜单名称
|
||||
*/
|
||||
private String menuName;
|
||||
|
||||
/**
|
||||
* 父菜单ID
|
||||
*/
|
||||
private Long parentId;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer orderNum;
|
||||
|
||||
/**
|
||||
* 路由地址
|
||||
*/
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 组件路径
|
||||
*/
|
||||
private String component;
|
||||
|
||||
/**
|
||||
* 路由参数
|
||||
*/
|
||||
private String queryParam;
|
||||
|
||||
/**
|
||||
* 菜单类型(M目录 C菜单 F按钮)
|
||||
*/
|
||||
private String menuType;
|
||||
|
||||
/**
|
||||
* 显示状态(0显示 1隐藏)
|
||||
*/
|
||||
private String visible;
|
||||
|
||||
/**
|
||||
* 菜单状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 权限标识
|
||||
*/
|
||||
private String perms;
|
||||
|
||||
/**
|
||||
* 菜单图标
|
||||
*/
|
||||
private String icon;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package org.dromara.app.system.domain.vo.role;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025-07-23 14:50
|
||||
*/
|
||||
@Data
|
||||
public class AppRoleVo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 222190798885808758L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 角色权限字符串
|
||||
*/
|
||||
private String roleKey;
|
||||
|
||||
/**
|
||||
* 显示顺序
|
||||
*/
|
||||
private Integer orderNum;
|
||||
|
||||
/**
|
||||
* 数据范围(1:全部数据权限 2:自定数据权限)
|
||||
*/
|
||||
private String dataScope;
|
||||
|
||||
/**
|
||||
* 角色状态(0正常 1停用)
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.dromara.app.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.dromara.app.system.domain.AppMenu;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_menu(app菜单)】的数据库操作Mapper
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
public interface AppMenuMapper extends BaseMapper<AppMenu> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
package org.dromara.app.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.dromara.app.system.domain.AppRole;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_role(app角色)】的数据库操作Mapper
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
public interface AppRoleMapper extends BaseMapper<AppRole> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
package org.dromara.app.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.dromara.app.system.domain.AppRoleMenu;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_role_menu(app角色和菜单关联)】的数据库操作Mapper
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
public interface AppRoleMenuMapper extends BaseMapper<AppRoleMenu> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,17 @@
|
||||
package org.dromara.app.system.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.dromara.app.system.domain.AppUserRole;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_user_role(app用户和角色关联)】的数据库操作Mapper
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
public interface AppUserRoleMapper extends BaseMapper<AppUserRole> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,59 @@
|
||||
package org.dromara.app.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.dromara.app.system.domain.AppMenu;
|
||||
import org.dromara.app.system.domain.dto.menu.AppMenuCreateReq;
|
||||
import org.dromara.app.system.domain.dto.menu.AppMenuQueryReq;
|
||||
import org.dromara.app.system.domain.dto.menu.AppMenuUpdateReq;
|
||||
import org.dromara.app.system.domain.vo.menu.AppMenuVo;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_menu(app菜单)】的数据库操作Service
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
public interface AppMenuService extends IService<AppMenu> {
|
||||
|
||||
/**
|
||||
* 新增app菜单
|
||||
*
|
||||
* @param req app菜单创建请求
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean insertByReq(AppMenuCreateReq req);
|
||||
|
||||
/**
|
||||
* 修改app菜单
|
||||
*
|
||||
* @param req app菜单更新请求
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean updateByReq(AppMenuUpdateReq req);
|
||||
|
||||
/**
|
||||
* 获取app菜单视图
|
||||
*
|
||||
* @param menu app菜单
|
||||
* @return app菜单视图
|
||||
*/
|
||||
AppMenuVo getVo(AppMenu menu);
|
||||
|
||||
/**
|
||||
* 构建查询条件封装
|
||||
*
|
||||
* @param req 查询条件
|
||||
* @return 查询条件封装
|
||||
*/
|
||||
LambdaQueryWrapper<AppMenu> buildQueryWrapper(AppMenuQueryReq req);
|
||||
|
||||
/**
|
||||
* 获取app菜单分页对象视图
|
||||
*
|
||||
* @param menuPage app菜单分页对象
|
||||
* @return app菜单分页对象视图
|
||||
*/
|
||||
Page<AppMenuVo> getVoPage(Page<AppMenu> menuPage);
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package org.dromara.app.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.dromara.app.system.domain.AppRoleMenu;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_role_menu(app角色和菜单关联)】的数据库操作Service
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
public interface AppRoleMenuService extends IService<AppRoleMenu> {
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package org.dromara.app.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.dromara.app.system.domain.AppRole;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_role(app角色)】的数据库操作Service
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
public interface AppRoleService extends IService<AppRole> {
|
||||
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package org.dromara.app.system.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.dromara.app.system.domain.AppUserRole;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_user_role(app用户和角色关联)】的数据库操作Service
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
public interface AppUserRoleService extends IService<AppUserRole> {
|
||||
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package org.dromara.app.system.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.dromara.app.system.domain.AppMenu;
|
||||
import org.dromara.app.system.domain.dto.menu.AppMenuCreateReq;
|
||||
import org.dromara.app.system.domain.dto.menu.AppMenuQueryReq;
|
||||
import org.dromara.app.system.domain.dto.menu.AppMenuUpdateReq;
|
||||
import org.dromara.app.system.domain.vo.menu.AppMenuVo;
|
||||
import org.dromara.app.system.mapper.AppMenuMapper;
|
||||
import org.dromara.app.system.service.AppMenuService;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_menu(app菜单)】的数据库操作Service实现
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
@Service
|
||||
public class AppMenuServiceImpl extends ServiceImpl<AppMenuMapper, AppMenu>
|
||||
implements AppMenuService {
|
||||
|
||||
/**
|
||||
* 新增app菜单
|
||||
*
|
||||
* @param req app菜单创建请求
|
||||
* @return 是否成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByReq(AppMenuCreateReq req) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改app菜单
|
||||
*
|
||||
* @param req app菜单更新请求
|
||||
* @return 是否成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByReq(AppMenuUpdateReq req) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取app菜单视图
|
||||
*
|
||||
* @param menu app菜单
|
||||
* @return app菜单视图
|
||||
*/
|
||||
@Override
|
||||
public AppMenuVo getVo(AppMenu menu) {
|
||||
AppMenuVo menuVo = new AppMenuVo();
|
||||
if (menu == null) {
|
||||
return menuVo;
|
||||
}
|
||||
BeanUtils.copyProperties(menu, menuVo);
|
||||
return menuVo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询条件封装
|
||||
*
|
||||
* @param req 查询条件
|
||||
* @return 查询条件封装
|
||||
*/
|
||||
@Override
|
||||
public LambdaQueryWrapper<AppMenu> buildQueryWrapper(AppMenuQueryReq req) {
|
||||
LambdaQueryWrapper<AppMenu> lqw = new LambdaQueryWrapper<>();
|
||||
if (req == null) {
|
||||
return lqw;
|
||||
}
|
||||
String menuName = req.getMenuName();
|
||||
String menuType = req.getMenuType();
|
||||
String visible = req.getVisible();
|
||||
String status = req.getStatus();
|
||||
lqw.like(StringUtils.isNotBlank(menuName), AppMenu::getMenuName, menuName);
|
||||
lqw.eq(StringUtils.isNotBlank(menuType), AppMenu::getMenuType, menuType);
|
||||
lqw.eq(StringUtils.isNotBlank(visible), AppMenu::getVisible, visible);
|
||||
lqw.eq(StringUtils.isNotBlank(status), AppMenu::getStatus, status);
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取app菜单分页对象视图
|
||||
*
|
||||
* @param menuPage app菜单分页对象
|
||||
* @return app菜单分页对象视图
|
||||
*/
|
||||
@Override
|
||||
public Page<AppMenuVo> getVoPage(Page<AppMenu> menuPage) {
|
||||
List<AppMenu> menuList = menuPage.getRecords();
|
||||
Page<AppMenuVo> menuVoPage = new Page<>(
|
||||
menuPage.getCurrent(),
|
||||
menuPage.getSize(),
|
||||
menuPage.getTotal());
|
||||
if (CollUtil.isEmpty(menuList)) {
|
||||
return menuVoPage;
|
||||
}
|
||||
List<AppMenuVo> menuVoList = menuList.stream().map(entity -> {
|
||||
AppMenuVo menuVo = new AppMenuVo();
|
||||
BeanUtils.copyProperties(entity, menuVo);
|
||||
return menuVo;
|
||||
}).toList();
|
||||
menuVoPage.setRecords(menuVoList);
|
||||
return menuVoPage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
package org.dromara.app.system.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.dromara.app.system.domain.AppRoleMenu;
|
||||
import org.dromara.app.system.mapper.AppRoleMenuMapper;
|
||||
import org.dromara.app.system.service.AppRoleMenuService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_role_menu(app角色和菜单关联)】的数据库操作Service实现
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
@Service
|
||||
public class AppRoleMenuServiceImpl extends ServiceImpl<AppRoleMenuMapper, AppRoleMenu>
|
||||
implements AppRoleMenuService {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
package org.dromara.app.system.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.dromara.app.system.domain.AppRole;
|
||||
import org.dromara.app.system.mapper.AppRoleMapper;
|
||||
import org.dromara.app.system.service.AppRoleService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_role(app角色)】的数据库操作Service实现
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
@Service
|
||||
public class AppRoleServiceImpl extends ServiceImpl<AppRoleMapper, AppRole>
|
||||
implements AppRoleService {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
package org.dromara.app.system.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.dromara.app.system.domain.AppUserRole;
|
||||
import org.dromara.app.system.mapper.AppUserRoleMapper;
|
||||
import org.dromara.app.system.service.AppUserRoleService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @description 针对表【app_user_role(app用户和角色关联)】的数据库操作Service实现
|
||||
* @createDate 2025-07-23 14:39:56
|
||||
*/
|
||||
@Service
|
||||
public class AppUserRoleServiceImpl extends ServiceImpl<AppUserRoleMapper, AppUserRole>
|
||||
implements AppUserRoleService {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
0
ruoyi-modules/ruoyi-app/src/main/resources/app/1
Normal file
0
ruoyi-modules/ruoyi-app/src/main/resources/app/1
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.app.system.mapper.AppMenuMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="org.dromara.app.system.domain.AppMenu">
|
||||
<id property="id" column="id"/>
|
||||
<result property="menuName" column="menu_name"/>
|
||||
<result property="parentId" column="parent_id"/>
|
||||
<result property="orderNum" column="order_num"/>
|
||||
<result property="path" column="path"/>
|
||||
<result property="component" column="component"/>
|
||||
<result property="queryParam" column="query_param"/>
|
||||
<result property="menuType" column="menu_type"/>
|
||||
<result property="visible" column="visible"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="perms" column="perms"/>
|
||||
<result property="icon" column="icon"/>
|
||||
<result property="createDept" column="create_dept"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,menu_name,parent_id,order_num,path,component,
|
||||
query_param,menu_type,visible,status,perms,
|
||||
icon,create_dept,remark,create_by,update_by,
|
||||
create_time,update_time
|
||||
</sql>
|
||||
</mapper>
|
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.app.system.mapper.AppRoleMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="org.dromara.app.system.domain.AppRole">
|
||||
<id property="id" column="id"/>
|
||||
<result property="roleName" column="role_name"/>
|
||||
<result property="roleKey" column="role_key"/>
|
||||
<result property="orderNum" column="order_num"/>
|
||||
<result property="dataScope" column="data_scope"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createDept" column="create_dept"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,role_name,role_key,order_num,data_scope,status,
|
||||
create_dept,remark,create_by,update_by,create_time,
|
||||
update_time
|
||||
</sql>
|
||||
</mapper>
|
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.app.system.mapper.AppRoleMenuMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="org.dromara.app.system.domain.AppRoleMenu">
|
||||
<id property="roleId" column="role_id"/>
|
||||
<id property="menuId" column="menu_id"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
role_id,menu_id
|
||||
</sql>
|
||||
</mapper>
|
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.app.system.mapper.AppUserRoleMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="org.dromara.app.system.domain.AppUserRole">
|
||||
<id property="userId" column="user_id"/>
|
||||
<id property="roleId" column="role_id"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
user_id,role_id
|
||||
</sql>
|
||||
</mapper>
|
84
ruoyi-modules/ruoyi-generator/pom.xml
Normal file
84
ruoyi-modules/ruoyi-generator/pom.xml
Normal file
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-generator</artifactId>
|
||||
|
||||
<description>
|
||||
generator 代码生成
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--velocity代码生成使用模板 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.velocity</groupId>
|
||||
<artifactId>velocity-engine-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.anyline</groupId>
|
||||
<artifactId>anyline-environment-spring-data-jdbc</artifactId>
|
||||
<version>${anyline.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.anyline</groupId>
|
||||
<artifactId>anyline-data-jdbc-mysql</artifactId>
|
||||
<version>${anyline.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- anyline支持100+种类型数据库 添加对应的jdbc依赖与anyline对应数据库依赖包即可 -->
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.anyline</groupId>-->
|
||||
<!-- <artifactId>anyline-data-jdbc-oracle</artifactId>-->
|
||||
<!-- <version>${anyline.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.anyline</groupId>-->
|
||||
<!-- <artifactId>anyline-data-jdbc-postgresql</artifactId>-->
|
||||
<!-- <version>${anyline.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.anyline</groupId>-->
|
||||
<!-- <artifactId>anyline-data-jdbc-mssql</artifactId>-->
|
||||
<!-- <version>${anyline.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,73 @@
|
||||
package org.dromara.generator.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 读取代码生成相关配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "gen")
|
||||
@PropertySource(value = {"classpath:generator.yml"}, encoding = "UTF-8")
|
||||
public class GenConfig {
|
||||
|
||||
/**
|
||||
* 作者
|
||||
*/
|
||||
public static String author;
|
||||
|
||||
/**
|
||||
* 生成包路径
|
||||
*/
|
||||
public static String packageName;
|
||||
|
||||
/**
|
||||
* 自动去除表前缀,默认是false
|
||||
*/
|
||||
public static boolean autoRemovePre;
|
||||
|
||||
/**
|
||||
* 表前缀(类名不会包含表前缀)
|
||||
*/
|
||||
public static String tablePrefix;
|
||||
|
||||
public static String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
@Value("${author}")
|
||||
public void setAuthor(String author) {
|
||||
GenConfig.author = author;
|
||||
}
|
||||
|
||||
public static String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
@Value("${packageName}")
|
||||
public void setPackageName(String packageName) {
|
||||
GenConfig.packageName = packageName;
|
||||
}
|
||||
|
||||
public static boolean getAutoRemovePre() {
|
||||
return autoRemovePre;
|
||||
}
|
||||
|
||||
@Value("${autoRemovePre}")
|
||||
public void setAutoRemovePre(boolean autoRemovePre) {
|
||||
GenConfig.autoRemovePre = autoRemovePre;
|
||||
}
|
||||
|
||||
public static String getTablePrefix() {
|
||||
return tablePrefix;
|
||||
}
|
||||
|
||||
@Value("${tablePrefix}")
|
||||
public void setTablePrefix(String tablePrefix) {
|
||||
GenConfig.tablePrefix = tablePrefix;
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package org.dromara.generator.config;
|
||||
|
||||
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.anyline.data.datasource.DataSourceMonitor;
|
||||
import org.anyline.data.runtime.DataRuntime;
|
||||
import org.anyline.util.ConfigTable;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* anyline 适配 动态数据源改造
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MyBatisDataSourceMonitor implements DataSourceMonitor {
|
||||
|
||||
public MyBatisDataSourceMonitor() {
|
||||
// 调整执行模式为自定义
|
||||
ConfigTable.KEEP_ADAPTER = 2;
|
||||
// 禁用缓存
|
||||
ConfigTable.METADATA_CACHE_SCOPE = 0;
|
||||
}
|
||||
|
||||
private final Map<String, String> features = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 数据源特征 用来定准 adapter 包含数据库或JDBC协议关键字<br/>
|
||||
* 一般会通过 产品名_url 合成 如果返回null 上层方法会通过driver_产品名_url合成
|
||||
*
|
||||
* @param datasource 数据源
|
||||
* @return String 返回null由上层自动提取
|
||||
*/
|
||||
@Override
|
||||
public String feature(DataRuntime runtime, Object datasource) {
|
||||
String feature = null;
|
||||
if (datasource instanceof JdbcTemplate jdbc) {
|
||||
DataSource ds = jdbc.getDataSource();
|
||||
if (ds instanceof DynamicRoutingDataSource) {
|
||||
String key = DynamicDataSourceContextHolder.peek();
|
||||
feature = features.get(key);
|
||||
if (null == feature) {
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DataSourceUtils.getConnection(ds);
|
||||
DatabaseMetaData meta = con.getMetaData();
|
||||
String url = meta.getURL();
|
||||
feature = meta.getDatabaseProductName().toLowerCase().replace(" ", "") + "_" + url;
|
||||
features.put(key, feature);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} finally {
|
||||
if (null != con && !DataSourceUtils.isConnectionTransactional(con, ds)) {
|
||||
DataSourceUtils.releaseConnection(con, ds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据源唯一标识 如果不实现则默认feature
|
||||
* @param datasource 数据源
|
||||
* @return String 返回null由上层自动提取
|
||||
*/
|
||||
@Override
|
||||
public String key(DataRuntime runtime, Object datasource) {
|
||||
if(datasource instanceof JdbcTemplate jdbc){
|
||||
DataSource ds = jdbc.getDataSource();
|
||||
if(ds instanceof DynamicRoutingDataSource){
|
||||
return DynamicDataSourceContextHolder.peek();
|
||||
}
|
||||
}
|
||||
return runtime.getKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* ConfigTable.KEEP_ADAPTER=2 : 根据当前接口判断是否保持同一个数据源绑定同一个adapter<br/>
|
||||
* DynamicRoutingDataSource类型的返回false,因为同一个DynamicRoutingDataSource可能对应多类数据库, 如果项目中只有一种数据库 应该直接返回true
|
||||
*
|
||||
* @param datasource 数据源
|
||||
* @return boolean
|
||||
*/
|
||||
@Override
|
||||
public boolean keepAdapter(DataRuntime runtime, Object datasource) {
|
||||
if (datasource instanceof JdbcTemplate jdbc) {
|
||||
DataSource ds = jdbc.getDataSource();
|
||||
return !(ds instanceof DynamicRoutingDataSource);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
package org.dromara.generator.constant;
|
||||
|
||||
/**
|
||||
* 代码生成通用常量
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface GenConstants {
|
||||
/**
|
||||
* 单表(增删改查)
|
||||
*/
|
||||
String TPL_CRUD = "crud";
|
||||
|
||||
/**
|
||||
* 树表(增删改查)
|
||||
*/
|
||||
String TPL_TREE = "tree";
|
||||
|
||||
/**
|
||||
* 树编码字段
|
||||
*/
|
||||
String TREE_CODE = "treeCode";
|
||||
|
||||
/**
|
||||
* 树父编码字段
|
||||
*/
|
||||
String TREE_PARENT_CODE = "treeParentCode";
|
||||
|
||||
/**
|
||||
* 树名称字段
|
||||
*/
|
||||
String TREE_NAME = "treeName";
|
||||
|
||||
/**
|
||||
* 上级菜单ID字段
|
||||
*/
|
||||
String PARENT_MENU_ID = "parentMenuId";
|
||||
|
||||
/**
|
||||
* 上级菜单名称字段
|
||||
*/
|
||||
String PARENT_MENU_NAME = "parentMenuName";
|
||||
|
||||
/**
|
||||
* 数据库字符串类型
|
||||
*/
|
||||
String[] COLUMNTYPE_STR = {"char", "varchar", "enum", "set", "nchar", "nvarchar", "varchar2", "nvarchar2"};
|
||||
|
||||
/**
|
||||
* 数据库文本类型
|
||||
*/
|
||||
String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext", "binary", "varbinary", "blob",
|
||||
"ntext", "image", "bytea"};
|
||||
|
||||
/**
|
||||
* 数据库时间类型
|
||||
*/
|
||||
String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp", "year", "interval",
|
||||
"smalldatetime", "datetime2", "datetimeoffset", "timestamptz"};
|
||||
|
||||
/**
|
||||
* 数据库数字类型
|
||||
*/
|
||||
String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "int2", "int4", "int8", "number", "integer",
|
||||
"bit", "bigint", "float", "float4", "float8", "double", "decimal", "numeric", "real", "double precision",
|
||||
"smallserial", "serial", "bigserial", "money", "smallmoney"};
|
||||
|
||||
/**
|
||||
* BO对象 不需要添加字段
|
||||
*/
|
||||
String[] COLUMNNAME_NOT_ADD = {"create_dept", "create_by", "create_time", "del_flag", "update_by",
|
||||
"update_time", "version", "tenant_id"};
|
||||
|
||||
/**
|
||||
* BO对象 不需要编辑字段
|
||||
*/
|
||||
String[] COLUMNNAME_NOT_EDIT = {"create_dept", "create_by", "create_time", "del_flag", "update_by",
|
||||
"update_time", "version", "tenant_id"};
|
||||
|
||||
/**
|
||||
* VO对象 不需要返回字段
|
||||
*/
|
||||
String[] COLUMNNAME_NOT_LIST = {"create_dept", "create_by", "create_time", "del_flag", "update_by",
|
||||
"update_time", "version", "tenant_id"};
|
||||
|
||||
/**
|
||||
* BO对象 不需要查询字段
|
||||
*/
|
||||
String[] COLUMNNAME_NOT_QUERY = {"id", "create_dept", "create_by", "create_time", "del_flag", "update_by",
|
||||
"update_time", "remark", "version", "tenant_id"};
|
||||
|
||||
/**
|
||||
* Entity基类字段
|
||||
*/
|
||||
String[] BASE_ENTITY = {"createDept", "createBy", "createTime", "updateBy", "updateTime", "tenantId"};
|
||||
|
||||
/**
|
||||
* 文本框
|
||||
*/
|
||||
String HTML_INPUT = "input";
|
||||
|
||||
/**
|
||||
* 文本域
|
||||
*/
|
||||
String HTML_TEXTAREA = "textarea";
|
||||
|
||||
/**
|
||||
* 下拉框
|
||||
*/
|
||||
String HTML_SELECT = "select";
|
||||
|
||||
/**
|
||||
* 单选框
|
||||
*/
|
||||
String HTML_RADIO = "radio";
|
||||
|
||||
/**
|
||||
* 复选框
|
||||
*/
|
||||
String HTML_CHECKBOX = "checkbox";
|
||||
|
||||
/**
|
||||
* 日期控件
|
||||
*/
|
||||
String HTML_DATETIME = "datetime";
|
||||
|
||||
/**
|
||||
* 图片上传控件
|
||||
*/
|
||||
String HTML_IMAGE_UPLOAD = "imageUpload";
|
||||
|
||||
/**
|
||||
* 文件上传控件
|
||||
*/
|
||||
String HTML_FILE_UPLOAD = "fileUpload";
|
||||
|
||||
/**
|
||||
* 富文本控件
|
||||
*/
|
||||
String HTML_EDITOR = "editor";
|
||||
|
||||
/**
|
||||
* 字符串类型
|
||||
*/
|
||||
String TYPE_STRING = "String";
|
||||
|
||||
/**
|
||||
* 整型
|
||||
*/
|
||||
String TYPE_INTEGER = "Integer";
|
||||
|
||||
/**
|
||||
* 长整型
|
||||
*/
|
||||
String TYPE_LONG = "Long";
|
||||
|
||||
/**
|
||||
* 浮点型
|
||||
*/
|
||||
String TYPE_DOUBLE = "Double";
|
||||
|
||||
/**
|
||||
* 高精度计算类型
|
||||
*/
|
||||
String TYPE_BIGDECIMAL = "BigDecimal";
|
||||
|
||||
/**
|
||||
* 时间类型
|
||||
*/
|
||||
String TYPE_DATE = "Date";
|
||||
|
||||
/**
|
||||
* 模糊查询
|
||||
*/
|
||||
String QUERY_LIKE = "LIKE";
|
||||
|
||||
/**
|
||||
* 相等查询
|
||||
*/
|
||||
String QUERY_EQ = "EQ";
|
||||
|
||||
/**
|
||||
* 需要
|
||||
*/
|
||||
String REQUIRE = "1";
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
package org.dromara.generator.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.generator.domain.GenTable;
|
||||
import org.dromara.generator.domain.GenTableColumn;
|
||||
import org.dromara.generator.service.IGenTableService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 代码生成 操作处理
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/tool/gen")
|
||||
public class GenController extends BaseController {
|
||||
|
||||
private final IGenTableService genTableService;
|
||||
|
||||
/**
|
||||
* 查询代码生成列表
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:list")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<GenTable> genList(GenTable genTable, PageQuery pageQuery) {
|
||||
return genTableService.selectPageGenTableList(genTable, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改代码生成业务
|
||||
*
|
||||
* @param tableId 表ID
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:query")
|
||||
@GetMapping(value = "/{tableId}")
|
||||
public R<Map<String, Object>> getInfo(@PathVariable Long tableId) {
|
||||
GenTable table = genTableService.selectGenTableById(tableId);
|
||||
List<GenTable> tables = genTableService.selectGenTableAll();
|
||||
List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
|
||||
Map<String, Object> map = new HashMap<>(3);
|
||||
map.put("info", table);
|
||||
map.put("rows", list);
|
||||
map.put("tables", tables);
|
||||
return R.ok(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据库列表
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:list")
|
||||
@GetMapping("/db/list")
|
||||
public TableDataInfo<GenTable> dataList(GenTable genTable, PageQuery pageQuery) {
|
||||
return genTableService.selectPageDbTableList(genTable, pageQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据表字段列表
|
||||
*
|
||||
* @param tableId 表ID
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:list")
|
||||
@GetMapping(value = "/column/{tableId}")
|
||||
public TableDataInfo<GenTableColumn> columnList(@PathVariable("tableId") Long tableId) {
|
||||
TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>();
|
||||
List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
|
||||
dataInfo.setRows(list);
|
||||
dataInfo.setTotal(list.size());
|
||||
return dataInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入表结构(保存)
|
||||
*
|
||||
* @param tables 表名串
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:import")
|
||||
@Log(title = "代码生成", businessType = BusinessType.IMPORT)
|
||||
@PostMapping("/importTable")
|
||||
public R<Void> importTableSave(String tables, String dataName) {
|
||||
String[] tableNames = Convert.toStrArray(tables);
|
||||
// 查询表信息
|
||||
List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames, dataName);
|
||||
genTableService.importGenTable(tableList, dataName);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存代码生成业务
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:edit")
|
||||
@Log(title = "代码生成", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public R<Void> editSave(@Validated @RequestBody GenTable genTable) {
|
||||
genTableService.validateEdit(genTable);
|
||||
genTableService.updateGenTable(genTable);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除代码生成
|
||||
*
|
||||
* @param tableIds 表ID串
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:remove")
|
||||
@Log(title = "代码生成", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{tableIds}")
|
||||
public R<Void> remove(@PathVariable Long[] tableIds) {
|
||||
genTableService.deleteGenTableByIds(tableIds);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 预览代码
|
||||
*
|
||||
* @param tableId 表ID
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:preview")
|
||||
@GetMapping("/preview/{tableId}")
|
||||
public R<Map<String, String>> preview(@PathVariable("tableId") Long tableId) throws IOException {
|
||||
Map<String, String> dataMap = genTableService.previewCode(tableId);
|
||||
return R.ok(dataMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成代码(下载方式)
|
||||
*
|
||||
* @param tableId 表ID
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:code")
|
||||
@Log(title = "代码生成", businessType = BusinessType.GENCODE)
|
||||
@GetMapping("/download/{tableId}")
|
||||
public void download(HttpServletResponse response, @PathVariable("tableId") Long tableId) throws IOException {
|
||||
byte[] data = genTableService.downloadCode(tableId);
|
||||
genCode(response, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成代码(自定义路径)
|
||||
*
|
||||
* @param tableId 表ID
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:code")
|
||||
@Log(title = "代码生成", businessType = BusinessType.GENCODE)
|
||||
@GetMapping("/genCode/{tableId}")
|
||||
public R<Void> genCode(@PathVariable("tableId") Long tableId) {
|
||||
genTableService.generatorCode(tableId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步数据库
|
||||
*
|
||||
* @param tableId 表ID
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:edit")
|
||||
@Log(title = "代码生成", businessType = BusinessType.UPDATE)
|
||||
@GetMapping("/synchDb/{tableId}")
|
||||
public R<Void> synchDb(@PathVariable("tableId") Long tableId) {
|
||||
genTableService.synchDb(tableId);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量生成代码
|
||||
*
|
||||
* @param tableIdStr 表ID串
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:code")
|
||||
@Log(title = "代码生成", businessType = BusinessType.GENCODE)
|
||||
@GetMapping("/batchGenCode")
|
||||
public void batchGenCode(HttpServletResponse response, String tableIdStr) throws IOException {
|
||||
String[] tableIds = Convert.toStrArray(tableIdStr);
|
||||
byte[] data = genTableService.downloadCode(tableIds);
|
||||
genCode(response, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成zip文件
|
||||
*/
|
||||
private void genCode(HttpServletResponse response, byte[] data) throws IOException {
|
||||
response.reset();
|
||||
response.addHeader("Access-Control-Allow-Origin", "*");
|
||||
response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
|
||||
response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
|
||||
response.addHeader("Content-Length", "" + data.length);
|
||||
response.setContentType("application/octet-stream; charset=UTF-8");
|
||||
IoUtil.write(response.getOutputStream(), false, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据源名称列表
|
||||
*/
|
||||
@SaCheckPermission("tool:gen:list")
|
||||
@GetMapping(value = "/getDataNames")
|
||||
public R<Object> getCurrentDataSourceNameList(){
|
||||
return R.ok(DataBaseHelper.getDataSourceNameList());
|
||||
}
|
||||
}
|
@ -0,0 +1,196 @@
|
||||
package org.dromara.generator.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.generator.constant.GenConstants;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 业务表 gen_table
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("gen_table")
|
||||
public class GenTable extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId(value = "table_id")
|
||||
private Long tableId;
|
||||
|
||||
/**
|
||||
* 数据源名称
|
||||
*/
|
||||
@NotBlank(message = "数据源名称不能为空")
|
||||
private String dataName;
|
||||
|
||||
/**
|
||||
* 表名称
|
||||
*/
|
||||
@NotBlank(message = "表名称不能为空")
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* 表描述
|
||||
*/
|
||||
@NotBlank(message = "表描述不能为空")
|
||||
private String tableComment;
|
||||
|
||||
/**
|
||||
* 关联父表的表名
|
||||
*/
|
||||
private String subTableName;
|
||||
|
||||
/**
|
||||
* 本表关联父表的外键名
|
||||
*/
|
||||
private String subTableFkName;
|
||||
|
||||
/**
|
||||
* 实体类名称(首字母大写)
|
||||
*/
|
||||
@NotBlank(message = "实体类名称不能为空")
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* 使用的模板(crud单表操作 tree树表操作 sub主子表操作)
|
||||
*/
|
||||
private String tplCategory;
|
||||
|
||||
/**
|
||||
* 生成包路径
|
||||
*/
|
||||
@NotBlank(message = "生成包路径不能为空")
|
||||
private String packageName;
|
||||
|
||||
/**
|
||||
* 生成模块名
|
||||
*/
|
||||
@NotBlank(message = "生成模块名不能为空")
|
||||
private String moduleName;
|
||||
|
||||
/**
|
||||
* 生成业务名
|
||||
*/
|
||||
@NotBlank(message = "生成业务名不能为空")
|
||||
private String businessName;
|
||||
|
||||
/**
|
||||
* 生成功能名
|
||||
*/
|
||||
@NotBlank(message = "生成功能名不能为空")
|
||||
private String functionName;
|
||||
|
||||
/**
|
||||
* 生成作者
|
||||
*/
|
||||
@NotBlank(message = "作者不能为空")
|
||||
private String functionAuthor;
|
||||
|
||||
/**
|
||||
* 生成代码方式(0zip压缩包 1自定义路径)
|
||||
*/
|
||||
private String genType;
|
||||
|
||||
/**
|
||||
* 生成路径(不填默认项目路径)
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
|
||||
private String genPath;
|
||||
|
||||
/**
|
||||
* 主键信息
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private GenTableColumn pkColumn;
|
||||
|
||||
/**
|
||||
* 表列信息
|
||||
*/
|
||||
@Valid
|
||||
@TableField(exist = false)
|
||||
private List<GenTableColumn> columns;
|
||||
|
||||
/**
|
||||
* 其它生成选项
|
||||
*/
|
||||
private String options;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 树编码字段
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String treeCode;
|
||||
|
||||
/**
|
||||
* 树父编码字段
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String treeParentCode;
|
||||
|
||||
/**
|
||||
* 树名称字段
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String treeName;
|
||||
|
||||
/*
|
||||
* 菜单id列表
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private List<Long> menuIds;
|
||||
|
||||
/**
|
||||
* 上级菜单ID字段
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private Long parentMenuId;
|
||||
|
||||
/**
|
||||
* 上级菜单名称字段
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String parentMenuName;
|
||||
|
||||
public boolean isTree() {
|
||||
return isTree(this.tplCategory);
|
||||
}
|
||||
|
||||
public static boolean isTree(String tplCategory) {
|
||||
return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);
|
||||
}
|
||||
|
||||
public boolean isCrud() {
|
||||
return isCrud(this.tplCategory);
|
||||
}
|
||||
|
||||
public static boolean isCrud(String tplCategory) {
|
||||
return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);
|
||||
}
|
||||
|
||||
public boolean isSuperColumn(String javaField) {
|
||||
return isSuperColumn(this.tplCategory, javaField);
|
||||
}
|
||||
|
||||
public static boolean isSuperColumn(String tplCategory, String javaField) {
|
||||
return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
|
||||
}
|
||||
}
|
@ -0,0 +1,222 @@
|
||||
package org.dromara.generator.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* 代码生成业务字段表 gen_table_column
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("gen_table_column")
|
||||
public class GenTableColumn extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId(value = "column_id")
|
||||
private Long columnId;
|
||||
|
||||
/**
|
||||
* 归属表编号
|
||||
*/
|
||||
private Long tableId;
|
||||
|
||||
/**
|
||||
* 列名称
|
||||
*/
|
||||
private String columnName;
|
||||
|
||||
/**
|
||||
* 列描述
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
|
||||
private String columnComment;
|
||||
|
||||
/**
|
||||
* 列类型
|
||||
*/
|
||||
private String columnType;
|
||||
|
||||
/**
|
||||
* JAVA类型
|
||||
*/
|
||||
private String javaType;
|
||||
|
||||
/**
|
||||
* JAVA字段名
|
||||
*/
|
||||
@NotBlank(message = "Java属性不能为空")
|
||||
private String javaField;
|
||||
|
||||
/**
|
||||
* 是否主键(1是)
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
|
||||
private String isPk;
|
||||
|
||||
/**
|
||||
* 是否自增(1是)
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
|
||||
private String isIncrement;
|
||||
|
||||
/**
|
||||
* 是否必填(1是)
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
|
||||
private String isRequired;
|
||||
|
||||
/**
|
||||
* 是否为插入字段(1是)
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
|
||||
private String isInsert;
|
||||
|
||||
/**
|
||||
* 是否编辑字段(1是)
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
|
||||
private String isEdit;
|
||||
|
||||
/**
|
||||
* 是否列表字段(1是)
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
|
||||
private String isList;
|
||||
|
||||
/**
|
||||
* 是否查询字段(1是)
|
||||
*/
|
||||
@TableField(updateStrategy = FieldStrategy.ALWAYS, jdbcType = JdbcType.VARCHAR)
|
||||
private String isQuery;
|
||||
|
||||
/**
|
||||
* 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围)
|
||||
*/
|
||||
private String queryType;
|
||||
|
||||
/**
|
||||
* 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件)
|
||||
*/
|
||||
private String htmlType;
|
||||
|
||||
/**
|
||||
* 字典类型
|
||||
*/
|
||||
private String dictType;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
public String getCapJavaField() {
|
||||
return StringUtils.capitalize(javaField);
|
||||
}
|
||||
|
||||
public boolean isPk() {
|
||||
return isPk(this.isPk);
|
||||
}
|
||||
|
||||
public boolean isPk(String isPk) {
|
||||
return isPk != null && StringUtils.equals("1", isPk);
|
||||
}
|
||||
|
||||
public boolean isIncrement() {
|
||||
return isIncrement(this.isIncrement);
|
||||
}
|
||||
|
||||
public boolean isIncrement(String isIncrement) {
|
||||
return isIncrement != null && StringUtils.equals("1", isIncrement);
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
return isRequired(this.isRequired);
|
||||
}
|
||||
|
||||
public boolean isRequired(String isRequired) {
|
||||
return isRequired != null && StringUtils.equals("1", isRequired);
|
||||
}
|
||||
|
||||
public boolean isInsert() {
|
||||
return isInsert(this.isInsert);
|
||||
}
|
||||
|
||||
public boolean isInsert(String isInsert) {
|
||||
return isInsert != null && StringUtils.equals("1", isInsert);
|
||||
}
|
||||
|
||||
public boolean isEdit() {
|
||||
return isEdit(this.isEdit);
|
||||
}
|
||||
|
||||
public boolean isEdit(String isEdit) {
|
||||
return isEdit != null && StringUtils.equals("1", isEdit);
|
||||
}
|
||||
|
||||
public boolean isList() {
|
||||
return isList(this.isList);
|
||||
}
|
||||
|
||||
public boolean isList(String isList) {
|
||||
return isList != null && StringUtils.equals("1", isList);
|
||||
}
|
||||
|
||||
public boolean isQuery() {
|
||||
return isQuery(this.isQuery);
|
||||
}
|
||||
|
||||
public boolean isQuery(String isQuery) {
|
||||
return isQuery != null && StringUtils.equals("1", isQuery);
|
||||
}
|
||||
|
||||
public boolean isSuperColumn() {
|
||||
return isSuperColumn(this.javaField);
|
||||
}
|
||||
|
||||
public static boolean isSuperColumn(String javaField) {
|
||||
return StringUtils.equalsAnyIgnoreCase(javaField,
|
||||
// BaseEntity
|
||||
"createBy", "createTime", "updateBy", "updateTime",
|
||||
// TreeEntity
|
||||
"parentName", "parentId");
|
||||
}
|
||||
|
||||
public boolean isUsableColumn() {
|
||||
return isUsableColumn(javaField);
|
||||
}
|
||||
|
||||
public static boolean isUsableColumn(String javaField) {
|
||||
// isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单
|
||||
return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
|
||||
}
|
||||
|
||||
public String readConverterExp() {
|
||||
String remarks = StringUtils.substringBetween(this.columnComment, "(", ")");
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if (StringUtils.isNotEmpty(remarks)) {
|
||||
for (String value : remarks.split(" ")) {
|
||||
if (StringUtils.isNotEmpty(value)) {
|
||||
Object startStr = value.subSequence(0, 1);
|
||||
String endStr = value.substring(1);
|
||||
sb.append(StringUtils.EMPTY).append(startStr).append("=").append(endStr).append(StringUtils.SEPARATOR);
|
||||
}
|
||||
}
|
||||
return sb.deleteCharAt(sb.length() - 1).toString();
|
||||
} else {
|
||||
return this.columnComment;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.dromara.generator.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.generator.domain.GenTableColumn;
|
||||
|
||||
/**
|
||||
* 业务字段 数据层
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@InterceptorIgnore(dataPermission = "true", tenantLine = "true")
|
||||
public interface GenTableColumnMapper extends BaseMapperPlus<GenTableColumn, GenTableColumn> {
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package org.dromara.generator.mapper;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
import org.dromara.generator.domain.GenTable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 业务 数据层
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@InterceptorIgnore(dataPermission = "true", tenantLine = "true")
|
||||
public interface GenTableMapper extends BaseMapperPlus<GenTable, GenTable> {
|
||||
|
||||
/**
|
||||
* 查询所有表信息
|
||||
*
|
||||
* @return 表信息集合
|
||||
*/
|
||||
List<GenTable> selectGenTableAll();
|
||||
|
||||
/**
|
||||
* 查询表ID业务信息
|
||||
*
|
||||
* @param id 业务ID
|
||||
* @return 业务信息
|
||||
*/
|
||||
GenTable selectGenTableById(Long id);
|
||||
|
||||
/**
|
||||
* 查询表名称业务信息
|
||||
*
|
||||
* @param tableName 表名称
|
||||
* @return 业务信息
|
||||
*/
|
||||
GenTable selectGenTableByName(String tableName);
|
||||
|
||||
/**
|
||||
* 查询指定数据源下的所有表名列表
|
||||
*
|
||||
* @param dataName 数据源名称,用于选择不同的数据源
|
||||
* @return 当前数据库中的表名列表
|
||||
*
|
||||
* @DS("") 使用默认数据源执行查询操作
|
||||
*/
|
||||
@DS("")
|
||||
List<String> selectTableNameList(String dataName);
|
||||
}
|
@ -0,0 +1,582 @@
|
||||
package org.dromara.generator.service;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.anyline.metadata.Column;
|
||||
import org.anyline.metadata.Table;
|
||||
import org.anyline.proxy.ServiceProxy;
|
||||
import org.apache.velocity.Template;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
import org.apache.velocity.app.Velocity;
|
||||
import org.dromara.common.core.constant.Constants;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.core.utils.SpringUtils;
|
||||
import org.dromara.common.core.utils.StreamUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.core.utils.file.FileUtils;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.generator.constant.GenConstants;
|
||||
import org.dromara.generator.domain.GenTable;
|
||||
import org.dromara.generator.domain.GenTableColumn;
|
||||
import org.dromara.generator.mapper.GenTableColumnMapper;
|
||||
import org.dromara.generator.mapper.GenTableMapper;
|
||||
import org.dromara.generator.util.GenUtils;
|
||||
import org.dromara.generator.util.VelocityInitializer;
|
||||
import org.dromara.generator.util.VelocityUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* 业务 服务层实现
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class GenTableServiceImpl implements IGenTableService {
|
||||
|
||||
private final GenTableMapper baseMapper;
|
||||
private final GenTableColumnMapper genTableColumnMapper;
|
||||
private final IdentifierGenerator identifierGenerator;
|
||||
|
||||
private static final String[] TABLE_IGNORE = new String[]{"sj_", "flow_", "gen_"};
|
||||
|
||||
/**
|
||||
* 查询业务字段列表
|
||||
*
|
||||
* @param tableId 业务字段编号
|
||||
* @return 业务字段集合
|
||||
*/
|
||||
@Override
|
||||
public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId) {
|
||||
return genTableColumnMapper.selectList(new LambdaQueryWrapper<GenTableColumn>()
|
||||
.eq(GenTableColumn::getTableId, tableId)
|
||||
.orderByAsc(GenTableColumn::getSort));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询业务信息
|
||||
*
|
||||
* @param id 业务ID
|
||||
* @return 业务信息
|
||||
*/
|
||||
@Override
|
||||
public GenTable selectGenTableById(Long id) {
|
||||
GenTable genTable = baseMapper.selectGenTableById(id);
|
||||
setTableFromOptions(genTable);
|
||||
return genTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery) {
|
||||
Page<GenTable> page = baseMapper.selectPage(pageQuery.build(), this.buildGenTableQueryWrapper(genTable));
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
private QueryWrapper<GenTable> buildGenTableQueryWrapper(GenTable genTable) {
|
||||
Map<String, Object> params = genTable.getParams();
|
||||
QueryWrapper<GenTable> wrapper = Wrappers.query();
|
||||
wrapper
|
||||
.eq(StringUtils.isNotEmpty(genTable.getDataName()), "data_name", genTable.getDataName())
|
||||
.like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
|
||||
.like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
|
||||
.between(params.get("beginTime") != null && params.get("endTime") != null,
|
||||
"create_time", params.get("beginTime"), params.get("endTime"))
|
||||
.orderByDesc("update_time");
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询数据库列表
|
||||
*
|
||||
* @param genTable 包含查询条件的GenTable对象
|
||||
* @param pageQuery 包含分页信息的PageQuery对象
|
||||
* @return 包含分页结果的TableDataInfo对象
|
||||
*/
|
||||
@DS("#genTable.dataName")
|
||||
@Override
|
||||
public TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery) {
|
||||
// 获取查询条件
|
||||
String tableName = genTable.getTableName();
|
||||
String tableComment = genTable.getTableComment();
|
||||
|
||||
LinkedHashMap<String, Table<?>> tablesMap = ServiceProxy.metadata().tables();
|
||||
if (CollUtil.isEmpty(tablesMap)) {
|
||||
return TableDataInfo.build();
|
||||
}
|
||||
List<String> tableNames = baseMapper.selectTableNameList(genTable.getDataName());
|
||||
String[] tableArrays;
|
||||
if (CollUtil.isNotEmpty(tableNames)) {
|
||||
tableArrays = tableNames.toArray(new String[0]);
|
||||
} else {
|
||||
tableArrays = new String[0];
|
||||
}
|
||||
// 过滤并转换表格数据
|
||||
List<GenTable> tables = tablesMap.values().stream()
|
||||
.filter(x -> !StringUtils.startWithAnyIgnoreCase(x.getName(), TABLE_IGNORE))
|
||||
.filter(x -> {
|
||||
if (CollUtil.isEmpty(tableNames)) {
|
||||
return true;
|
||||
}
|
||||
return !StringUtils.equalsAnyIgnoreCase(x.getName(), tableArrays);
|
||||
})
|
||||
.filter(x -> {
|
||||
boolean nameMatches = true;
|
||||
boolean commentMatches = true;
|
||||
// 进行表名称的模糊查询
|
||||
if (StringUtils.isNotBlank(tableName)) {
|
||||
nameMatches = StringUtils.containsIgnoreCase(x.getName(), tableName);
|
||||
}
|
||||
// 进行表描述的模糊查询
|
||||
if (StringUtils.isNotBlank(tableComment)) {
|
||||
commentMatches = StringUtils.containsIgnoreCase(x.getComment(), tableComment);
|
||||
}
|
||||
// 同时匹配名称和描述
|
||||
return nameMatches && commentMatches;
|
||||
})
|
||||
.map(x -> {
|
||||
GenTable gen = new GenTable();
|
||||
gen.setTableName(x.getName());
|
||||
gen.setTableComment(x.getComment());
|
||||
// postgresql的表元数据没有创建时间这个东西(好奇葩) 只能new Date代替
|
||||
gen.setCreateTime(ObjectUtil.defaultIfNull(x.getCreateTime(), new Date()));
|
||||
gen.setUpdateTime(x.getUpdateTime());
|
||||
return gen;
|
||||
}).sorted(Comparator.comparing(GenTable::getCreateTime).reversed())
|
||||
.toList();
|
||||
|
||||
IPage<GenTable> page = pageQuery.build();
|
||||
page.setTotal(tables.size());
|
||||
// 手动分页 set数据
|
||||
page.setRecords(CollUtil.page((int) page.getCurrent() - 1, (int) page.getSize(), tables));
|
||||
return TableDataInfo.build(page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询据库列表
|
||||
*
|
||||
* @param tableNames 表名称组
|
||||
* @param dataName 数据源名称
|
||||
* @return 数据库表集合
|
||||
*/
|
||||
@DS("#dataName")
|
||||
@Override
|
||||
public List<GenTable> selectDbTableListByNames(String[] tableNames, String dataName) {
|
||||
Set<String> tableNameSet = new HashSet<>(List.of(tableNames));
|
||||
LinkedHashMap<String, Table<?>> tablesMap = ServiceProxy.metadata().tables();
|
||||
|
||||
if (CollUtil.isEmpty(tablesMap)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<Table<?>> tableList = tablesMap.values().stream()
|
||||
.filter(x -> !StringUtils.startWithAnyIgnoreCase(x.getName(), TABLE_IGNORE))
|
||||
.filter(x -> tableNameSet.contains(x.getName())).toList();
|
||||
|
||||
if (CollUtil.isEmpty(tableList)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return tableList.stream().map(x -> {
|
||||
GenTable gen = new GenTable();
|
||||
gen.setDataName(dataName);
|
||||
gen.setTableName(x.getName());
|
||||
gen.setTableComment(x.getComment());
|
||||
gen.setCreateTime(x.getCreateTime());
|
||||
gen.setUpdateTime(x.getUpdateTime());
|
||||
return gen;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有表信息
|
||||
*
|
||||
* @return 表信息集合
|
||||
*/
|
||||
@Override
|
||||
public List<GenTable> selectGenTableAll() {
|
||||
return baseMapper.selectGenTableAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改业务
|
||||
*
|
||||
* @param genTable 业务信息
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void updateGenTable(GenTable genTable) {
|
||||
String options = JsonUtils.toJsonString(genTable.getParams());
|
||||
genTable.setOptions(options);
|
||||
int row = baseMapper.updateById(genTable);
|
||||
if (row > 0) {
|
||||
for (GenTableColumn cenTableColumn : genTable.getColumns()) {
|
||||
genTableColumnMapper.updateById(cenTableColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除业务对象
|
||||
*
|
||||
* @param tableIds 需要删除的数据ID
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public void deleteGenTableByIds(Long[] tableIds) {
|
||||
List<Long> ids = Arrays.asList(tableIds);
|
||||
baseMapper.deleteByIds(ids);
|
||||
genTableColumnMapper.delete(new LambdaQueryWrapper<GenTableColumn>().in(GenTableColumn::getTableId, ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入表结构
|
||||
*
|
||||
* @param tableList 导入表列表
|
||||
* @param dataName 数据源名称
|
||||
*/
|
||||
@DSTransactional
|
||||
@Override
|
||||
public void importGenTable(List<GenTable> tableList, String dataName) {
|
||||
try {
|
||||
for (GenTable table : tableList) {
|
||||
String tableName = table.getTableName();
|
||||
GenUtils.initTable(table);
|
||||
table.setDataName(dataName);
|
||||
int row = baseMapper.insert(table);
|
||||
if (row > 0) {
|
||||
// 保存列信息
|
||||
List<GenTableColumn> genTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(tableName, dataName);
|
||||
List<GenTableColumn> saveColumns = new ArrayList<>();
|
||||
for (GenTableColumn column : genTableColumns) {
|
||||
GenUtils.initColumnField(column, table);
|
||||
saveColumns.add(column);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(saveColumns)) {
|
||||
genTableColumnMapper.insertBatch(saveColumns);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("导入失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名称查询列信息
|
||||
*
|
||||
* @param tableName 表名称
|
||||
* @param dataName 数据源名称
|
||||
* @return 列信息
|
||||
*/
|
||||
@DS("#dataName")
|
||||
@Override
|
||||
public List<GenTableColumn> selectDbTableColumnsByName(String tableName, String dataName) {
|
||||
Table<?> table = ServiceProxy.metadata().table(tableName);
|
||||
if (ObjectUtil.isNull(table)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
LinkedHashMap<String, Column> columns = table.getColumns();
|
||||
List<GenTableColumn> tableColumns = new ArrayList<>();
|
||||
columns.forEach((columnName, column) -> {
|
||||
GenTableColumn tableColumn = new GenTableColumn();
|
||||
tableColumn.setIsPk(String.valueOf(column.isPrimaryKey()));
|
||||
tableColumn.setColumnName(column.getName());
|
||||
tableColumn.setColumnComment(column.getComment());
|
||||
tableColumn.setColumnType(column.getOriginType().toLowerCase());
|
||||
tableColumn.setSort(column.getPosition());
|
||||
tableColumn.setIsRequired(column.isNullable() == 0 ? "1" : "0");
|
||||
tableColumn.setIsIncrement(column.isAutoIncrement() == -1 ? "0" : "1");
|
||||
tableColumns.add(tableColumn);
|
||||
});
|
||||
return tableColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* 预览代码
|
||||
*
|
||||
* @param tableId 表编号
|
||||
* @return 预览数据列表
|
||||
*/
|
||||
@Override
|
||||
public Map<String, String> previewCode(Long tableId) {
|
||||
Map<String, String> dataMap = new LinkedHashMap<>();
|
||||
// 查询表信息
|
||||
GenTable table = baseMapper.selectGenTableById(tableId);
|
||||
List<Long> menuIds = new ArrayList<>();
|
||||
for (int i = 0; i < 6; i++) {
|
||||
menuIds.add(identifierGenerator.nextId(null).longValue());
|
||||
}
|
||||
table.setMenuIds(menuIds);
|
||||
// 设置主键列信息
|
||||
setPkColumn(table);
|
||||
VelocityInitializer.initVelocity();
|
||||
|
||||
VelocityContext context = VelocityUtils.prepareContext(table);
|
||||
|
||||
// 获取模板列表
|
||||
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
|
||||
for (String template : templates) {
|
||||
// 渲染模板
|
||||
StringWriter sw = new StringWriter();
|
||||
Template tpl = Velocity.getTemplate(template, Constants.UTF8);
|
||||
tpl.merge(context, sw);
|
||||
dataMap.put(template, sw.toString());
|
||||
}
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成代码(下载方式)
|
||||
*
|
||||
* @param tableId 表名称
|
||||
* @return 数据
|
||||
*/
|
||||
@Override
|
||||
public byte[] downloadCode(Long tableId) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
ZipOutputStream zip = new ZipOutputStream(outputStream);
|
||||
generatorCode(tableId, zip);
|
||||
IoUtil.close(zip);
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成代码(自定义路径)
|
||||
*
|
||||
* @param tableId 表名称
|
||||
*/
|
||||
@Override
|
||||
public void generatorCode(Long tableId) {
|
||||
// 查询表信息
|
||||
GenTable table = baseMapper.selectGenTableById(tableId);
|
||||
// 设置主键列信息
|
||||
setPkColumn(table);
|
||||
|
||||
VelocityInitializer.initVelocity();
|
||||
|
||||
VelocityContext context = VelocityUtils.prepareContext(table);
|
||||
|
||||
// 获取模板列表
|
||||
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
|
||||
for (String template : templates) {
|
||||
if (!StringUtils.containsAny(template, "sql.vm", "api.ts.vm", "types.ts.vm", "index.vue.vm", "index-tree.vue.vm")) {
|
||||
// 渲染模板
|
||||
StringWriter sw = new StringWriter();
|
||||
Template tpl = Velocity.getTemplate(template, Constants.UTF8);
|
||||
tpl.merge(context, sw);
|
||||
try {
|
||||
String path = getGenPath(table, template);
|
||||
FileUtils.writeUtf8String(sw.toString(), path);
|
||||
} catch (Exception e) {
|
||||
throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步数据库
|
||||
*
|
||||
* @param tableId 表名称
|
||||
*/
|
||||
@DSTransactional
|
||||
@Override
|
||||
public void synchDb(Long tableId) {
|
||||
GenTable table = baseMapper.selectGenTableById(tableId);
|
||||
List<GenTableColumn> tableColumns = table.getColumns();
|
||||
Map<String, GenTableColumn> tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName);
|
||||
|
||||
List<GenTableColumn> dbTableColumns = SpringUtils.getAopProxy(this).selectDbTableColumnsByName(table.getTableName(), table.getDataName());
|
||||
if (CollUtil.isEmpty(dbTableColumns)) {
|
||||
throw new ServiceException("同步数据失败,原表结构不存在");
|
||||
}
|
||||
List<String> dbTableColumnNames = StreamUtils.toList(dbTableColumns, GenTableColumn::getColumnName);
|
||||
|
||||
List<GenTableColumn> saveColumns = new ArrayList<>();
|
||||
dbTableColumns.forEach(column -> {
|
||||
GenUtils.initColumnField(column, table);
|
||||
if (tableColumnMap.containsKey(column.getColumnName())) {
|
||||
GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
|
||||
column.setColumnId(prevColumn.getColumnId());
|
||||
if (column.isList()) {
|
||||
// 如果是列表,继续保留查询方式/字典类型选项
|
||||
column.setDictType(prevColumn.getDictType());
|
||||
column.setQueryType(prevColumn.getQueryType());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
|
||||
&& (column.isInsert() || column.isEdit())
|
||||
&& ((column.isUsableColumn()) || (!column.isSuperColumn()))) {
|
||||
// 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项
|
||||
column.setIsRequired(prevColumn.getIsRequired());
|
||||
column.setHtmlType(prevColumn.getHtmlType());
|
||||
}
|
||||
}
|
||||
saveColumns.add(column);
|
||||
});
|
||||
if (CollUtil.isNotEmpty(saveColumns)) {
|
||||
genTableColumnMapper.insertOrUpdateBatch(saveColumns);
|
||||
}
|
||||
List<GenTableColumn> delColumns = StreamUtils.filter(tableColumns, column -> !dbTableColumnNames.contains(column.getColumnName()));
|
||||
if (CollUtil.isNotEmpty(delColumns)) {
|
||||
List<Long> ids = StreamUtils.toList(delColumns, GenTableColumn::getColumnId);
|
||||
if (CollUtil.isNotEmpty(ids)) {
|
||||
genTableColumnMapper.deleteByIds(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量生成代码(下载方式)
|
||||
*
|
||||
* @param tableIds 表ID数组
|
||||
* @return 数据
|
||||
*/
|
||||
@Override
|
||||
public byte[] downloadCode(String[] tableIds) {
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
ZipOutputStream zip = new ZipOutputStream(outputStream);
|
||||
for (String tableId : tableIds) {
|
||||
generatorCode(Long.parseLong(tableId), zip);
|
||||
}
|
||||
IoUtil.close(zip);
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询表信息并生成代码
|
||||
*/
|
||||
private void generatorCode(Long tableId, ZipOutputStream zip) {
|
||||
// 查询表信息
|
||||
GenTable table = baseMapper.selectGenTableById(tableId);
|
||||
List<Long> menuIds = new ArrayList<>();
|
||||
for (int i = 0; i < 6; i++) {
|
||||
menuIds.add(identifierGenerator.nextId(null).longValue());
|
||||
}
|
||||
table.setMenuIds(menuIds);
|
||||
// 设置主键列信息
|
||||
setPkColumn(table);
|
||||
|
||||
VelocityInitializer.initVelocity();
|
||||
|
||||
VelocityContext context = VelocityUtils.prepareContext(table);
|
||||
|
||||
// 获取模板列表
|
||||
List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
|
||||
for (String template : templates) {
|
||||
// 渲染模板
|
||||
StringWriter sw = new StringWriter();
|
||||
Template tpl = Velocity.getTemplate(template, Constants.UTF8);
|
||||
tpl.merge(context, sw);
|
||||
try {
|
||||
// 添加到zip
|
||||
zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
|
||||
IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
|
||||
IoUtil.close(sw);
|
||||
zip.flush();
|
||||
zip.closeEntry();
|
||||
} catch (IOException e) {
|
||||
log.error("渲染模板失败,表名:" + table.getTableName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存参数校验
|
||||
*
|
||||
* @param genTable 业务信息
|
||||
*/
|
||||
@Override
|
||||
public void validateEdit(GenTable genTable) {
|
||||
if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) {
|
||||
String options = JsonUtils.toJsonString(genTable.getParams());
|
||||
Dict paramsObj = JsonUtils.parseMap(options);
|
||||
if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_CODE))) {
|
||||
throw new ServiceException("树编码字段不能为空");
|
||||
} else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_PARENT_CODE))) {
|
||||
throw new ServiceException("树父编码字段不能为空");
|
||||
} else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_NAME))) {
|
||||
throw new ServiceException("树名称字段不能为空");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置主键列信息
|
||||
*
|
||||
* @param table 业务表信息
|
||||
*/
|
||||
public void setPkColumn(GenTable table) {
|
||||
for (GenTableColumn column : table.getColumns()) {
|
||||
if (column.isPk()) {
|
||||
table.setPkColumn(column);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ObjectUtil.isNull(table.getPkColumn())) {
|
||||
table.setPkColumn(table.getColumns().get(0));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置代码生成其他选项值
|
||||
*
|
||||
* @param genTable 设置后的生成对象
|
||||
*/
|
||||
public void setTableFromOptions(GenTable genTable) {
|
||||
Dict paramsObj = JsonUtils.parseMap(genTable.getOptions());
|
||||
if (ObjectUtil.isNotNull(paramsObj)) {
|
||||
String treeCode = paramsObj.getStr(GenConstants.TREE_CODE);
|
||||
String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE);
|
||||
String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
|
||||
Long parentMenuId = paramsObj.getLong(GenConstants.PARENT_MENU_ID);
|
||||
String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME);
|
||||
|
||||
genTable.setTreeCode(treeCode);
|
||||
genTable.setTreeParentCode(treeParentCode);
|
||||
genTable.setTreeName(treeName);
|
||||
genTable.setParentMenuId(parentMenuId);
|
||||
genTable.setParentMenuName(parentMenuName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取代码生成地址
|
||||
*
|
||||
* @param table 业务表信息
|
||||
* @param template 模板文件路径
|
||||
* @return 生成地址
|
||||
*/
|
||||
public static String getGenPath(GenTable table, String template) {
|
||||
String genPath = table.getGenPath();
|
||||
if (StringUtils.equals(genPath, "/")) {
|
||||
return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
|
||||
}
|
||||
return genPath + File.separator + VelocityUtils.getFileName(template, table);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,141 @@
|
||||
package org.dromara.generator.service;
|
||||
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.generator.domain.GenTable;
|
||||
import org.dromara.generator.domain.GenTableColumn;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 业务 服务层
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface IGenTableService {
|
||||
|
||||
/**
|
||||
* 查询业务字段列表
|
||||
*
|
||||
* @param tableId 业务字段编号
|
||||
* @return 业务字段集合
|
||||
*/
|
||||
List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
|
||||
|
||||
/**
|
||||
* 查询业务列表
|
||||
*
|
||||
* @param genTable 业务信息
|
||||
* @return 业务集合
|
||||
*/
|
||||
TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询据库列表
|
||||
*
|
||||
* @param genTable 业务信息
|
||||
* @return 数据库表集合
|
||||
*/
|
||||
TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery);
|
||||
|
||||
/**
|
||||
* 查询据库列表
|
||||
*
|
||||
* @param tableNames 表名称组
|
||||
* @param dataName 数据源名称
|
||||
* @return 数据库表集合
|
||||
*/
|
||||
List<GenTable> selectDbTableListByNames(String[] tableNames, String dataName);
|
||||
|
||||
/**
|
||||
* 查询所有表信息
|
||||
*
|
||||
* @return 表信息集合
|
||||
*/
|
||||
List<GenTable> selectGenTableAll();
|
||||
|
||||
/**
|
||||
* 查询业务信息
|
||||
*
|
||||
* @param id 业务ID
|
||||
* @return 业务信息
|
||||
*/
|
||||
GenTable selectGenTableById(Long id);
|
||||
|
||||
/**
|
||||
* 修改业务
|
||||
*
|
||||
* @param genTable 业务信息
|
||||
*/
|
||||
void updateGenTable(GenTable genTable);
|
||||
|
||||
/**
|
||||
* 删除业务信息
|
||||
*
|
||||
* @param tableIds 需要删除的表数据ID
|
||||
*/
|
||||
void deleteGenTableByIds(Long[] tableIds);
|
||||
|
||||
/**
|
||||
* 导入表结构
|
||||
*
|
||||
* @param tableList 导入表列表
|
||||
* @param dataName 数据源名称
|
||||
*/
|
||||
void importGenTable(List<GenTable> tableList, String dataName);
|
||||
|
||||
/**
|
||||
* 根据表名称查询列信息
|
||||
*
|
||||
* @param tableName 表名称
|
||||
* @param dataName 数据源名称
|
||||
* @return 列信息
|
||||
*/
|
||||
List<GenTableColumn> selectDbTableColumnsByName(String tableName, String dataName);
|
||||
|
||||
/**
|
||||
* 预览代码
|
||||
*
|
||||
* @param tableId 表编号
|
||||
* @return 预览数据列表
|
||||
*/
|
||||
Map<String, String> previewCode(Long tableId);
|
||||
|
||||
/**
|
||||
* 生成代码(下载方式)
|
||||
*
|
||||
* @param tableId 表名称
|
||||
* @return 数据
|
||||
*/
|
||||
byte[] downloadCode(Long tableId);
|
||||
|
||||
/**
|
||||
* 生成代码(自定义路径)
|
||||
*
|
||||
* @param tableId 表名称
|
||||
*/
|
||||
void generatorCode(Long tableId);
|
||||
|
||||
/**
|
||||
* 同步数据库
|
||||
*
|
||||
* @param tableId 表名称
|
||||
*/
|
||||
void synchDb(Long tableId);
|
||||
|
||||
/**
|
||||
* 批量生成代码(下载方式)
|
||||
*
|
||||
* @param tableIds 表ID数组
|
||||
* @return 数据
|
||||
*/
|
||||
byte[] downloadCode(String[] tableIds);
|
||||
|
||||
/**
|
||||
* 修改保存参数校验
|
||||
*
|
||||
* @param genTable 业务信息
|
||||
*/
|
||||
void validateEdit(GenTable genTable);
|
||||
}
|
@ -0,0 +1,219 @@
|
||||
package org.dromara.generator.util;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.RegExUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.generator.config.GenConfig;
|
||||
import org.dromara.generator.constant.GenConstants;
|
||||
import org.dromara.generator.domain.GenTable;
|
||||
import org.dromara.generator.domain.GenTableColumn;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 代码生成器 工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class GenUtils {
|
||||
|
||||
/**
|
||||
* 初始化表信息
|
||||
*/
|
||||
public static void initTable(GenTable genTable) {
|
||||
genTable.setClassName(convertClassName(genTable.getTableName()));
|
||||
genTable.setPackageName(GenConfig.getPackageName());
|
||||
genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
|
||||
genTable.setBusinessName(getBusinessName(genTable.getTableName()));
|
||||
genTable.setFunctionName(replaceText(genTable.getTableComment()));
|
||||
genTable.setFunctionAuthor(GenConfig.getAuthor());
|
||||
genTable.setCreateTime(null);
|
||||
genTable.setUpdateTime(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化列属性字段
|
||||
*/
|
||||
public static void initColumnField(GenTableColumn column, GenTable table) {
|
||||
String dataType = getDbType(column.getColumnType());
|
||||
// 统一转小写 避免有些数据库默认大写问题 如果需要特别书写方式 请在实体类增加注解标注别名
|
||||
String columnName = column.getColumnName().toLowerCase();
|
||||
column.setTableId(table.getTableId());
|
||||
column.setCreateTime(null);
|
||||
column.setUpdateTime(null);
|
||||
// 设置java字段名
|
||||
column.setJavaField(StringUtils.toCamelCase(columnName));
|
||||
// 设置默认类型
|
||||
column.setJavaType(GenConstants.TYPE_STRING);
|
||||
column.setQueryType(GenConstants.QUERY_EQ);
|
||||
|
||||
if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) {
|
||||
// 字符串长度超过500设置为文本域
|
||||
Integer columnLength = getColumnLength(column.getColumnType());
|
||||
String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
|
||||
column.setHtmlType(htmlType);
|
||||
} else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) {
|
||||
column.setJavaType(GenConstants.TYPE_DATE);
|
||||
column.setHtmlType(GenConstants.HTML_DATETIME);
|
||||
} else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) {
|
||||
column.setHtmlType(GenConstants.HTML_INPUT);
|
||||
// 数据库的数字字段与java不匹配 且很多数据库的数字字段很模糊 例如oracle只有number没有细分
|
||||
// 所以默认数字类型全为Long可在界面上自行编辑想要的类型 有什么特殊需求也可以在这里特殊处理
|
||||
column.setJavaType(GenConstants.TYPE_LONG);
|
||||
}
|
||||
|
||||
// BO对象 默认插入勾选
|
||||
if (!arraysContains(GenConstants.COLUMNNAME_NOT_ADD, columnName) && !column.isPk()) {
|
||||
column.setIsInsert(GenConstants.REQUIRE);
|
||||
}
|
||||
// BO对象 默认编辑勾选
|
||||
if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
|
||||
column.setIsEdit(GenConstants.REQUIRE);
|
||||
}
|
||||
// VO对象 默认返回勾选
|
||||
if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName)) {
|
||||
column.setIsList(GenConstants.REQUIRE);
|
||||
}
|
||||
// BO对象 默认查询勾选
|
||||
if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) {
|
||||
column.setIsQuery(GenConstants.REQUIRE);
|
||||
}
|
||||
|
||||
// 查询字段类型
|
||||
if (StringUtils.endsWithIgnoreCase(columnName, "name")) {
|
||||
column.setQueryType(GenConstants.QUERY_LIKE);
|
||||
}
|
||||
// 状态字段设置单选框
|
||||
if (StringUtils.endsWithIgnoreCase(columnName, "status")) {
|
||||
column.setHtmlType(GenConstants.HTML_RADIO);
|
||||
}
|
||||
// 类型&性别字段设置下拉框
|
||||
else if (StringUtils.endsWithIgnoreCase(columnName, "type")
|
||||
|| StringUtils.endsWithIgnoreCase(columnName, "sex")) {
|
||||
column.setHtmlType(GenConstants.HTML_SELECT);
|
||||
}
|
||||
// 图片字段设置图片上传控件
|
||||
else if (StringUtils.endsWithIgnoreCase(columnName, "image")) {
|
||||
column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
|
||||
}
|
||||
// 文件字段设置文件上传控件
|
||||
else if (StringUtils.endsWithIgnoreCase(columnName, "file")) {
|
||||
column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
|
||||
}
|
||||
// 内容字段设置富文本控件
|
||||
else if (StringUtils.endsWithIgnoreCase(columnName, "content")) {
|
||||
column.setHtmlType(GenConstants.HTML_EDITOR);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验数组是否包含指定值
|
||||
*
|
||||
* @param arr 数组
|
||||
* @param targetValue 值
|
||||
* @return 是否包含
|
||||
*/
|
||||
public static boolean arraysContains(String[] arr, String targetValue) {
|
||||
return Arrays.asList(arr).contains(targetValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块名
|
||||
*
|
||||
* @param packageName 包名
|
||||
* @return 模块名
|
||||
*/
|
||||
public static String getModuleName(String packageName) {
|
||||
int lastIndex = packageName.lastIndexOf(".");
|
||||
int nameLength = packageName.length();
|
||||
return StringUtils.substring(packageName, lastIndex + 1, nameLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取业务名
|
||||
*
|
||||
* @param tableName 表名
|
||||
* @return 业务名
|
||||
*/
|
||||
public static String getBusinessName(String tableName) {
|
||||
int firstIndex = tableName.indexOf("_");
|
||||
int nameLength = tableName.length();
|
||||
String businessName = StringUtils.substring(tableName, firstIndex + 1, nameLength);
|
||||
businessName = StringUtils.toCamelCase(businessName);
|
||||
return businessName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表名转换成Java类名
|
||||
*
|
||||
* @param tableName 表名称
|
||||
* @return 类名
|
||||
*/
|
||||
public static String convertClassName(String tableName) {
|
||||
boolean autoRemovePre = GenConfig.getAutoRemovePre();
|
||||
String tablePrefix = GenConfig.getTablePrefix();
|
||||
if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) {
|
||||
String[] searchList = StringUtils.split(tablePrefix, StringUtils.SEPARATOR);
|
||||
tableName = replaceFirst(tableName, searchList);
|
||||
}
|
||||
return StringUtils.convertToCamelCase(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量替换前缀
|
||||
*
|
||||
* @param replacementm 替换值
|
||||
* @param searchList 替换列表
|
||||
*/
|
||||
public static String replaceFirst(String replacementm, String[] searchList) {
|
||||
String text = replacementm;
|
||||
for (String searchString : searchList) {
|
||||
if (replacementm.startsWith(searchString)) {
|
||||
text = replacementm.replaceFirst(searchString, StringUtils.EMPTY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关键字替换
|
||||
*
|
||||
* @param text 需要被替换的名字
|
||||
* @return 替换后的名字
|
||||
*/
|
||||
public static String replaceText(String text) {
|
||||
return RegExUtils.replaceAll(text, "(?:表|若依)", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库类型字段
|
||||
*
|
||||
* @param columnType 列类型
|
||||
* @return 截取后的列类型
|
||||
*/
|
||||
public static String getDbType(String columnType) {
|
||||
if (StringUtils.indexOf(columnType, "(") > 0) {
|
||||
return StringUtils.substringBefore(columnType, "(");
|
||||
} else {
|
||||
return columnType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字段长度
|
||||
*
|
||||
* @param columnType 列类型
|
||||
* @return 截取后的列类型
|
||||
*/
|
||||
public static Integer getColumnLength(String columnType) {
|
||||
if (StringUtils.indexOf(columnType, "(") > 0) {
|
||||
String length = StringUtils.substringBetween(columnType, "(", ")");
|
||||
return Integer.valueOf(length);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.dromara.generator.util;
|
||||
|
||||
import org.dromara.common.core.constant.Constants;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.velocity.app.Velocity;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* VelocityEngine工厂
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class VelocityInitializer {
|
||||
|
||||
/**
|
||||
* 初始化vm方法
|
||||
*/
|
||||
public static void initVelocity() {
|
||||
Properties p = new Properties();
|
||||
try {
|
||||
// 加载classpath目录下的vm文件
|
||||
p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
|
||||
// 定义字符集
|
||||
p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
|
||||
// 初始化Velocity引擎,指定配置Properties
|
||||
Velocity.init(p);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,341 @@
|
||||
package org.dromara.generator.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import org.dromara.generator.constant.GenConstants;
|
||||
import org.dromara.common.core.utils.DateUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
import org.dromara.common.json.utils.JsonUtils;
|
||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||
import org.dromara.generator.domain.GenTable;
|
||||
import org.dromara.generator.domain.GenTableColumn;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.velocity.VelocityContext;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 模板处理工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class VelocityUtils {
|
||||
|
||||
/**
|
||||
* 项目空间路径
|
||||
*/
|
||||
private static final String PROJECT_PATH = "main/java";
|
||||
|
||||
/**
|
||||
* mybatis空间路径
|
||||
*/
|
||||
private static final String MYBATIS_PATH = "main/resources/mapper";
|
||||
|
||||
/**
|
||||
* 默认上级菜单,系统工具
|
||||
*/
|
||||
private static final String DEFAULT_PARENT_MENU_ID = "3";
|
||||
|
||||
/**
|
||||
* 设置模板变量信息
|
||||
*
|
||||
* @return 模板列表
|
||||
*/
|
||||
public static VelocityContext prepareContext(GenTable genTable) {
|
||||
String moduleName = genTable.getModuleName();
|
||||
String businessName = genTable.getBusinessName();
|
||||
String packageName = genTable.getPackageName();
|
||||
String tplCategory = genTable.getTplCategory();
|
||||
String functionName = genTable.getFunctionName();
|
||||
|
||||
VelocityContext velocityContext = new VelocityContext();
|
||||
velocityContext.put("tplCategory", genTable.getTplCategory());
|
||||
velocityContext.put("tableName", genTable.getTableName());
|
||||
velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
|
||||
velocityContext.put("ClassName", genTable.getClassName());
|
||||
velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
|
||||
velocityContext.put("moduleName", genTable.getModuleName());
|
||||
velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
|
||||
velocityContext.put("businessName", genTable.getBusinessName());
|
||||
velocityContext.put("basePackage", getPackagePrefix(packageName));
|
||||
velocityContext.put("packageName", packageName);
|
||||
velocityContext.put("author", genTable.getFunctionAuthor());
|
||||
velocityContext.put("datetime", DateUtils.getDate());
|
||||
velocityContext.put("pkColumn", genTable.getPkColumn());
|
||||
velocityContext.put("importList", getImportList(genTable));
|
||||
velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
|
||||
velocityContext.put("columns", genTable.getColumns());
|
||||
velocityContext.put("table", genTable);
|
||||
velocityContext.put("dicts", getDicts(genTable));
|
||||
setMenuVelocityContext(velocityContext, genTable);
|
||||
if (GenConstants.TPL_TREE.equals(tplCategory)) {
|
||||
setTreeVelocityContext(velocityContext, genTable);
|
||||
}
|
||||
return velocityContext;
|
||||
}
|
||||
|
||||
public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) {
|
||||
String options = genTable.getOptions();
|
||||
Dict paramsObj = JsonUtils.parseMap(options);
|
||||
String parentMenuId = getParentMenuId(paramsObj);
|
||||
context.put("parentMenuId", parentMenuId);
|
||||
}
|
||||
|
||||
public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) {
|
||||
String options = genTable.getOptions();
|
||||
Dict paramsObj = JsonUtils.parseMap(options);
|
||||
String treeCode = getTreecode(paramsObj);
|
||||
String treeParentCode = getTreeParentCode(paramsObj);
|
||||
String treeName = getTreeName(paramsObj);
|
||||
|
||||
context.put("treeCode", treeCode);
|
||||
context.put("treeParentCode", treeParentCode);
|
||||
context.put("treeName", treeName);
|
||||
context.put("expandColumn", getExpandColumn(genTable));
|
||||
if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
|
||||
context.put("tree_parent_code", paramsObj.get(GenConstants.TREE_PARENT_CODE));
|
||||
}
|
||||
if (paramsObj.containsKey(GenConstants.TREE_NAME)) {
|
||||
context.put("tree_name", paramsObj.get(GenConstants.TREE_NAME));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模板信息
|
||||
*
|
||||
* @return 模板列表
|
||||
*/
|
||||
public static List<String> getTemplateList(String tplCategory) {
|
||||
List<String> templates = new ArrayList<>();
|
||||
templates.add("vm/java/domain.java.vm");
|
||||
templates.add("vm/java/vo.java.vm");
|
||||
templates.add("vm/java/bo.java.vm");
|
||||
templates.add("vm/java/mapper.java.vm");
|
||||
templates.add("vm/java/service.java.vm");
|
||||
templates.add("vm/java/serviceImpl.java.vm");
|
||||
templates.add("vm/java/controller.java.vm");
|
||||
templates.add("vm/xml/mapper.xml.vm");
|
||||
if (DataBaseHelper.isOracle()) {
|
||||
templates.add("vm/sql/oracle/sql.vm");
|
||||
} else if (DataBaseHelper.isPostgerSql()) {
|
||||
templates.add("vm/sql/postgres/sql.vm");
|
||||
} else if (DataBaseHelper.isSqlServer()) {
|
||||
templates.add("vm/sql/sqlserver/sql.vm");
|
||||
} else {
|
||||
templates.add("vm/sql/sql.vm");
|
||||
}
|
||||
templates.add("vm/ts/api.ts.vm");
|
||||
templates.add("vm/ts/types.ts.vm");
|
||||
if (GenConstants.TPL_CRUD.equals(tplCategory)) {
|
||||
templates.add("vm/vue/index.vue.vm");
|
||||
} else if (GenConstants.TPL_TREE.equals(tplCategory)) {
|
||||
templates.add("vm/vue/index-tree.vue.vm");
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名
|
||||
*/
|
||||
public static String getFileName(String template, GenTable genTable) {
|
||||
// 文件名称
|
||||
String fileName = "";
|
||||
// 包路径
|
||||
String packageName = genTable.getPackageName();
|
||||
// 模块名
|
||||
String moduleName = genTable.getModuleName();
|
||||
// 大写类名
|
||||
String className = genTable.getClassName();
|
||||
// 业务名称
|
||||
String businessName = genTable.getBusinessName();
|
||||
|
||||
String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
|
||||
String mybatisPath = MYBATIS_PATH + "/" + moduleName;
|
||||
String vuePath = "vue";
|
||||
|
||||
if (template.contains("domain.java.vm")) {
|
||||
fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
|
||||
}
|
||||
if (template.contains("vo.java.vm")) {
|
||||
fileName = StringUtils.format("{}/domain/vo/{}Vo.java", javaPath, className);
|
||||
}
|
||||
if (template.contains("bo.java.vm")) {
|
||||
fileName = StringUtils.format("{}/domain/bo/{}Bo.java", javaPath, className);
|
||||
}
|
||||
if (template.contains("mapper.java.vm")) {
|
||||
fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
|
||||
} else if (template.contains("service.java.vm")) {
|
||||
fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
|
||||
} else if (template.contains("serviceImpl.java.vm")) {
|
||||
fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
|
||||
} else if (template.contains("controller.java.vm")) {
|
||||
fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
|
||||
} else if (template.contains("mapper.xml.vm")) {
|
||||
fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
|
||||
} else if (template.contains("sql.vm")) {
|
||||
fileName = businessName + "Menu.sql";
|
||||
} else if (template.contains("api.ts.vm")) {
|
||||
fileName = StringUtils.format("{}/api/{}/{}/index.ts", vuePath, moduleName, businessName);
|
||||
} else if (template.contains("types.ts.vm")) {
|
||||
fileName = StringUtils.format("{}/api/{}/{}/types.ts", vuePath, moduleName, businessName);
|
||||
} else if (template.contains("index.vue.vm")) {
|
||||
fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
|
||||
} else if (template.contains("index-tree.vue.vm")) {
|
||||
fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取包前缀
|
||||
*
|
||||
* @param packageName 包名称
|
||||
* @return 包前缀名称
|
||||
*/
|
||||
public static String getPackagePrefix(String packageName) {
|
||||
int lastIndex = packageName.lastIndexOf(".");
|
||||
return StringUtils.substring(packageName, 0, lastIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据列类型获取导入包
|
||||
*
|
||||
* @param genTable 业务表对象
|
||||
* @return 返回需要导入的包列表
|
||||
*/
|
||||
public static HashSet<String> getImportList(GenTable genTable) {
|
||||
List<GenTableColumn> columns = genTable.getColumns();
|
||||
HashSet<String> importList = new HashSet<>();
|
||||
for (GenTableColumn column : columns) {
|
||||
if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) {
|
||||
importList.add("java.util.Date");
|
||||
importList.add("com.fasterxml.jackson.annotation.JsonFormat");
|
||||
} else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) {
|
||||
importList.add("java.math.BigDecimal");
|
||||
} else if (!column.isSuperColumn() && "imageUpload".equals(column.getHtmlType())) {
|
||||
importList.add("org.dromara.common.translation.annotation.Translation");
|
||||
importList.add("org.dromara.common.translation.constant.TransConstant");
|
||||
}
|
||||
}
|
||||
return importList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据列类型获取字典组
|
||||
*
|
||||
* @param genTable 业务表对象
|
||||
* @return 返回字典组
|
||||
*/
|
||||
public static String getDicts(GenTable genTable) {
|
||||
List<GenTableColumn> columns = genTable.getColumns();
|
||||
Set<String> dicts = new HashSet<>();
|
||||
addDicts(dicts, columns);
|
||||
return StringUtils.join(dicts, ", ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加字典列表
|
||||
*
|
||||
* @param dicts 字典列表
|
||||
* @param columns 列集合
|
||||
*/
|
||||
public static void addDicts(Set<String> dicts, List<GenTableColumn> columns) {
|
||||
for (GenTableColumn column : columns) {
|
||||
if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
|
||||
column.getHtmlType(),
|
||||
new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) {
|
||||
dicts.add("'" + column.getDictType() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限前缀
|
||||
*
|
||||
* @param moduleName 模块名称
|
||||
* @param businessName 业务名称
|
||||
* @return 返回权限前缀
|
||||
*/
|
||||
public static String getPermissionPrefix(String moduleName, String businessName) {
|
||||
return StringUtils.format("{}:{}", moduleName, businessName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上级菜单ID字段
|
||||
*
|
||||
* @param paramsObj 生成其他选项
|
||||
* @return 上级菜单ID字段
|
||||
*/
|
||||
public static String getParentMenuId(Dict paramsObj) {
|
||||
if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
|
||||
&& StringUtils.isNotEmpty(paramsObj.getStr(GenConstants.PARENT_MENU_ID))) {
|
||||
return paramsObj.getStr(GenConstants.PARENT_MENU_ID);
|
||||
}
|
||||
return DEFAULT_PARENT_MENU_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取树编码
|
||||
*
|
||||
* @param paramsObj 生成其他选项
|
||||
* @return 树编码
|
||||
*/
|
||||
public static String getTreecode(Map<String, Object> paramsObj) {
|
||||
if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE)) {
|
||||
return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE)));
|
||||
}
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取树父编码
|
||||
*
|
||||
* @param paramsObj 生成其他选项
|
||||
* @return 树父编码
|
||||
*/
|
||||
public static String getTreeParentCode(Dict paramsObj) {
|
||||
if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
|
||||
return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_PARENT_CODE));
|
||||
}
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取树名称
|
||||
*
|
||||
* @param paramsObj 生成其他选项
|
||||
* @return 树名称
|
||||
*/
|
||||
public static String getTreeName(Dict paramsObj) {
|
||||
if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME)) {
|
||||
return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_NAME));
|
||||
}
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取需要在哪一列上面显示展开按钮
|
||||
*
|
||||
* @param genTable 业务表对象
|
||||
* @return 展开按钮列序号
|
||||
*/
|
||||
public static int getExpandColumn(GenTable genTable) {
|
||||
String options = genTable.getOptions();
|
||||
Dict paramsObj = JsonUtils.parseMap(options);
|
||||
String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
|
||||
int num = 0;
|
||||
for (GenTableColumn column : genTable.getColumns()) {
|
||||
if (column.isList()) {
|
||||
num++;
|
||||
String columnName = column.getColumnName();
|
||||
if (columnName.equals(treeName)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
# 代码生成
|
||||
gen:
|
||||
# 作者
|
||||
author: Lion Li
|
||||
# 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
|
||||
packageName: org.dromara.system
|
||||
# 自动去除表前缀,默认是false
|
||||
autoRemovePre: false
|
||||
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
|
||||
tablePrefix: sys_
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.generator.mapper.GenTableColumnMapper">
|
||||
|
||||
<resultMap type="org.dromara.generator.domain.GenTableColumn" id="GenTableColumnResult">
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="org.dromara.generator.mapper.GenTableMapper">
|
||||
|
||||
<!-- 多结构嵌套自动映射需带上每个实体的主键id 否则映射会失败 -->
|
||||
<resultMap type="org.dromara.generator.domain.GenTable" id="GenTableResult">
|
||||
<id property="tableId" column="table_id" />
|
||||
<collection property="columns" javaType="java.util.List" resultMap="GenTableColumnResult" />
|
||||
</resultMap>
|
||||
|
||||
<resultMap type="org.dromara.generator.domain.GenTableColumn" id="GenTableColumnResult">
|
||||
<id property="columnId" column="column_id"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="genSelect">
|
||||
SELECT t.table_id, t.data_name, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
|
||||
c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
|
||||
FROM gen_table t
|
||||
LEFT JOIN gen_table_column c ON t.table_id = c.table_id
|
||||
</sql>
|
||||
|
||||
<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
|
||||
<include refid="genSelect"/>
|
||||
where t.table_id = #{tableId} order by c.sort
|
||||
</select>
|
||||
|
||||
<select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
|
||||
<include refid="genSelect"/>
|
||||
where t.table_name = #{tableName} order by c.sort
|
||||
</select>
|
||||
|
||||
<select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
|
||||
<include refid="genSelect"/>
|
||||
order by c.sort
|
||||
</select>
|
||||
|
||||
<select id="selectTableNameList" resultType="java.lang.String">
|
||||
select table_name from gen_table where data_name = #{dataName,jdbcType=VARCHAR}
|
||||
</select>
|
||||
</mapper>
|
@ -0,0 +1,3 @@
|
||||
java包使用 `.` 分割 resource 目录使用 `/` 分割
|
||||
<br>
|
||||
此文件目的 防止文件夹粘连找不到 `xml` 文件
|
@ -0,0 +1,50 @@
|
||||
package ${packageName}.domain.bo;
|
||||
|
||||
import ${packageName}.domain.${ClassName};
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import jakarta.validation.constraints.*;
|
||||
#foreach ($import in $importList)
|
||||
import ${import};
|
||||
#end
|
||||
|
||||
/**
|
||||
* ${functionName}业务对象 ${tableName}
|
||||
*
|
||||
* @author ${author}
|
||||
* @date ${datetime}
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false)
|
||||
public class ${ClassName}Bo extends BaseEntity {
|
||||
|
||||
#foreach ($column in $columns)
|
||||
#if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit))
|
||||
/**
|
||||
* $column.columnComment
|
||||
*/
|
||||
#if($column.insert && $column.edit)
|
||||
#set($Group="AddGroup.class, EditGroup.class")
|
||||
#elseif($column.insert)
|
||||
#set($Group="AddGroup.class")
|
||||
#elseif($column.edit)
|
||||
#set($Group="EditGroup.class")
|
||||
#end
|
||||
#if($column.required)
|
||||
#if($column.javaType == 'String')
|
||||
@NotBlank(message = "$column.columnComment不能为空", groups = { $Group })
|
||||
#else
|
||||
@NotNull(message = "$column.columnComment不能为空", groups = { $Group })
|
||||
#end
|
||||
#end
|
||||
private $column.javaType $column.javaField;
|
||||
|
||||
#end
|
||||
#end
|
||||
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package ${packageName}.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.constraints.*;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||
import org.dromara.common.log.annotation.Log;
|
||||
import org.dromara.common.web.core.BaseController;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import org.dromara.common.core.domain.R;
|
||||
import org.dromara.common.core.validate.AddGroup;
|
||||
import org.dromara.common.core.validate.EditGroup;
|
||||
import org.dromara.common.log.enums.BusinessType;
|
||||
import org.dromara.common.excel.utils.ExcelUtil;
|
||||
import ${packageName}.domain.vo.${ClassName}Vo;
|
||||
import ${packageName}.domain.bo.${ClassName}Bo;
|
||||
import ${packageName}.service.I${ClassName}Service;
|
||||
#if($table.crud)
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
#elseif($table.tree)
|
||||
#end
|
||||
|
||||
/**
|
||||
* ${functionName}
|
||||
*
|
||||
* @author ${author}
|
||||
* @date ${datetime}
|
||||
*/
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/${moduleName}/${businessName}")
|
||||
public class ${ClassName}Controller extends BaseController {
|
||||
|
||||
private final I${ClassName}Service ${className}Service;
|
||||
|
||||
/**
|
||||
* 查询${functionName}列表
|
||||
*/
|
||||
@SaCheckPermission("${permissionPrefix}:list")
|
||||
@GetMapping("/list")
|
||||
#if($table.crud)
|
||||
public TableDataInfo<${ClassName}Vo> list(${ClassName}Bo bo, PageQuery pageQuery) {
|
||||
return ${className}Service.queryPageList(bo, pageQuery);
|
||||
}
|
||||
#elseif($table.tree)
|
||||
public R<List<${ClassName}Vo>> list(${ClassName}Bo bo) {
|
||||
List<${ClassName}Vo> list = ${className}Service.queryList(bo);
|
||||
return R.ok(list);
|
||||
}
|
||||
#end
|
||||
|
||||
/**
|
||||
* 导出${functionName}列表
|
||||
*/
|
||||
@SaCheckPermission("${permissionPrefix}:export")
|
||||
@Log(title = "${functionName}", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(${ClassName}Bo bo, HttpServletResponse response) {
|
||||
List<${ClassName}Vo> list = ${className}Service.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取${functionName}详细信息
|
||||
*
|
||||
* @param ${pkColumn.javaField} 主键
|
||||
*/
|
||||
@SaCheckPermission("${permissionPrefix}:query")
|
||||
@GetMapping("/{${pkColumn.javaField}}")
|
||||
public R<${ClassName}Vo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable ${pkColumn.javaType} ${pkColumn.javaField}) {
|
||||
return R.ok(${className}Service.queryById(${pkColumn.javaField}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增${functionName}
|
||||
*/
|
||||
@SaCheckPermission("${permissionPrefix}:add")
|
||||
@Log(title = "${functionName}", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit()
|
||||
@PostMapping()
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) {
|
||||
return toAjax(${className}Service.insertByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改${functionName}
|
||||
*/
|
||||
@SaCheckPermission("${permissionPrefix}:edit")
|
||||
@Log(title = "${functionName}", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit()
|
||||
@PutMapping()
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) {
|
||||
return toAjax(${className}Service.updateByBo(bo));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField}s 主键串
|
||||
*/
|
||||
@SaCheckPermission("${permissionPrefix}:remove")
|
||||
@Log(title = "${functionName}", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{${pkColumn.javaField}s}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) {
|
||||
return toAjax(${className}Service.deleteWithValidByIds(List.of(${pkColumn.javaField}s), true));
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package ${packageName}.domain;
|
||||
|
||||
#foreach ($column in $columns)
|
||||
#if($column.javaField=='tenantId')
|
||||
#set($IsTenant=1)
|
||||
#end
|
||||
#end
|
||||
#if($IsTenant==1)
|
||||
import org.dromara.common.tenant.core.TenantEntity;
|
||||
#else
|
||||
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
||||
#end
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
#foreach ($import in $importList)
|
||||
import ${import};
|
||||
#end
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
* ${functionName}对象 ${tableName}
|
||||
*
|
||||
* @author ${author}
|
||||
* @date ${datetime}
|
||||
*/
|
||||
#if($IsTenant==1)
|
||||
#set($Entity="TenantEntity")
|
||||
#else
|
||||
#set($Entity="BaseEntity")
|
||||
#end
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("${tableName}")
|
||||
public class ${ClassName} extends ${Entity} {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
#foreach ($column in $columns)
|
||||
#if(!$table.isSuperColumn($column.javaField))
|
||||
/**
|
||||
* $column.columnComment
|
||||
*/
|
||||
#if($column.javaField=='delFlag')
|
||||
@TableLogic
|
||||
#end
|
||||
#if($column.javaField=='version')
|
||||
@Version
|
||||
#end
|
||||
#if($column.isPk==1)
|
||||
@TableId(value = "$column.columnName")
|
||||
#end
|
||||
private $column.javaType $column.javaField;
|
||||
|
||||
#end
|
||||
#end
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package ${packageName}.mapper;
|
||||
|
||||
import ${packageName}.domain.${ClassName};
|
||||
import ${packageName}.domain.vo.${ClassName}Vo;
|
||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||
|
||||
/**
|
||||
* ${functionName}Mapper接口
|
||||
*
|
||||
* @author ${author}
|
||||
* @date ${datetime}
|
||||
*/
|
||||
public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}, ${ClassName}Vo> {
|
||||
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package ${packageName}.service;
|
||||
|
||||
import ${packageName}.domain.vo.${ClassName}Vo;
|
||||
import ${packageName}.domain.bo.${ClassName}Bo;
|
||||
#if($table.crud)
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
#end
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ${functionName}Service接口
|
||||
*
|
||||
* @author ${author}
|
||||
* @date ${datetime}
|
||||
*/
|
||||
public interface I${ClassName}Service {
|
||||
|
||||
/**
|
||||
* 查询${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField} 主键
|
||||
* @return ${functionName}
|
||||
*/
|
||||
${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField});
|
||||
|
||||
#if($table.crud)
|
||||
/**
|
||||
* 分页查询${functionName}列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return ${functionName}分页列表
|
||||
*/
|
||||
TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery);
|
||||
#end
|
||||
|
||||
/**
|
||||
* 查询符合条件的${functionName}列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return ${functionName}列表
|
||||
*/
|
||||
List<${ClassName}Vo> queryList(${ClassName}Bo bo);
|
||||
|
||||
/**
|
||||
* 新增${functionName}
|
||||
*
|
||||
* @param bo ${functionName}
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
Boolean insertByBo(${ClassName}Bo bo);
|
||||
|
||||
/**
|
||||
* 修改${functionName}
|
||||
*
|
||||
* @param bo ${functionName}
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
Boolean updateByBo(${ClassName}Bo bo);
|
||||
|
||||
/**
|
||||
* 校验并批量删除${functionName}信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid);
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
package ${packageName}.service.impl;
|
||||
|
||||
import org.dromara.common.core.utils.MapstructUtils;
|
||||
import org.dromara.common.core.utils.StringUtils;
|
||||
#if($table.crud)
|
||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
#end
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import ${packageName}.domain.bo.${ClassName}Bo;
|
||||
import ${packageName}.domain.vo.${ClassName}Vo;
|
||||
import ${packageName}.domain.${ClassName};
|
||||
import ${packageName}.mapper.${ClassName}Mapper;
|
||||
import ${packageName}.service.I${ClassName}Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* ${functionName}Service业务层处理
|
||||
*
|
||||
* @author ${author}
|
||||
* @date ${datetime}
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ${ClassName}ServiceImpl implements I${ClassName}Service {
|
||||
|
||||
private final ${ClassName}Mapper baseMapper;
|
||||
|
||||
/**
|
||||
* 查询${functionName}
|
||||
*
|
||||
* @param ${pkColumn.javaField} 主键
|
||||
* @return ${functionName}
|
||||
*/
|
||||
@Override
|
||||
public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}){
|
||||
return baseMapper.selectVoById(${pkColumn.javaField});
|
||||
}
|
||||
|
||||
#if($table.crud)
|
||||
/**
|
||||
* 分页查询${functionName}列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @param pageQuery 分页参数
|
||||
* @return ${functionName}分页列表
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo);
|
||||
Page<${ClassName}Vo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
#end
|
||||
|
||||
/**
|
||||
* 查询符合条件的${functionName}列表
|
||||
*
|
||||
* @param bo 查询条件
|
||||
* @return ${functionName}列表
|
||||
*/
|
||||
@Override
|
||||
public List<${ClassName}Vo> queryList(${ClassName}Bo bo) {
|
||||
LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName}Bo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery();
|
||||
#foreach($column in $columns)
|
||||
#if($column.query)
|
||||
#set($queryType=$column.queryType)
|
||||
#set($javaField=$column.javaField)
|
||||
#set($javaType=$column.javaType)
|
||||
#set($columnName=$column.columnName)
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
#set($mpMethod=$column.queryType.toLowerCase())
|
||||
#if($queryType != 'BETWEEN')
|
||||
#if($javaType == 'String')
|
||||
#set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())')
|
||||
#else
|
||||
#set($condition='bo.get'+$AttrName+'() != null')
|
||||
#end
|
||||
lqw.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName());
|
||||
#else
|
||||
lqw.between(params.get("begin$AttrName") != null && params.get("end$AttrName") != null,
|
||||
${ClassName}::get$AttrName ,params.get("begin$AttrName"), params.get("end$AttrName"));
|
||||
#end
|
||||
#end
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
#if($column.isPk==1)
|
||||
lqw.orderByAsc(${ClassName}::get$AttrName);
|
||||
#end
|
||||
#end
|
||||
return lqw;
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增${functionName}
|
||||
*
|
||||
* @param bo ${functionName}
|
||||
* @return 是否新增成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(${ClassName}Bo bo) {
|
||||
${ClassName} add = MapstructUtils.convert(bo, ${ClassName}.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
#set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)})
|
||||
if (flag) {
|
||||
bo.set$pk(add.get$pk());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改${functionName}
|
||||
*
|
||||
* @param bo ${functionName}
|
||||
* @return 是否修改成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(${ClassName}Bo bo) {
|
||||
${ClassName} update = MapstructUtils.convert(bo, ${ClassName}.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
private void validEntityBeforeSave(${ClassName} entity){
|
||||
//TODO 做一些数据校验,如唯一约束
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验并批量删除${functionName}信息
|
||||
*
|
||||
* @param ids 待删除的主键集合
|
||||
* @param isValid 是否进行有效性校验
|
||||
* @return 是否删除成功
|
||||
*/
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return baseMapper.deleteByIds(ids) > 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package ${packageName}.domain.vo;
|
||||
|
||||
#foreach ($import in $importList)
|
||||
import ${import};
|
||||
#end
|
||||
import ${packageName}.domain.${ClassName};
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import org.dromara.common.excel.annotation.ExcelDictFormat;
|
||||
import org.dromara.common.excel.convert.ExcelDictConvert;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ${functionName}视图对象 ${tableName}
|
||||
*
|
||||
* @author ${author}
|
||||
* @date ${datetime}
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
@AutoMapper(target = ${ClassName}.class)
|
||||
public class ${ClassName}Vo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
#foreach ($column in $columns)
|
||||
#if($column.list)
|
||||
/**
|
||||
* $column.columnComment
|
||||
*/
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if(${column.dictType} && ${column.dictType} != '')
|
||||
@ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(dictType = "${column.dictType}")
|
||||
#elseif($parentheseIndex != -1)
|
||||
@ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
|
||||
@ExcelDictFormat(readConverterExp = "$column.readConverterExp()")
|
||||
#else
|
||||
@ExcelProperty(value = "${comment}")
|
||||
#end
|
||||
private $column.javaType $column.javaField;
|
||||
|
||||
#if($column.htmlType == "imageUpload")
|
||||
/**
|
||||
* ${column.columnComment}Url
|
||||
*/
|
||||
@Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}")
|
||||
private String ${column.javaField}Url;
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
-- 菜单 SQL
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate, null, null, '${functionName}菜单');
|
||||
|
||||
-- 按钮 SQL
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate, null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate, null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate, null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate, null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate, null, null, '');
|
@ -0,0 +1,20 @@
|
||||
-- 菜单 SQL
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, now(), null, null, '${functionName}菜单');
|
||||
|
||||
-- 按钮 SQL
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, now(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, now(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, now(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, now(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, now(), null, null, '');
|
||||
|
@ -0,0 +1,19 @@
|
||||
-- 菜单 SQL
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate(), null, null, '${functionName}菜单');
|
||||
|
||||
-- 按钮 SQL
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate(), null, null, '');
|
@ -0,0 +1,19 @@
|
||||
-- 菜单 SQL
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, getdate(), null, null, '${functionName}菜单');
|
||||
|
||||
-- 按钮 SQL
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, getdate(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, getdate(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, getdate(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, getdate(), null, null, '');
|
||||
|
||||
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
|
||||
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, getdate(), null, null, '');
|
@ -0,0 +1,63 @@
|
||||
import request from '@/utils/request';
|
||||
import { AxiosPromise } from 'axios';
|
||||
import { ${BusinessName}VO, ${BusinessName}Form, ${BusinessName}Query } from '@/api/${moduleName}/${businessName}/types';
|
||||
|
||||
/**
|
||||
* 查询${functionName}列表
|
||||
* @param query
|
||||
* @returns {*}
|
||||
*/
|
||||
|
||||
export const list${BusinessName} = (query?: ${BusinessName}Query): AxiosPromise<${BusinessName}VO[]> => {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询${functionName}详细
|
||||
* @param ${pkColumn.javaField}
|
||||
*/
|
||||
export const get${BusinessName} = (${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> => {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||
method: 'get'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 新增${functionName}
|
||||
* @param data
|
||||
*/
|
||||
export const add${BusinessName} = (data: ${BusinessName}Form) => {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 修改${functionName}
|
||||
* @param data
|
||||
*/
|
||||
export const update${BusinessName} = (data: ${BusinessName}Form) => {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除${functionName}
|
||||
* @param ${pkColumn.javaField}
|
||||
*/
|
||||
export const del${BusinessName} = (${pkColumn.javaField}: string | number | Array<string | number>) => {
|
||||
return request({
|
||||
url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
|
||||
method: 'delete'
|
||||
});
|
||||
};
|
@ -0,0 +1,64 @@
|
||||
export interface ${BusinessName}VO {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.list)
|
||||
/**
|
||||
* $column.columnComment
|
||||
*/
|
||||
$column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
|
||||
#elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
|
||||
#elseif($column.javaType == 'Boolean') boolean;
|
||||
#else string;
|
||||
#end
|
||||
#if($column.htmlType == "imageUpload")
|
||||
/**
|
||||
* ${column.columnComment}Url
|
||||
*/
|
||||
${column.javaField}Url: string;
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#if ($table.tree)
|
||||
/**
|
||||
* 子对象
|
||||
*/
|
||||
children: ${BusinessName}VO[];
|
||||
#end
|
||||
}
|
||||
|
||||
export interface ${BusinessName}Form extends BaseEntity {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.insert || $column.edit)
|
||||
/**
|
||||
* $column.columnComment
|
||||
*/
|
||||
$column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
|
||||
#elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
|
||||
#elseif($column.javaType == 'Boolean') boolean;
|
||||
#else string;
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
}
|
||||
|
||||
export interface ${BusinessName}Query #if(!${treeCode})extends PageQuery #end{
|
||||
|
||||
#foreach ($column in $columns)
|
||||
#if($column.query)
|
||||
/**
|
||||
* $column.columnComment
|
||||
*/
|
||||
$column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
|
||||
#elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
|
||||
#elseif($column.javaType == 'Boolean') boolean;
|
||||
#else string;
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
/**
|
||||
* 日期范围参数
|
||||
*/
|
||||
params?: any;
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,498 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
#foreach($column in $columns)
|
||||
#if($column.query)
|
||||
#set($dictType=$column.dictType)
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($column.htmlType == "input" || $column.htmlType == "textarea")
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-input v-model="queryParams.${column.javaField}" placeholder="请输入${comment}" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
|
||||
<el-option v-for="dict in ${dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
|
||||
<el-option label="请选择字典生成" value="" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-date-picker clearable
|
||||
v-model="queryParams.${column.javaField}"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择${comment}"
|
||||
/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
<el-form-item label="${comment}" style="width: 308px">
|
||||
<el-date-picker
|
||||
v-model="dateRange${AttrName}"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
|
||||
/>
|
||||
</el-form-item>
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['${moduleName}:${businessName}:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">展开/折叠</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
<el-table
|
||||
ref="${businessName}TableRef"
|
||||
v-loading="loading"
|
||||
:data="${businessName}List"
|
||||
row-key="${treeCode}"
|
||||
:default-expand-all="isExpandAll"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
>
|
||||
#foreach($column in $columns)
|
||||
#set($javaField=$column.javaField)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($column.pk)
|
||||
#elseif($column.list && $column.htmlType == "datetime")
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && $column.htmlType == "imageUpload")
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}Url" width="100">
|
||||
<template #default="scope">
|
||||
<image-preview :src="scope.row.${javaField}Url" :width="50" :height="50"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && $column.dictType && "" != $column.dictType)
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}">
|
||||
<template #default="scope">
|
||||
#if($column.htmlType == "checkbox")
|
||||
<dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
|
||||
#else
|
||||
<dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
|
||||
#end
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && "" != $javaField)
|
||||
#if(${foreach.index} == 1)
|
||||
<el-table-column label="${comment}" prop="${javaField}" />
|
||||
#else
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}" />
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']" />
|
||||
</el-tooltip>
|
||||
<el-tooltip content="新增" placement="top">
|
||||
<el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${moduleName}:${businessName}:add']" />
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
<!-- 添加或修改${functionName}对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
<el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
|
||||
#foreach($column in $columns)
|
||||
#set($field=$column.javaField)
|
||||
#if(($column.insert || $column.edit) && !$column.pk)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#set($dictType=$column.dictType)
|
||||
#if("" != $treeParentCode && $column.javaField == $treeParentCode)
|
||||
<el-form-item label="${comment}" prop="${treeParentCode}">
|
||||
<el-tree-select
|
||||
v-model="form.${treeParentCode}"
|
||||
:data="${businessName}Options"
|
||||
:props="{ value: '${treeCode}', label: '${treeName}', children: 'children' }"
|
||||
value-key="${treeCode}"
|
||||
placeholder="请选择${comment}"
|
||||
check-strictly
|
||||
/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "input")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-input v-model="form.${field}" placeholder="请输入${comment}" />
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "imageUpload")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<image-upload v-model="form.${field}"/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "fileUpload")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<file-upload v-model="form.${field}"/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "editor")
|
||||
<el-form-item label="${comment}">
|
||||
<editor v-model="form.${field}" :min-height="192"/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "select" && "" != $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-select v-model="form.${field}" placeholder="请选择${comment}">
|
||||
<el-option
|
||||
v-for="dict in ${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long")
|
||||
:value="parseInt(dict.value)"
|
||||
#else
|
||||
:value="dict.value"
|
||||
#end
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "select" && $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-select v-model="form.${field}" placeholder="请选择${comment}">
|
||||
<el-option label="请选择字典生成" value="" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "checkbox" && "" != $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-checkbox-group v-model="form.${field}">
|
||||
<el-checkbox
|
||||
v-for="dict in ${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.value">
|
||||
{{dict.label}}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "checkbox" && $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-checkbox-group v-model="form.${field}">
|
||||
<el-checkbox>请选择字典生成</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "radio" && "" != $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-radio-group v-model="form.${field}">
|
||||
<el-radio
|
||||
v-for="dict in ${dictType}"
|
||||
:key="dict.value"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long")
|
||||
:value="parseInt(dict.value)"
|
||||
#else
|
||||
:value="dict.value"
|
||||
#end
|
||||
>{{dict.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "radio" && $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-radio-group v-model="form.${field}">
|
||||
<el-radio value="1">请选择字典生成</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "datetime")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-date-picker clearable
|
||||
v-model="form.${field}"
|
||||
type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="选择${comment}"
|
||||
/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "textarea")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="${BusinessName}" lang="ts">
|
||||
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
|
||||
import { ${BusinessName}VO, ${BusinessName}Query, ${BusinessName}Form } from '@/api/${moduleName}/${businessName}/types';
|
||||
|
||||
type ${BusinessName}Option = {
|
||||
${treeCode}: number;
|
||||
${treeName}: string;
|
||||
children?: ${BusinessName}Option[];
|
||||
}
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;;
|
||||
|
||||
#if(${dicts} != '')
|
||||
#set($dictsNoSymbol=$dicts.replace("'", ""))
|
||||
const { ${dictsNoSymbol} } = toRefs<any>(proxy?.useDict(${dicts}));
|
||||
#end
|
||||
|
||||
const ${businessName}List = ref<${BusinessName}VO[]>([]);
|
||||
const ${businessName}Options = ref<${BusinessName}Option[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const showSearch = ref(true);
|
||||
const isExpandAll = ref(true);
|
||||
const loading = ref(false);
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const ${businessName}FormRef = ref<ElFormInstance>();
|
||||
const ${businessName}TableRef = ref<ElTableInstance>()
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
const dateRange${AttrName} = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
#end
|
||||
#end
|
||||
|
||||
const initFormData: ${BusinessName}Form = {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.insert || $column.edit)
|
||||
#if($column.htmlType == "checkbox")
|
||||
$column.javaField: []#if($foreach.count != $columns.size()),#end
|
||||
#else
|
||||
$column.javaField: undefined#if($foreach.count != $columns.size()),#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
}
|
||||
|
||||
const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
|
||||
form: {...initFormData},
|
||||
queryParams: {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.query)
|
||||
#if($column.htmlType != "datetime" || $column.queryType != "BETWEEN")
|
||||
$column.javaField: undefined,
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
params: {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.query)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
$column.javaField: undefined#if($foreach.count != $columns.size()),#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.insert || $column.edit)
|
||||
#if($column.required)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
$column.javaField: [
|
||||
{ required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
|
||||
]#if($foreach.count != $columns.size()),#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询${functionName}列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
queryParams.value.params = {};
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
proxy?.addDateRange(queryParams.value, dateRange${AttrName}.value, '${AttrName}');
|
||||
#end
|
||||
#end
|
||||
const res = await list${BusinessName}(queryParams.value);
|
||||
const data = proxy?.handleTree<${BusinessName}VO>(res.data, "${treeCode}", "${treeParentCode}");
|
||||
if (data) {
|
||||
${businessName}List.value = data;
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 查询${functionName}下拉树结构 */
|
||||
const getTreeselect = async () => {
|
||||
const res = await list${BusinessName}();
|
||||
${businessName}Options.value = [];
|
||||
const data: ${BusinessName}Option = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
|
||||
data.children = proxy?.handleTree<${BusinessName}Option>(res.data, "${treeCode}", "${treeParentCode}");
|
||||
${businessName}Options.value.push(data);
|
||||
}
|
||||
|
||||
// 取消按钮
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
}
|
||||
|
||||
// 表单重置
|
||||
const reset = () => {
|
||||
form.value = {...initFormData}
|
||||
${businessName}FormRef.value?.resetFields();
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
getList();
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
dateRange${AttrName}.value = ['', ''];
|
||||
#end
|
||||
#end
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = (row?: ${BusinessName}VO) => {
|
||||
reset();
|
||||
getTreeselect();
|
||||
if (row != null && row.${treeCode}) {
|
||||
form.value.${treeParentCode} = row.${treeCode};
|
||||
} else {
|
||||
form.value.${treeParentCode} = 0;
|
||||
}
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加${functionName}";
|
||||
}
|
||||
|
||||
/** 展开/折叠操作 */
|
||||
const handleToggleExpandAll = () => {
|
||||
isExpandAll.value = !isExpandAll.value;
|
||||
toggleExpandAll(${businessName}List.value, isExpandAll.value)
|
||||
}
|
||||
|
||||
/** 展开/折叠操作 */
|
||||
const toggleExpandAll = (data: ${BusinessName}VO[], status: boolean) => {
|
||||
data.forEach((item) => {
|
||||
${businessName}TableRef.value?.toggleRowExpansion(item, status)
|
||||
if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
|
||||
})
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row: ${BusinessName}VO) => {
|
||||
reset();
|
||||
await getTreeselect();
|
||||
if (row != null) {
|
||||
form.value.${treeParentCode} = row.${treeParentCode};
|
||||
}
|
||||
const res = await get${BusinessName}(row.${pkColumn.javaField});
|
||||
Object.assign(form.value, res.data);
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "checkbox")
|
||||
form.value.$column.javaField = form.value.${column.javaField}.split(",");
|
||||
#end
|
||||
#end
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改${functionName}";
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
${businessName}FormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "checkbox")
|
||||
form.value.$column.javaField = form.value.${column.javaField}.join(",");
|
||||
#end
|
||||
#end
|
||||
if (form.value.${pkColumn.javaField}) {
|
||||
await update${BusinessName}(form.value).finally(() => buttonLoading.value = false);
|
||||
} else {
|
||||
await add${BusinessName}(form.value).finally(() => buttonLoading.value = false);
|
||||
}
|
||||
proxy?.#[[$modal]]#.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row: ${BusinessName}VO) => {
|
||||
await proxy?.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?');
|
||||
loading.value = true;
|
||||
await del${BusinessName}(row.${pkColumn.javaField}).finally(() => loading.value = false);
|
||||
await getList();
|
||||
proxy?.#[[$modal]]#.msgSuccess("删除成功");
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
@ -0,0 +1,459 @@
|
||||
<template>
|
||||
<div class="p-2">
|
||||
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||
<div v-show="showSearch" class="mb-[10px]">
|
||||
<el-card shadow="hover">
|
||||
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||
#foreach($column in $columns)
|
||||
#if($column.query)
|
||||
#set($dictType=$column.dictType)
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($column.htmlType == "input" || $column.htmlType == "textarea")
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-input v-model="queryParams.${column.javaField}" placeholder="请输入${comment}" clearable @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable >
|
||||
<el-option v-for="dict in ${dictType}" :key="dict.value" :label="dict.label" :value="dict.value"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable >
|
||||
<el-option label="请选择字典生成" value="" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
|
||||
<el-form-item label="${comment}" prop="${column.javaField}">
|
||||
<el-date-picker clearable
|
||||
v-model="queryParams.${column.javaField}"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择${comment}"
|
||||
/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
<el-form-item label="${comment}" style="width: 308px">
|
||||
<el-date-picker
|
||||
v-model="dateRange${AttrName}"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
type="daterange"
|
||||
range-separator="-"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
|
||||
/>
|
||||
</el-form-item>
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</transition>
|
||||
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['${moduleName}:${businessName}:add']">新增</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['${moduleName}:${businessName}:export']">导出</el-button>
|
||||
</el-col>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
</template>
|
||||
|
||||
<el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
#foreach($column in $columns)
|
||||
#set($javaField=$column.javaField)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#if($column.pk)
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}" v-if="${column.list}" />
|
||||
#elseif($column.list && $column.htmlType == "datetime")
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
|
||||
<template #default="scope">
|
||||
<span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && $column.htmlType == "imageUpload")
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}Url" width="100">
|
||||
<template #default="scope">
|
||||
<image-preview :src="scope.row.${javaField}Url" :width="50" :height="50"/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && $column.dictType && "" != $column.dictType)
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}">
|
||||
<template #default="scope">
|
||||
#if($column.htmlType == "checkbox")
|
||||
<dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
|
||||
#else
|
||||
<dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
|
||||
#end
|
||||
</template>
|
||||
</el-table-column>
|
||||
#elseif($column.list && "" != $javaField)
|
||||
<el-table-column label="${comment}" align="center" prop="${javaField}" />
|
||||
#end
|
||||
#end
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template #default="scope">
|
||||
<el-tooltip content="修改" placement="top">
|
||||
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']"></el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="删除" placement="top">
|
||||
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']"></el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</el-card>
|
||||
<!-- 添加或修改${functionName}对话框 -->
|
||||
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||
<el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
|
||||
#foreach($column in $columns)
|
||||
#set($field=$column.javaField)
|
||||
#if(($column.insert || $column.edit) && !$column.pk)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
#set($dictType=$column.dictType)
|
||||
#if($column.htmlType == "input")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-input v-model="form.${field}" placeholder="请输入${comment}" />
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "imageUpload")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<image-upload v-model="form.${field}"/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "fileUpload")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<file-upload v-model="form.${field}"/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "editor")
|
||||
<el-form-item label="${comment}">
|
||||
<editor v-model="form.${field}" :min-height="192"/>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "select" && "" != $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-select v-model="form.${field}" placeholder="请选择${comment}">
|
||||
<el-option
|
||||
v-for="dict in ${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long")
|
||||
:value="parseInt(dict.value)"
|
||||
#else
|
||||
:value="dict.value"
|
||||
#end
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "select" && $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-select v-model="form.${field}" placeholder="请选择${comment}">
|
||||
<el-option label="请选择字典生成" value="" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "checkbox" && "" != $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-checkbox-group v-model="form.${field}">
|
||||
<el-checkbox
|
||||
v-for="dict in ${dictType}"
|
||||
:key="dict.value"
|
||||
:label="dict.value">
|
||||
{{dict.label}}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "checkbox" && $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-checkbox-group v-model="form.${field}">
|
||||
<el-checkbox>请选择字典生成</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "radio" && "" != $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-radio-group v-model="form.${field}">
|
||||
<el-radio
|
||||
v-for="dict in ${dictType}"
|
||||
:key="dict.value"
|
||||
#if($column.javaType == "Integer" || $column.javaType == "Long")
|
||||
:value="parseInt(dict.value)"
|
||||
#else
|
||||
:value="dict.value"
|
||||
#end
|
||||
>{{dict.label}}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "radio" && $dictType)
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-radio-group v-model="form.${field}">
|
||||
<el-radio value="1">请选择字典生成</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "datetime")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-date-picker clearable
|
||||
v-model="form.${field}"
|
||||
type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="请选择${comment}">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
#elseif($column.htmlType == "textarea")
|
||||
<el-form-item label="${comment}" prop="${field}">
|
||||
<el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
|
||||
</el-form-item>
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="${BusinessName}" lang="ts">
|
||||
import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from '@/api/${moduleName}/${businessName}';
|
||||
import { ${BusinessName}VO, ${BusinessName}Query, ${BusinessName}Form } from '@/api/${moduleName}/${businessName}/types';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
#if(${dicts} != '')
|
||||
#set($dictsNoSymbol=$dicts.replace("'", ""))
|
||||
const { ${dictsNoSymbol} } = toRefs<any>(proxy?.useDict(${dicts}));
|
||||
#end
|
||||
|
||||
const ${businessName}List = ref<${BusinessName}VO[]>([]);
|
||||
const buttonLoading = ref(false);
|
||||
const loading = ref(true);
|
||||
const showSearch = ref(true);
|
||||
const ids = ref<Array<string | number>>([]);
|
||||
const single = ref(true);
|
||||
const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
const dateRange${AttrName} = ref<[DateModelType, DateModelType]>(['', '']);
|
||||
#end
|
||||
#end
|
||||
|
||||
const queryFormRef = ref<ElFormInstance>();
|
||||
const ${businessName}FormRef = ref<ElFormInstance>();
|
||||
|
||||
const dialog = reactive<DialogOption>({
|
||||
visible: false,
|
||||
title: ''
|
||||
});
|
||||
|
||||
const initFormData: ${BusinessName}Form = {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.insert || $column.edit)
|
||||
#if($column.htmlType == "checkbox")
|
||||
$column.javaField: []#if($foreach.count != $columns.size()),#end
|
||||
#else
|
||||
$column.javaField: undefined#if($foreach.count != $columns.size()),#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
}
|
||||
const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
|
||||
form: {...initFormData},
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
#foreach ($column in $columns)
|
||||
#if($column.query)
|
||||
#if($column.htmlType != "datetime" || $column.queryType != "BETWEEN")
|
||||
$column.javaField: undefined,
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
params: {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.query)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
$column.javaField: undefined#if($foreach.count != $columns.size()),#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.insert || $column.edit)
|
||||
#if($column.required)
|
||||
#set($parentheseIndex=$column.columnComment.indexOf("("))
|
||||
#if($parentheseIndex != -1)
|
||||
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
|
||||
#else
|
||||
#set($comment=$column.columnComment)
|
||||
#end
|
||||
$column.javaField: [
|
||||
{ required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
|
||||
]#if($foreach.count != $columns.size()),#end
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
}
|
||||
});
|
||||
|
||||
const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
/** 查询${functionName}列表 */
|
||||
const getList = async () => {
|
||||
loading.value = true;
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
queryParams.value.params = {};
|
||||
#break
|
||||
#end
|
||||
#end
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
proxy?.addDateRange(queryParams.value, dateRange${AttrName}.value, '${AttrName}');
|
||||
#end
|
||||
#end
|
||||
const res = await list${BusinessName}(queryParams.value);
|
||||
${businessName}List.value = res.rows;
|
||||
total.value = res.total;
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
/** 取消按钮 */
|
||||
const cancel = () => {
|
||||
reset();
|
||||
dialog.visible = false;
|
||||
}
|
||||
|
||||
/** 表单重置 */
|
||||
const reset = () => {
|
||||
form.value = {...initFormData};
|
||||
${businessName}FormRef.value?.resetFields();
|
||||
}
|
||||
|
||||
/** 搜索按钮操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.value.pageNum = 1;
|
||||
getList();
|
||||
}
|
||||
|
||||
/** 重置按钮操作 */
|
||||
const resetQuery = () => {
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
|
||||
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
|
||||
dateRange${AttrName}.value = ['', ''];
|
||||
#end
|
||||
#end
|
||||
queryFormRef.value?.resetFields();
|
||||
handleQuery();
|
||||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: ${BusinessName}VO[]) => {
|
||||
ids.value = selection.map(item => item.${pkColumn.javaField});
|
||||
single.value = selection.length != 1;
|
||||
multiple.value = !selection.length;
|
||||
}
|
||||
|
||||
/** 新增按钮操作 */
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
dialog.visible = true;
|
||||
dialog.title = "添加${functionName}";
|
||||
}
|
||||
|
||||
/** 修改按钮操作 */
|
||||
const handleUpdate = async (row?: ${BusinessName}VO) => {
|
||||
reset();
|
||||
const _${pkColumn.javaField} = row?.${pkColumn.javaField} || ids.value[0]
|
||||
const res = await get${BusinessName}(_${pkColumn.javaField});
|
||||
Object.assign(form.value, res.data);
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "checkbox")
|
||||
form.value.$column.javaField = form.value.${column.javaField}.split(",");
|
||||
#end
|
||||
#end
|
||||
dialog.visible = true;
|
||||
dialog.title = "修改${functionName}";
|
||||
}
|
||||
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
${businessName}FormRef.value?.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
buttonLoading.value = true;
|
||||
#foreach ($column in $columns)
|
||||
#if($column.htmlType == "checkbox")
|
||||
form.value.$column.javaField = form.value.${column.javaField}.join(",");
|
||||
#end
|
||||
#end
|
||||
if (form.value.${pkColumn.javaField}) {
|
||||
await update${BusinessName}(form.value).finally(() => buttonLoading.value = false);
|
||||
} else {
|
||||
await add${BusinessName}(form.value).finally(() => buttonLoading.value = false);
|
||||
}
|
||||
proxy?.#[[$modal]]#.msgSuccess("操作成功");
|
||||
dialog.visible = false;
|
||||
await getList();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除按钮操作 */
|
||||
const handleDelete = async (row?: ${BusinessName}VO) => {
|
||||
const _${pkColumn.javaField}s = row?.${pkColumn.javaField} || ids.value;
|
||||
await proxy?.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + _${pkColumn.javaField}s + '"的数据项?').finally(() => loading.value = false);
|
||||
await del${BusinessName}(_${pkColumn.javaField}s);
|
||||
proxy?.#[[$modal]]#.msgSuccess("删除成功");
|
||||
await getList();
|
||||
}
|
||||
|
||||
/** 导出按钮操作 */
|
||||
const handleExport = () => {
|
||||
proxy?.download('${moduleName}/${businessName}/export', {
|
||||
...queryParams.value
|
||||
}, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
|
||||
|
||||
</mapper>
|
34
ruoyi-modules/ruoyi-job/pom.xml
Normal file
34
ruoyi-modules/ruoyi-job/pom.xml
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>ruoyi-job</artifactId>
|
||||
|
||||
<description>
|
||||
任务调度
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-job</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -0,0 +1 @@
|
||||
package org.dromara.job;
|
@ -0,0 +1,23 @@
|
||||
package org.dromara.job.snailjob;
|
||||
|
||||
import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
|
||||
import com.aizuda.snailjob.client.job.core.dto.JobArgs;
|
||||
import com.aizuda.snailjob.client.model.ExecuteResult;
|
||||
import com.aizuda.snailjob.common.core.util.JsonUtil;
|
||||
import com.aizuda.snailjob.common.log.SnailJobLog;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author opensnail
|
||||
* @date 2024-05-17
|
||||
*/
|
||||
@Component
|
||||
@JobExecutor(name = "testJobExecutor")
|
||||
public class TestAnnoJobExecutor {
|
||||
|
||||
public ExecuteResult jobExecute(JobArgs jobArgs) {
|
||||
SnailJobLog.LOCAL.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs));
|
||||
SnailJobLog.REMOTE.info("testJobExecutor. jobArgs:{}", JsonUtil.toJsonString(jobArgs));
|
||||
return ExecuteResult.success("测试成功");
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package org.dromara.job.snailjob;
|
||||
|
||||
import com.aizuda.snailjob.client.job.core.dto.JobArgs;
|
||||
import com.aizuda.snailjob.client.job.core.executor.AbstractJobExecutor;
|
||||
import com.aizuda.snailjob.client.model.ExecuteResult;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author opensnail
|
||||
* @date 2024-05-17
|
||||
*/
|
||||
@Component
|
||||
public class TestClassJobExecutor extends AbstractJobExecutor {
|
||||
|
||||
@Override
|
||||
protected ExecuteResult doJobExecute(JobArgs jobArgs) {
|
||||
return ExecuteResult.success("TestJobExecutor测试成功");
|
||||
}
|
||||
}
|
216
ruoyi-modules/ruoyi-system/pom.xml
Normal file
216
ruoyi-modules/ruoyi-system/pom.xml
Normal file
@ -0,0 +1,216 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-modules</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
|
||||
<description>
|
||||
system系统模块
|
||||
</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<!-- JSON解析(FastJSON) -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>2.0.32</version>
|
||||
</dependency>
|
||||
<!-- word转pdf转图片 -->
|
||||
<!-- docx4j 核心 -->
|
||||
<dependency>
|
||||
<groupId>org.docx4j</groupId>
|
||||
<artifactId>docx4j-core</artifactId>
|
||||
<version>11.5.3</version>
|
||||
</dependency>
|
||||
<!-- JAXB 引擎 -->
|
||||
<dependency>
|
||||
<groupId>org.docx4j</groupId>
|
||||
<artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
|
||||
<version>11.5.3</version>
|
||||
</dependency>
|
||||
<!-- XSL-FO 输出 PDF -->
|
||||
<dependency>
|
||||
<groupId>org.docx4j</groupId>
|
||||
<artifactId>docx4j-export-fo</artifactId>
|
||||
<version>11.5.3</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>fontbox</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- PDF 渲染用的 PDFBox -->
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
<version>2.0.29</version>
|
||||
</dependency>
|
||||
<!-- 必须配套引入 fontbox,否则运行时报错 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>fontbox</artifactId>
|
||||
<version>2.0.29</version>
|
||||
</dependency>
|
||||
|
||||
<!-- word 模版导出 poi-tl 模板引擎 -->
|
||||
<dependency>
|
||||
<groupId>com.deepoove</groupId>
|
||||
<artifactId>poi-tl</artifactId>
|
||||
<version>1.12.2</version> <!-- 建议使用最新版本 -->
|
||||
</dependency>
|
||||
|
||||
<!-- 在pdf上生成二维码 -->
|
||||
<!-- 支持中文字体 -->
|
||||
<dependency>
|
||||
<groupId>com.itextpdf</groupId>
|
||||
<artifactId>itext-asian</artifactId>
|
||||
<version>5.2.0</version>
|
||||
</dependency>
|
||||
<!-- iText -->
|
||||
<dependency>
|
||||
<groupId>com.itextpdf</groupId>
|
||||
<artifactId>itextpdf</artifactId>
|
||||
<version>5.5.13.3</version>
|
||||
</dependency>
|
||||
<!-- ZXing -->
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>3.5.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>javase</artifactId>
|
||||
<version>3.5.2</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-doc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-translation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- OSS功能模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-oss</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- excel-->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SMS功能模块 -->
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-sms</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-tenant</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-idempotent</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-sensitive</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-encrypt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-sse</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-common-jts</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.dromara</groupId>
|
||||
<artifactId>ruoyi-workflow</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-library</artifactId>
|
||||
<version>2.13.9</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna-platform</artifactId>
|
||||
<version>5.15.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,28 @@
|
||||
package org.dromara.common.constant;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/4/23 11:09
|
||||
*/
|
||||
public interface DesignMapFileConstant {
|
||||
|
||||
String DXF_BASE_PATH = "file" + File.separator + "resource" + File.separator + "design";
|
||||
|
||||
/**
|
||||
* WGS 84
|
||||
*/
|
||||
String EPSG4326 = "4326";
|
||||
|
||||
String EPSG4524 = "4524";
|
||||
|
||||
String DXFFileSuffix = "dxf";
|
||||
|
||||
String JSONFileSuffix = "json";
|
||||
|
||||
static String getDxfProjectPath(Long projectId) {
|
||||
return DXF_BASE_PATH + File.separator + projectId;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.dromara.common.constant;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/4/24 17:44
|
||||
*/
|
||||
public interface GeoJsonConstant {
|
||||
|
||||
String POINT = "Point";
|
||||
|
||||
String LINE = "LineString";
|
||||
|
||||
String POLYGON = "Polygon";
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package org.dromara.common.constant;
|
||||
|
||||
/**
|
||||
* @Author: Cory·铁憨憨
|
||||
* @Date: 2025-07-03-14:12
|
||||
* @Description: minio存储路线
|
||||
*/
|
||||
|
||||
public interface MinioPathConstant {
|
||||
// 联系单
|
||||
String ContactNotice = "contactNotice";
|
||||
// 联系单模板
|
||||
String ContactNoticeTemplate = "contactNotice/template";
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.dromara.common.constant;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 10:38
|
||||
* @Version 1.0
|
||||
*/public interface businessConstant {
|
||||
String REDIS_BAIDU_KEY = "baidu:access_token"; //百度token存储在redis中的key
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.dromara.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/4/14 14:03
|
||||
*/
|
||||
@Getter
|
||||
public enum DocumentStatusEnum {
|
||||
|
||||
NORMAL("正常", "0"),
|
||||
DELETE("删除", "1");
|
||||
|
||||
private final String text;
|
||||
|
||||
private final String value;
|
||||
|
||||
DocumentStatusEnum(String text, String value) {
|
||||
this.text = text;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package org.dromara.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/4/14 10:42
|
||||
*/
|
||||
@Getter
|
||||
public enum DocumentTypeEnum {
|
||||
|
||||
FOLDER("文件夹", "1"),
|
||||
FILE("文件", "2"),
|
||||
PICTURE("图片", "3");
|
||||
|
||||
private final String text;
|
||||
|
||||
private final String value;
|
||||
|
||||
DocumentTypeEnum(String text, String value) {
|
||||
this.text = text;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.dromara.common.utils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/5/27 9:16
|
||||
*/
|
||||
public class BigDecimalUtil {
|
||||
|
||||
/**
|
||||
* 计算百分比
|
||||
*
|
||||
* @param dividend 被除数
|
||||
* @param divisor 除数
|
||||
* @return 百分比(保留2位小数)如 12.34%
|
||||
*/
|
||||
public static BigDecimal toPercentage(BigDecimal dividend, BigDecimal divisor) {
|
||||
if (dividend == null || divisor == null || divisor.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return new BigDecimal(0);
|
||||
}
|
||||
return dividend.divide(divisor, 2, RoundingMode.HALF_UP).multiply(new BigDecimal("100"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package org.dromara.common.utils;
|
||||
|
||||
import org.apache.poi.util.Units;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFRun;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.DirectoryStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/4/17 14:53
|
||||
*/
|
||||
public class DocumentUtil {
|
||||
|
||||
/**
|
||||
* 在给定的 run 里插入图片,并按原始大小(或缩放后大小)设置宽高。
|
||||
*
|
||||
* @param run 要插入图片的 XWPFRun
|
||||
* @param imagePath 本地图片路径或 URL(这里示例用本地文件)
|
||||
* @param document 当前文档对象
|
||||
* @param maxWidthPx 最大允许宽度(像素),如果原图更宽就按比例缩放;设置为 <=0 则不缩放
|
||||
*/
|
||||
public static void insertImageDynamic(XWPFRun run,
|
||||
String imagePath,
|
||||
XWPFDocument document,
|
||||
int maxWidthPx) throws Exception {
|
||||
// 1. 先把图片读到 byte[]
|
||||
byte[] imgBytes = Files.readAllBytes(Paths.get(imagePath));
|
||||
// 2. 用 ImageIO 读出宽高(像素)
|
||||
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imgBytes));
|
||||
int widthPx = img.getWidth();
|
||||
int heightPx = img.getHeight();
|
||||
// 3. 如果指定了最大宽度,而且原图更宽,则按比例缩放
|
||||
if (maxWidthPx > 0 && widthPx > maxWidthPx) {
|
||||
double ratio = (double) maxWidthPx / widthPx;
|
||||
widthPx = maxWidthPx;
|
||||
heightPx = (int) (heightPx * ratio);
|
||||
}
|
||||
// 4. 把像素转换成 EMU
|
||||
int widthEmu = Units.pixelToEMU(widthPx);
|
||||
int heightEmu = Units.pixelToEMU(heightPx);
|
||||
// 5. 插入图片
|
||||
String lower = imagePath.toLowerCase();
|
||||
int format = lower.endsWith(".png") ? XWPFDocument.PICTURE_TYPE_PNG
|
||||
: lower.endsWith(".gif") ? XWPFDocument.PICTURE_TYPE_GIF
|
||||
: lower.endsWith(".jpeg") ? XWPFDocument.PICTURE_TYPE_JPEG
|
||||
: lower.endsWith(".jpg") ? XWPFDocument.PICTURE_TYPE_JPEG
|
||||
: XWPFDocument.PICTURE_TYPE_PNG; // 默认当 PNG
|
||||
try (InputStream picIn = new ByteArrayInputStream(imgBytes)) {
|
||||
run.addPicture(picIn, format, imagePath, widthEmu, heightEmu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 递归将 sourceDir 中的所有文件和子目录,按照相对于 rootDir 的路径写入 ZipOutputStream。
|
||||
*
|
||||
* @param rootDir 源目录的根,用来计算相对路径
|
||||
* @param sourceDir 当前递归到的目录
|
||||
* @param zos ZIP 输出流
|
||||
*/
|
||||
public static void zipDirectory(Path rootDir, Path sourceDir, ZipOutputStream zos) throws IOException {
|
||||
// 遍历当前目录下的所有文件和文件夹
|
||||
try (DirectoryStream<Path> stream = Files.newDirectoryStream(sourceDir)) {
|
||||
for (Path entry : stream) {
|
||||
if (Files.isDirectory(entry)) {
|
||||
// 如果是目录,递归
|
||||
zipDirectory(rootDir, entry, zos);
|
||||
} else {
|
||||
// 如果是文件,创建一个 ZipEntry,路径以 '/' 分隔
|
||||
Path relativePath = rootDir.relativize(entry);
|
||||
String zipEntryName = relativePath.toString().replace(File.separatorChar, '/');
|
||||
ZipEntry zipEntry = new ZipEntry(zipEntryName);
|
||||
zos.putNextEntry(zipEntry);
|
||||
// 把文件内容写入 ZIP
|
||||
try (InputStream is = Files.newInputStream(entry)) {
|
||||
byte[] buffer = new byte[4096];
|
||||
int len;
|
||||
while ((len = is.read(buffer)) != -1) {
|
||||
zos.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package org.dromara.common.utils;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/4/23 10:42
|
||||
*/
|
||||
@Slf4j
|
||||
public class Dxf2JsonUtil {
|
||||
|
||||
/**
|
||||
* dxf转json
|
||||
*
|
||||
* @param exePath dxf2json.exe路径
|
||||
* @param inputDXFPath 输入dxf文件路径
|
||||
* @param outputJSONPath 输出json文件路径
|
||||
* @param sourceEPSG 源坐标系
|
||||
* @param targetEPSG 目标坐标系
|
||||
*/
|
||||
public static void dxf2json(String exePath, String inputDXFPath, String outputJSONPath, String sourceEPSG, String targetEPSG) {
|
||||
// 判断对应文件是否存在
|
||||
File exeFile = new File(exePath);
|
||||
if (!exeFile.exists()) {
|
||||
throw new ServiceException("转换程序不存在!");
|
||||
}
|
||||
File inputDXFFile = new File(inputDXFPath);
|
||||
if (!inputDXFFile.exists()) {
|
||||
throw new ServiceException("待转换 dxf 文件不存在!");
|
||||
}
|
||||
// 构造命令行参数
|
||||
List<String> parameters = buildParameter(exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG);
|
||||
// 执行命令行
|
||||
ProcessBuilder builder = new ProcessBuilder(parameters);
|
||||
// 合并标准错误和输出
|
||||
builder.redirectErrorStream(true);
|
||||
try {
|
||||
Process process = builder.start();
|
||||
// 读取输出
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(process.getInputStream(), "GBK")
|
||||
);
|
||||
String line;
|
||||
log.info("dxf 转 json 程序开始执行,程序路径:{},输入 dxf 路径:{},输出 json 文件路径:{},源坐标系:{},模板坐标系:{}",
|
||||
exePath, inputDXFPath, outputJSONPath, sourceEPSG, targetEPSG);
|
||||
while ((line = reader.readLine()) != null) {
|
||||
log.info("dxf 转 json 程序执行中:{}", line);
|
||||
JSONObject jsonObject = JSONUtil.parseObj(line);
|
||||
Integer code = jsonObject.get("code", Integer.class);
|
||||
if (code != 0 && code != 200) {
|
||||
throw new ServiceException("dxf 转 json 程序执行出错!");
|
||||
}
|
||||
}
|
||||
int exitCode = process.waitFor();
|
||||
log.info("dxf 转 json 程序执行完毕,程序退出码:{}", exitCode);
|
||||
reader.close();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
log.error("执行 dxf 转 json 命令行时出错", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造命令行参数
|
||||
*
|
||||
* @param exePath dxf2json.exe路径
|
||||
* @param inputDXFPath 输入dxf文件路径
|
||||
* @param outputJSONPath 输出json文件路径
|
||||
* @param sourceEPSG 源坐标系
|
||||
* @param targetEPSG 目标坐标系
|
||||
* @return 命令行参数
|
||||
*/
|
||||
public static List<String> buildParameter(String exePath,
|
||||
String inputDXFPath,
|
||||
String outputJSONPath,
|
||||
String sourceEPSG,
|
||||
String targetEPSG) {
|
||||
// 构造命令行
|
||||
return Arrays.asList(
|
||||
exePath,
|
||||
inputDXFPath,
|
||||
outputJSONPath,
|
||||
sourceEPSG,
|
||||
targetEPSG
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.dromara.common.utils;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.net.http.HttpClient;
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 10:16
|
||||
* @Version 1.0
|
||||
*
|
||||
* HttpClient 设计为可重用、线程安全的组件,其内部维护了连接池等资源,适合在多个接口调用中共享使用,所以交给Spring Bean 管理
|
||||
*/
|
||||
@Configuration
|
||||
public class HttpClientConfig {
|
||||
@Bean
|
||||
public HttpClient httpClient() {
|
||||
return HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(10))
|
||||
.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package org.dromara.common.utils;
|
||||
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.crypto.symmetric.AES;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/6/25 10:57
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class IdCardEncryptorUtil {
|
||||
|
||||
@Value("${id-card.encrypt-key}")
|
||||
private String encryptKeyHex;
|
||||
|
||||
private AES aes;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
byte[] keyBytes = HexUtil.decodeHex(encryptKeyHex);
|
||||
this.aes = SecureUtil.aes(keyBytes);
|
||||
log.info("身份证 AES 加解密工具初始化成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param idCard 身份证号码
|
||||
* @return 加密后的身份证号码
|
||||
*/
|
||||
public String encrypt(String idCard) {
|
||||
return aes.encryptBase64(idCard);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param encrypted 密文
|
||||
* @return 解密后的身份证号码
|
||||
*/
|
||||
public String decrypt(String encrypted) {
|
||||
return aes.decryptStr(encrypted);
|
||||
}
|
||||
}
|
@ -0,0 +1,270 @@
|
||||
package org.dromara.common.utils;
|
||||
|
||||
import org.dromara.common.core.constant.HttpStatus;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
import org.dromara.common.constant.GeoJsonConstant;
|
||||
import org.dromara.facility.domain.dto.geojson.FacFeatureByPlane;
|
||||
import org.dromara.facility.domain.dto.geojson.FacFeatureByPoint;
|
||||
import org.dromara.facility.domain.dto.geojson.FacGeometry;
|
||||
import org.dromara.facility.domain.dto.geojson.FacGeometryByPoint;
|
||||
import org.locationtech.jts.geom.*;
|
||||
import org.locationtech.jts.index.strtree.STRtree;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/4/24 11:48
|
||||
*/
|
||||
public class JSTUtil {
|
||||
|
||||
private static final GeometryFactory geometryFactory = new GeometryFactory();
|
||||
|
||||
/**
|
||||
* 获取最近点的名称
|
||||
*
|
||||
* @param target 目标点
|
||||
* @param nameGeoJson 点对象列表
|
||||
* @return 最近点的名称
|
||||
*/
|
||||
public static String findNearestText(List<Double> target, List<FacFeatureByPoint> nameGeoJson) {
|
||||
Point targetPoint = geometryFactory.createPoint(new Coordinate(target.get(0), target.get(1)));
|
||||
FacFeatureByPoint nearestFeature = null;
|
||||
double minDistance = Double.MAX_VALUE;
|
||||
for (FacFeatureByPoint feature : nameGeoJson) {
|
||||
FacGeometryByPoint geometry = feature.getGeometry();
|
||||
List<Double> coords = geometry.getCoordinates();
|
||||
if (coords != null && coords.size() == 2) {
|
||||
Point currentPoint = geometryFactory.createPoint(new Coordinate(coords.get(0), coords.get(1)));
|
||||
double distance = targetPoint.distance(currentPoint);
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
nearestFeature = feature;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nearestFeature != null && nearestFeature.getProperties() != null) {
|
||||
return nearestFeature.getProperties().getText();
|
||||
}
|
||||
return null; // 如果没找到合适的点
|
||||
}
|
||||
|
||||
/**
|
||||
* 点是否在平面内
|
||||
*
|
||||
* @param planeLists 平面坐标
|
||||
* @param pointList 点坐标
|
||||
* @return 点是否在平面内
|
||||
*/
|
||||
public static Boolean pointIsWithInPlane(List<List<Double>> planeLists, List<Double> pointList) {
|
||||
// 构建平面
|
||||
Coordinate[] coordinates = getPlaneCoordinate(planeLists);
|
||||
Polygon polygon = geometryFactory.createPolygon(coordinates);
|
||||
// 构建待判断点
|
||||
Point point = geometryFactory.createPoint(new Coordinate(pointList.get(0), pointList.get(1)));
|
||||
// 判断是否在多边形内
|
||||
return polygon.contains(point);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平面内点列表集合
|
||||
*
|
||||
* @param planeLists 平面坐标列表
|
||||
* @param pointLists 点坐标列表集合
|
||||
* @return 平面内点坐标列表集合
|
||||
*/
|
||||
public static List<List<Double>> getPointInPlaneList(List<List<Double>> planeLists, List<List<Double>> pointLists) {
|
||||
// 构建平面
|
||||
Coordinate[] coordinates = getPlaneCoordinate(planeLists);
|
||||
LinearRing shell = geometryFactory.createLinearRing(coordinates);
|
||||
Polygon polygon = geometryFactory.createPolygon(shell);
|
||||
// 获取平面内点结合
|
||||
return pointLists.stream().filter(pointList -> {
|
||||
// 构建待判断点
|
||||
Point point = geometryFactory.createPoint(new Coordinate(pointList.get(0), pointList.get(1)));
|
||||
// 判断是否在多边形内
|
||||
return polygon.contains(point);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 平面是否在平面内
|
||||
*
|
||||
* @param referencePlane 参考平面
|
||||
* @param comparePlane 比较平面
|
||||
* @return 平面是否在平面内
|
||||
*/
|
||||
public static Boolean planeIsWithInPlane(List<List<Double>> referencePlane, List<List<Double>> comparePlane) {
|
||||
// 构建参考平面
|
||||
Coordinate[] referenceCoordinates = getPlaneCoordinate(referencePlane);
|
||||
Polygon referencePolygon = geometryFactory.createPolygon(referenceCoordinates);
|
||||
// 构建比较平面
|
||||
Coordinate[] compareCoordinates = getPlaneCoordinate(comparePlane);
|
||||
Polygon comparePolygon = geometryFactory.createPolygon(compareCoordinates);
|
||||
// 判断是否在多边形内
|
||||
return referencePolygon.contains(comparePolygon);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断两个平面是否相交
|
||||
*
|
||||
* @param referencePlane 参考平面
|
||||
* @param comparePlane 待比较平面
|
||||
* @return 平面是否相交
|
||||
*/
|
||||
public static Boolean arePolygonsIntersecting(List<List<Double>> referencePlane, List<List<Double>> comparePlane) {
|
||||
// 构建 Polygon A(参考面)
|
||||
Coordinate[] coordsA = referencePlane.stream()
|
||||
.map(p -> new Coordinate(p.getFirst(), p.get(1)))
|
||||
.toArray(Coordinate[]::new);
|
||||
Polygon polygonA = geometryFactory.createPolygon(coordsA);
|
||||
// 构建 Polygon B(比较面)
|
||||
Coordinate[] coordsB = comparePlane.stream()
|
||||
.map(p -> new Coordinate(p.getFirst(), p.get(1)))
|
||||
.toArray(Coordinate[]::new);
|
||||
Polygon polygonB = geometryFactory.createPolygon(coordsB);
|
||||
// 使用 JTS 判断是否相交
|
||||
return polygonA.intersects(polygonB);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平面坐标数组
|
||||
*
|
||||
* @param planeLists 平面坐标列表
|
||||
* @return 平面坐标数组
|
||||
*/
|
||||
public static Coordinate[] getPlaneCoordinate(List<List<Double>> planeLists) {
|
||||
return planeLists.stream().map(planeList ->
|
||||
new Coordinate(planeList.getFirst(), planeList.get(1)))
|
||||
.toList().toArray(new Coordinate[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取二维坐标
|
||||
*
|
||||
* @param geometry 几何对象
|
||||
* @return 二维坐标
|
||||
*/
|
||||
public static List<List<Double>> getTwoDimensionalCoordinates(FacGeometry geometry) {
|
||||
String type = geometry.getType();
|
||||
List<Object> coordinates = geometry.getCoordinates();
|
||||
return switch (type) {
|
||||
case GeoJsonConstant.POINT -> throw new ServiceException("点位无法创建方阵", HttpStatus.BAD_REQUEST);
|
||||
case GeoJsonConstant.LINE -> coordinates.stream()
|
||||
.filter(obj -> obj instanceof List<?>)
|
||||
.map(obj -> ((List<?>) obj).stream()
|
||||
.filter(num -> num instanceof Number)
|
||||
.map(num -> ((Number) num).doubleValue())
|
||||
.collect(Collectors.toList()))
|
||||
.collect(Collectors.toList());
|
||||
case GeoJsonConstant.POLYGON -> coordinates.stream()
|
||||
.filter(obj -> obj instanceof List<?>)
|
||||
.flatMap(obj -> ((List<?>) obj).stream())
|
||||
.filter(pointObj -> pointObj instanceof List<?>)
|
||||
.map(pointObj -> ((List<?>) pointObj).stream()
|
||||
.filter(num -> num instanceof Number)
|
||||
.map(num -> ((Number) num).doubleValue())
|
||||
.collect(Collectors.toList()))
|
||||
.collect(Collectors.toList());
|
||||
default -> throw new ServiceException("暂不支持该类型", HttpStatus.BAD_REQUEST);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配最近的点,获取该点的名称
|
||||
*
|
||||
* @param polygon 平面
|
||||
* @param points 点列表集合
|
||||
* @return 最近点的名称
|
||||
*/
|
||||
public static String findNearestPointText(List<List<Double>> polygon, List<FacFeatureByPoint> points) {
|
||||
if (polygon == null || polygon.size() < 3 || points == null || points.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// 1. 构建 Polygon
|
||||
Coordinate[] polygonCoords = polygon.stream()
|
||||
.map(coord -> new Coordinate(coord.getFirst(), coord.get(1)))
|
||||
.toArray(Coordinate[]::new);
|
||||
Polygon jtsPolygon = geometryFactory.createPolygon(polygonCoords);
|
||||
// 2. 构建空间索引(JTS STRtree)
|
||||
STRtree spatialIndex = new STRtree();
|
||||
Map<Coordinate, FacFeatureByPoint> coordToFeatureMap = new HashMap<>();
|
||||
for (FacFeatureByPoint feature : points) {
|
||||
List<Double> coords = feature.getGeometry().getCoordinates();
|
||||
if (coords == null || coords.size() != 2) continue;
|
||||
Coordinate coord = new Coordinate(coords.get(0), coords.get(1));
|
||||
Point point = geometryFactory.createPoint(coord);
|
||||
// 用点的 Envelope 加入索引
|
||||
spatialIndex.insert(point.getEnvelopeInternal(), point);
|
||||
coordToFeatureMap.put(coord, feature);
|
||||
}
|
||||
// 3. 查询距离 polygon 最近的点
|
||||
// 用 polygon 中心点附近构造 Envelope(扩大一些范围)
|
||||
Envelope searchEnv = jtsPolygon.getEnvelopeInternal();
|
||||
searchEnv.expandBy(10); // 扩大搜索半径
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Point> candidatePoints = spatialIndex.query(searchEnv);
|
||||
double minDistance = Double.MAX_VALUE;
|
||||
Coordinate nearestCoord = null;
|
||||
for (Point point : candidatePoints) {
|
||||
double distance = point.distance(jtsPolygon);
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
nearestCoord = point.getCoordinate();
|
||||
}
|
||||
}
|
||||
if (nearestCoord != null) {
|
||||
FacFeatureByPoint nearestFeature = coordToFeatureMap.get(nearestCoord);
|
||||
if (nearestFeature != null && nearestFeature.getProperties() != null) {
|
||||
return nearestFeature.getProperties().getText();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 匹配最近的面,获取该面的信息
|
||||
*
|
||||
* @param pointFeature 点位
|
||||
* @param polygons 平面列表
|
||||
* @return 最近面的信息
|
||||
*/
|
||||
public static FacFeatureByPlane findNearestOrContainingPolygon(
|
||||
FacFeatureByPoint pointFeature,
|
||||
List<FacFeatureByPlane> polygons
|
||||
) {
|
||||
if (pointFeature == null || polygons == null || polygons.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
List<Double> coords = pointFeature.getGeometry().getCoordinates();
|
||||
if (coords == null || coords.size() != 2) return null;
|
||||
Coordinate pointCoord = new Coordinate(coords.get(0), coords.get(1));
|
||||
Point point = geometryFactory.createPoint(pointCoord);
|
||||
FacFeatureByPlane nearestPolygon = null;
|
||||
double minDistance = Double.MAX_VALUE;
|
||||
for (FacFeatureByPlane polygonFeature : polygons) {
|
||||
if (polygonFeature == null || polygonFeature.getGeometry() == null) {
|
||||
continue; // 跳过空对象
|
||||
}
|
||||
List<List<Double>> polyCoords = polygonFeature.getGeometry().getCoordinates().getFirst();
|
||||
Coordinate[] polygonCoords = polyCoords.stream()
|
||||
.map(c -> new Coordinate(c.getFirst(), c.get(1)))
|
||||
.toArray(Coordinate[]::new);
|
||||
Polygon polygon = geometryFactory.createPolygon(polygonCoords);
|
||||
// 优先使用包含点的 polygon
|
||||
if (polygon.contains(point)) {
|
||||
return polygonFeature;
|
||||
}
|
||||
double distance = polygon.distance(point);
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance;
|
||||
nearestPolygon = polygonFeature;
|
||||
}
|
||||
}
|
||||
return nearestPolygon;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.dromara.common.utils;
|
||||
|
||||
import cn.hutool.json.JSONArray;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/5/30 14:55
|
||||
*/
|
||||
public class JsonDimensionUtil {
|
||||
|
||||
/**
|
||||
* 判断 JSONArray 的嵌套维度
|
||||
*
|
||||
* @param array 需要判断的 JSONArray
|
||||
* @return 返回维度层级:1 表示一维,2 表示二维,3 表示三维 ...
|
||||
*/
|
||||
public static int getJsonArrayDepth(Object array) {
|
||||
if (array instanceof JSONArray jsonArray && !jsonArray.isEmpty()) {
|
||||
return 1 + getJsonArrayDepth(jsonArray.getFirst());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.dromara.common.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/5/28 11:25
|
||||
*/
|
||||
public class PageConvertUtil {
|
||||
|
||||
/**
|
||||
* 将 Page<T> 转换为 Page<V>
|
||||
*
|
||||
* @param source 原始分页数据
|
||||
* @param mapper 实体 -> VO 的转换函数
|
||||
* @return Page<V>
|
||||
*/
|
||||
public static <T, V> Page<V> convert(Page<T> source, Function<T, V> mapper) {
|
||||
Page<V> target = new Page<>(source.getCurrent(), source.getSize(), source.getTotal());
|
||||
if (CollUtil.isEmpty(source.getRecords())) {
|
||||
target.setRecords(Collections.emptyList());
|
||||
} else {
|
||||
List<V> voList = source.getRecords().stream().map(mapper).toList();
|
||||
target.setRecords(voList);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
package org.dromara.common.utils;
|
||||
|
||||
import cn.hutool.core.img.ImgUtil;
|
||||
import cn.hutool.extra.qrcode.QrCodeUtil;
|
||||
import com.google.zxing.BarcodeFormat;
|
||||
import com.google.zxing.MultiFormatWriter;
|
||||
import com.google.zxing.client.j2se.MatrixToImageWriter;
|
||||
import com.google.zxing.common.BitMatrix;
|
||||
import com.itextpdf.text.DocumentException;
|
||||
import com.itextpdf.text.Image;
|
||||
import com.itextpdf.text.pdf.PdfContentByte;
|
||||
import com.itextpdf.text.pdf.PdfReader;
|
||||
import com.itextpdf.text.pdf.PdfStamper;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author lilemy
|
||||
* @date 2025/7/7 9:56
|
||||
*/
|
||||
public class PdfBoxQrCodeGenerator {
|
||||
|
||||
/**
|
||||
* 生成二维码图片并返回路径
|
||||
*
|
||||
* @param text 二维码文本
|
||||
* @param width 二维码宽度
|
||||
* @param height 二维码高度
|
||||
* @param outputPath 二维码图片保存路径
|
||||
* @return 二维码图片保存路径
|
||||
*/
|
||||
public static String generateQRCodeImage(String text, int width, int height, String outputPath) throws Exception {
|
||||
BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height);
|
||||
MatrixToImageWriter.writeToPath(bitMatrix, "PNG", new File(outputPath).toPath());
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取二维码图片字节数组
|
||||
*
|
||||
* @param text 二维码文本
|
||||
* @param width 二维码宽度
|
||||
* @param height 二维码高度
|
||||
* @return 二维码图片字节数组
|
||||
*/
|
||||
public static byte[] generateQRCodeBytes(String text, int width, int height) {
|
||||
BufferedImage image = QrCodeUtil.generate(text, width, height);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ImgUtil.write(image, ImgUtil.IMAGE_TYPE_PNG, out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取二维码图片字节数组
|
||||
*
|
||||
* @param text 二维码文本
|
||||
* @return 二维码图片字节数组
|
||||
*/
|
||||
public static byte[] generateQRCodeBytes(String text) {
|
||||
return generateQRCodeBytes(text, 200, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在PDF指定位置添加二维码
|
||||
*
|
||||
* @param srcPdf 原PDF文件路径
|
||||
* @param destPdf 新PDF文件路径
|
||||
* @param qrImagePath 二维码图片路径
|
||||
* @param pageNum 页码
|
||||
* @param x 坐标
|
||||
* @param y 坐标
|
||||
*/
|
||||
public static void addQRCodeToPDF(String srcPdf, String destPdf, String qrImagePath, int pageNum, float x, float y) throws IOException, DocumentException {
|
||||
PdfReader reader = new PdfReader(srcPdf);
|
||||
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(destPdf));
|
||||
PdfContentByte content = stamper.getOverContent(pageNum);
|
||||
Image image = Image.getInstance(qrImagePath);
|
||||
image.setAbsolutePosition(x, y); // 坐标:左下角为原点
|
||||
image.scaleAbsolute(100, 100); // 设置二维码大小
|
||||
|
||||
content.addImage(image);
|
||||
stamper.close();
|
||||
reader.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在PDF指定位置添加二维码
|
||||
*
|
||||
* @param srcPdf 原PDF文件路径
|
||||
* @param destPdf 新PDF文件路径
|
||||
* @param qrCodeBytes 二维码图片字节数组
|
||||
* @param pageNum 页码
|
||||
* @param x 坐标
|
||||
* @param y 坐标
|
||||
*/
|
||||
public static void addQRCodeToPDF(String srcPdf, String destPdf, byte[] qrCodeBytes, int pageNum, float x, float y) throws IOException, DocumentException {
|
||||
PdfReader reader = new PdfReader(srcPdf);
|
||||
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(destPdf));
|
||||
PdfContentByte content = stamper.getOverContent(pageNum);
|
||||
|
||||
Image image = Image.getInstance(qrCodeBytes);
|
||||
image.setAbsolutePosition(x, y); // 坐标:左下角为原点
|
||||
image.scaleAbsolute(100, 100); // 设置二维码大小
|
||||
|
||||
content.addImage(image);
|
||||
stamper.close();
|
||||
reader.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在PDF指定位置添加二维码并返回数据流
|
||||
*
|
||||
* @param srcPdf 原PDF文件路径
|
||||
* @param qrCodeBytes 二维码图片字节数组
|
||||
* @param pageNum 页码
|
||||
* @param x 坐标
|
||||
* @param y 坐标
|
||||
* @return 插入二维码后的PDF文件流
|
||||
*/
|
||||
public static ByteArrayOutputStream addQRCodeToPDF(String srcPdf, byte[] qrCodeBytes, int pageNum, float x, float y) throws IOException, DocumentException {
|
||||
|
||||
PdfReader reader = new PdfReader(srcPdf);
|
||||
ByteArrayOutputStream pdfOut = new ByteArrayOutputStream();
|
||||
PdfStamper stamper = new PdfStamper(reader, pdfOut);
|
||||
|
||||
PdfContentByte content = stamper.getOverContent(pageNum);
|
||||
Image image = Image.getInstance(qrCodeBytes);
|
||||
image.setAbsolutePosition(x, y); // 坐标:左下角为原点
|
||||
image.scaleAbsolute(100, 100); // 设置二维码大小
|
||||
|
||||
content.addImage(image);
|
||||
stamper.close();
|
||||
reader.close();
|
||||
|
||||
return pdfOut;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package org.dromara.common.utils.baiduUtil;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import org.dromara.common.utils.baiduUtil.entity.AccessTokenResponse;
|
||||
import org.glassfish.jaxb.runtime.v2.runtime.reflect.opt.Const;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.dromara.common.constant.businessConstant.REDIS_BAIDU_KEY;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 9:46
|
||||
* @Version 1.0
|
||||
*
|
||||
* 获取百度AccessToken
|
||||
*/
|
||||
@Service
|
||||
public class BaiDuCommon {
|
||||
@Autowired
|
||||
private HttpClient httpClient;
|
||||
|
||||
@Autowired
|
||||
private StringRedisTemplate redisTemplate;
|
||||
|
||||
@Value("${baidu.client.id}")
|
||||
private String clientId;
|
||||
|
||||
@Value("${baidu.client.secret}")
|
||||
private String clientSecret;
|
||||
|
||||
private static final String TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token?client_id=%s&client_secret=%s&grant_type=client_credentials";
|
||||
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
/**
|
||||
* 获取百度AccessToken,优先从Redis缓存中获取
|
||||
*/
|
||||
public String getAccessToken() {
|
||||
// 1. 尝试从Redis中获取
|
||||
String cachedToken = redisTemplate.opsForValue().get(REDIS_BAIDU_KEY);
|
||||
if (cachedToken != null) {
|
||||
return cachedToken;
|
||||
}
|
||||
|
||||
// 2. Redis中没有,加锁防止并发请求刷新Token
|
||||
synchronized (this) {
|
||||
// 再次检查,避免其他线程已经刷新
|
||||
cachedToken = redisTemplate.opsForValue().get(REDIS_BAIDU_KEY);
|
||||
if (cachedToken != null) {
|
||||
return cachedToken;
|
||||
}
|
||||
|
||||
// 3. 真正调用API获取新Token
|
||||
String newToken = fetchAccessTokenFromBaidu();
|
||||
if (newToken != null) {
|
||||
// 4. 将新Token存入Redis,并设置过期时间(比实际有效期短一些)
|
||||
redisTemplate.opsForValue().set(REDIS_BAIDU_KEY, newToken, 29, TimeUnit.DAYS);
|
||||
return newToken;
|
||||
}
|
||||
}
|
||||
|
||||
return null; // 获取失败
|
||||
}
|
||||
|
||||
/**
|
||||
* 从百度API获取AccessToken
|
||||
*/
|
||||
private String fetchAccessTokenFromBaidu() {
|
||||
String url = String.format(TOKEN_URL, clientId, clientSecret);
|
||||
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Accept", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.noBody())
|
||||
.build();
|
||||
|
||||
try {
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
if (response.statusCode() == 200) {
|
||||
AccessTokenResponse tokenResponse = gson.fromJson(response.body(), AccessTokenResponse.class);
|
||||
return tokenResponse.getAccessToken();
|
||||
} else {
|
||||
throw new IOException("获取AccessToken失败,状态码: " + response.statusCode());
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("调用百度API获取AccessToken失败", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package org.dromara.common.utils.baiduUtil;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.dromara.common.utils.baiduUtil.entity.face.ComparisonRes;
|
||||
import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceReq;
|
||||
import org.dromara.common.utils.baiduUtil.entity.face.HumanFaceRes;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 17:09
|
||||
* @Version 1.0
|
||||
* 处理百度人脸相关逻辑:人脸检测、人脸对比
|
||||
*/
|
||||
@Service
|
||||
public class BaiDuFace {
|
||||
|
||||
@Autowired
|
||||
private BaiDuCommon baiDuCommon;
|
||||
@Autowired
|
||||
private HttpClient httpClient;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
// 人脸识别API地址
|
||||
private static final String FACE_DETECT_URL = "https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=%s";
|
||||
// 人脸对比API地址
|
||||
private static final String FACE_COMPARE_URL = "https://aip.baidubce.com/rest/2.0/face/v3/match?access_token=%s";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 人脸识别+人脸检测
|
||||
* @param request 人脸请求参数
|
||||
* @throws RuntimeException 检测失败时抛出异常(由Spring统一处理)
|
||||
*/
|
||||
public void humanFace(HumanFaceReq request) {
|
||||
// 1. 获取AccessToken
|
||||
String accessToken = baiDuCommon.getAccessToken();
|
||||
if (accessToken == null || accessToken.trim().isEmpty()) {
|
||||
throw new RuntimeException("获取访问令牌失败:token为空");
|
||||
}
|
||||
|
||||
// 2. 构建请求URL
|
||||
String requestUrl = String.format(FACE_DETECT_URL, URLEncoder.encode(accessToken, StandardCharsets.UTF_8));
|
||||
|
||||
try {
|
||||
// 3. 序列化请求参数
|
||||
String requestBody = objectMapper.writeValueAsString(request);
|
||||
|
||||
// 4. 构建HTTP请求
|
||||
HttpRequest httpRequest = HttpRequest.newBuilder()
|
||||
.uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
||||
.build();
|
||||
|
||||
// 5. 发送请求并获取响应
|
||||
HttpResponse<String> response = httpClient.send(
|
||||
httpRequest,
|
||||
HttpResponse.BodyHandlers.ofString()
|
||||
);
|
||||
|
||||
// 6. 解析响应结果
|
||||
HumanFaceRes faceRep = objectMapper.readValue(response.body(), HumanFaceRes.class);
|
||||
|
||||
// 7. 处理API返回错误
|
||||
if (faceRep.getErrorCode() != 0) {
|
||||
throw new RuntimeException("错误码说明:" + faceRep.getErrorMsg());
|
||||
}
|
||||
|
||||
// 8. 验证人脸信息(无人脸时抛出异常)
|
||||
if (faceRep.getResult() == null
|
||||
|| faceRep.getResult().getFaceList() == null
|
||||
|| faceRep.getResult().getFaceList().isEmpty()) {
|
||||
throw new RuntimeException("未检测到有效人脸信息");
|
||||
}
|
||||
|
||||
// 9. 人脸质量校验
|
||||
HumanFaceRes.FaceList faceInfo = faceRep.getResult().getFaceList().get(0);
|
||||
|
||||
// 9.1 人脸置信度校验(必须为1.0)
|
||||
if (faceInfo.getFaceProbability() != 1.0) {
|
||||
throw new RuntimeException("人脸置信度过低,请重新拍摄!");
|
||||
}
|
||||
|
||||
// 9.2 真实人脸校验(排除卡通人脸)
|
||||
HumanFaceRes.FaceType faceType = faceInfo.getFaceType();
|
||||
if (faceType == null) {
|
||||
throw new RuntimeException("无法判断人脸类型");
|
||||
}
|
||||
if ("cartoon".equals(faceType.getType())) {
|
||||
throw new RuntimeException("请传入真实人脸,勿使用卡通图像");
|
||||
}
|
||||
// 校验真实人脸置信度(需≥0.8)
|
||||
if (faceType.getProbability() < 0.8) {
|
||||
throw new RuntimeException("人脸识别不清晰,请换个角度拍摄");
|
||||
}
|
||||
|
||||
// 9.3 人脸模糊度校验(模糊度≥0.1视为模糊)
|
||||
HumanFaceRes.Quality quality = faceInfo.getQuality();
|
||||
if (quality == null) {
|
||||
throw new RuntimeException("无法获取人脸质量信息");
|
||||
}
|
||||
if (quality.getBlur() != 0) {
|
||||
throw new RuntimeException("人脸过于模糊,请保持镜头稳定");
|
||||
}
|
||||
|
||||
// 9.4 光线校验(光线值<100视为过暗)
|
||||
if (quality.getIllumination() < 100.0) {
|
||||
throw new RuntimeException("光线太暗,请在光线充足的环境下拍摄");
|
||||
}
|
||||
|
||||
// 9.5 人脸完整性校验(1为完整,0为不完整)
|
||||
if (quality.getCompleteness() != 1) {
|
||||
throw new RuntimeException("人脸未完全显示,请确保面部在框内");
|
||||
}
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException("请求参数序列化失败:" + e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("IO处理异常:" + e.getMessage(), e);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt(); // 恢复中断状态
|
||||
throw new RuntimeException("请求被中断:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 人脸对比(计算人脸相似度)
|
||||
* @param requestList 人脸请求参数列表(至少包含2个人脸)
|
||||
* @return 人脸相似度得分
|
||||
* @throws RuntimeException 对比失败时抛出异常
|
||||
*/
|
||||
public double comparison(List<HumanFaceReq> requestList) {
|
||||
// 1. 校验请求参数
|
||||
if (requestList == null || requestList.size() < 2) {
|
||||
throw new RuntimeException("人脸对比至少需要2张人脸图片");
|
||||
}
|
||||
|
||||
// 2. 获取AccessToken
|
||||
String accessToken = baiDuCommon.getAccessToken();
|
||||
if (accessToken == null || accessToken.trim().isEmpty()) {
|
||||
throw new RuntimeException("获取访问令牌失败:token为空");
|
||||
}
|
||||
|
||||
// 3. 构建请求URL
|
||||
String requestUrl = String.format(FACE_COMPARE_URL, URLEncoder.encode(accessToken, StandardCharsets.UTF_8));
|
||||
|
||||
try {
|
||||
// 4. 序列化请求参数
|
||||
String requestBody = objectMapper.writeValueAsString(requestList);
|
||||
|
||||
// 5. 构建HTTP请求
|
||||
HttpRequest httpRequest = HttpRequest.newBuilder()
|
||||
.uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
||||
.build();
|
||||
|
||||
// 6. 发送请求并获取响应
|
||||
HttpResponse<String> response = httpClient.send(
|
||||
httpRequest,
|
||||
HttpResponse.BodyHandlers.ofString()
|
||||
);
|
||||
|
||||
// 7. 解析响应结果
|
||||
ComparisonRes comparisonRep = objectMapper.readValue(response.body(), ComparisonRes.class);
|
||||
|
||||
// 8. 处理API返回错误
|
||||
if (comparisonRep.getErrorCode() != 0) {
|
||||
throw new RuntimeException("人脸对比失败:" + comparisonRep.getErrorMsg()
|
||||
+ "(错误码:" + comparisonRep.getErrorCode() + ")");
|
||||
}
|
||||
|
||||
// 9. 校验对比结果
|
||||
if (comparisonRep.getResult() == null) {
|
||||
throw new RuntimeException("人脸对比结果为空");
|
||||
}
|
||||
|
||||
return comparisonRep.getResult().getScore();
|
||||
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException("请求参数序列化失败:" + e.getMessage(), e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("IO处理异常:" + e.getMessage(), e);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("请求被中断:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
package org.dromara.common.utils.baiduUtil;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.dromara.common.utils.baiduUtil.entity.ocr.IDCardInfo;
|
||||
import org.dromara.common.utils.baiduUtil.entity.ocr.OcrReq;
|
||||
import org.dromara.common.utils.baiduUtil.entity.ocr.Result;
|
||||
import org.dromara.common.utils.baiduUtil.entity.ocr.WordsResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 10:45
|
||||
* @Version 1.0
|
||||
*
|
||||
* 处理百度OCR相关逻辑:身份证识别、银行卡识别
|
||||
*/
|
||||
@Service
|
||||
public class BaiDuOCR {
|
||||
@Autowired
|
||||
private BaiDuCommon baiDuCommon;
|
||||
@Autowired
|
||||
private HttpClient httpClient;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper; //ObjectMapper 是 Java 处理 JSON 的核心工具,项目中使用它进行 JSON 与 Java 对象的相互转换。
|
||||
|
||||
|
||||
String baseUrlTemplate = "https://aip.baidubce.com/rest/2.0/ocr/v1/bankcard?access_token=%s";
|
||||
String BASE_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token=%s";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description 银行卡OCR识别
|
||||
* @author 铁憨憨
|
||||
* @date 2025/7/18 11:50
|
||||
* @param vr 请求参数
|
||||
* @return 识别结果Result
|
||||
**/
|
||||
public Result bankCardOCRRecognition(OcrReq vr) {
|
||||
// 先从缓存里面捞取token,若为空直接抛出异常
|
||||
String atStr = baiDuCommon.getAccessToken();
|
||||
if (atStr == null || atStr.trim().isEmpty()) {
|
||||
throw new RuntimeException("获取访问令牌失败:token为空");
|
||||
}
|
||||
|
||||
try {
|
||||
// 构建请求URL(包含token参数)
|
||||
String requestUrl = String.format(baseUrlTemplate, URLEncoder.encode(atStr, StandardCharsets.UTF_8));
|
||||
|
||||
// 准备请求体(将请求参数转为JSON)
|
||||
String requestBody = objectMapper.writeValueAsString(vr);
|
||||
if (requestBody == null) {
|
||||
throw new RuntimeException("请求参数序列化失败");
|
||||
}
|
||||
|
||||
// 构建HTTP请求
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
||||
.build();
|
||||
|
||||
// 发送请求并获取响应
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
// 处理响应状态码(非200直接抛出异常)
|
||||
if (response.statusCode() != 200) {
|
||||
throw new RuntimeException("接口请求失败,状态码:" + response.statusCode() + ",响应信息:" + response.body());
|
||||
}
|
||||
|
||||
// 解析响应结果(若解析失败抛出异常)
|
||||
Result result = objectMapper.readValue(response.body(), Result.class);
|
||||
if (result == null) {
|
||||
throw new RuntimeException("响应结果解析失败");
|
||||
}
|
||||
|
||||
// // 若接口返回错误码(如百度API的error_code),抛出异常
|
||||
// if (result.getErrorCode() != null && result.getErrorCode() != 0) {
|
||||
// throw new RuntimeException("接口返回错误:" + result.getErrorMessage() + "(错误码:" + result.getErrorCode() + ")");
|
||||
// }
|
||||
|
||||
return result;
|
||||
|
||||
} catch (IOException e) {
|
||||
// IO异常(如序列化失败、网络IO错误)
|
||||
throw new RuntimeException("IO处理异常:" + e.getMessage(), e);
|
||||
} catch (InterruptedException e) {
|
||||
// 线程中断异常
|
||||
Thread.currentThread().interrupt(); // 恢复中断状态
|
||||
throw new RuntimeException("请求被中断:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description 身份证OCR识别
|
||||
* @author 铁憨憨
|
||||
* @date 2025/7/18 16:53
|
||||
* @param request 请求参数
|
||||
* @return 识别结果WordsResult
|
||||
**/
|
||||
public WordsResult idCardOCR(OcrReq request) {
|
||||
// 获取AccessToken,为空直接抛异常
|
||||
String accessToken = baiDuCommon.getAccessToken();
|
||||
if (accessToken == null || accessToken.trim().isEmpty()) {
|
||||
throw new RuntimeException("获取访问令牌失败:token为空");
|
||||
}
|
||||
|
||||
// 构建请求URL
|
||||
String requestUrl = String.format(BASE_URL, accessToken);
|
||||
|
||||
try {
|
||||
// 准备请求体(序列化失败抛异常)
|
||||
String requestBody = objectMapper.writeValueAsString(request);
|
||||
if (requestBody == null) {
|
||||
throw new RuntimeException("请求参数序列化失败");
|
||||
}
|
||||
|
||||
// 构建HTTP请求
|
||||
HttpRequest httpRequest = HttpRequest.newBuilder()
|
||||
.uri(URI.create(requestUrl))
|
||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
|
||||
.build();
|
||||
|
||||
// 发送请求并获取响应
|
||||
HttpResponse<String> response = httpClient.send(
|
||||
httpRequest,
|
||||
HttpResponse.BodyHandlers.ofString()
|
||||
);
|
||||
|
||||
// 处理响应状态码(非200直接抛异常)
|
||||
if (response.statusCode() != 200) {
|
||||
throw new RuntimeException("接口请求失败,状态码:" + response.statusCode() + ",响应信息:" + response.body());
|
||||
}
|
||||
|
||||
// 处理响应内容(去除空格并解析)
|
||||
String responseBody = response.body().replaceAll("\\s+", "");
|
||||
IDCardInfo idCardInfo = objectMapper.readValue(responseBody, IDCardInfo.class);
|
||||
if (idCardInfo == null) {
|
||||
throw new RuntimeException("响应结果解析失败");
|
||||
}
|
||||
|
||||
// 检查身份证状态(状态异常由validateImageStatus抛异常)
|
||||
validateImageStatus(idCardInfo.getImageStatus());
|
||||
|
||||
// 提取识别结果(结果为空抛异常)
|
||||
WordsResult wordsResult = idCardInfo.getWordsResult();
|
||||
if (wordsResult == null) {
|
||||
throw new RuntimeException("未识别到身份证信息");
|
||||
}
|
||||
|
||||
return wordsResult;
|
||||
|
||||
} catch (IOException e) {
|
||||
// IO异常(序列化、网络IO等)
|
||||
throw new RuntimeException("IO处理异常:" + e.getMessage(), e);
|
||||
} catch (InterruptedException e) {
|
||||
// 线程中断异常
|
||||
Thread.currentThread().interrupt(); // 恢复中断状态
|
||||
throw new RuntimeException("请求被中断:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description 验证身份证图片状态
|
||||
* @author 铁憨憨
|
||||
* @date 2025/7/18 17:08
|
||||
* @param imageStatus 图片状态
|
||||
* @throws RuntimeException 当状态不正常时抛出运行时异常
|
||||
**/
|
||||
private void validateImageStatus(String imageStatus) {
|
||||
if (imageStatus == null || "normal".equals(imageStatus)) {
|
||||
return; // 正常状态,直接返回
|
||||
}
|
||||
|
||||
// 根据不同状态码抛出不同的异常信息
|
||||
String errorMessage = switch (imageStatus) {
|
||||
case "reversed_side" -> "身份证正反面颠倒,请调整后重新上传";
|
||||
case "non_idcard" -> "上传的图片中不包含身份证,请重新上传";
|
||||
case "blurred" -> "身份证图片模糊,请重新上传清晰的图片";
|
||||
case "other_type_card" -> "上传的不是身份证,请上传有效的身份证图片";
|
||||
case "over_exposure" -> "身份证关键字段反光或过曝,请调整光线后重新上传";
|
||||
case "over_dark" -> "身份证图片欠曝(亮度过低),请调整光线后重新上传";
|
||||
default -> "未知错误:" + imageStatus;
|
||||
};
|
||||
|
||||
throw new RuntimeException(errorMessage);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 9:56
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class AccessTokenResponse {
|
||||
private String accessToken;
|
||||
private int expiresIn;
|
||||
private String scope;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.face;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 17:15
|
||||
* @Version 1.0
|
||||
*
|
||||
* 人脸对比响应结果
|
||||
*/
|
||||
@Data
|
||||
public class ComparisonRes {
|
||||
@JsonProperty("error_code")
|
||||
private int errorCode;
|
||||
|
||||
@JsonProperty("error_msg")
|
||||
private String errorMsg;
|
||||
|
||||
@JsonProperty("log_id")
|
||||
private long logId;
|
||||
|
||||
@JsonProperty("timestamp")
|
||||
private long timestamp;
|
||||
|
||||
@JsonProperty("cached")
|
||||
private int cached;
|
||||
|
||||
@JsonProperty("result")
|
||||
private CompareResult result;
|
||||
|
||||
@Data
|
||||
public static class CompareResult {
|
||||
@JsonProperty("score")
|
||||
private double score; // 人脸相似度得分
|
||||
|
||||
@JsonProperty("face_list")
|
||||
private List<FaceToken> faceList;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class FaceToken {
|
||||
@JsonProperty("face_token")
|
||||
private String faceToken;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.face;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 17:12
|
||||
* @Version 1.0
|
||||
*
|
||||
* 人脸识别请求参数
|
||||
*/
|
||||
@Data
|
||||
public class HumanFaceReq {
|
||||
@JsonProperty("image")
|
||||
private String image; // 图片base64字符串
|
||||
|
||||
@JsonProperty("image_type")
|
||||
private String imageType = "BASE64"; // 图片类型(固定为BASE64)
|
||||
|
||||
@JsonProperty("face_field")
|
||||
private String faceField = "face_type,quality"; // 需要返回的人脸字段
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.face;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 17:13
|
||||
* @Version 1.0
|
||||
*
|
||||
* 人脸识别响应结果
|
||||
*/
|
||||
@Data
|
||||
public class HumanFaceRes {
|
||||
@JsonProperty("error_code")
|
||||
private int errorCode;
|
||||
|
||||
@JsonProperty("error_msg")
|
||||
private String errorMsg;
|
||||
|
||||
@JsonProperty("log_id")
|
||||
private long logId;
|
||||
|
||||
@JsonProperty("timestamp")
|
||||
private long timestamp;
|
||||
|
||||
@JsonProperty("cached")
|
||||
private int cached;
|
||||
|
||||
@JsonProperty("result")
|
||||
private Result result;
|
||||
|
||||
@Data
|
||||
public static class Result {
|
||||
@JsonProperty("face_num")
|
||||
private int faceNum;
|
||||
|
||||
@JsonProperty("face_list")
|
||||
private List<FaceList> faceList;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class FaceList {
|
||||
@JsonProperty("face_token")
|
||||
private String faceToken;
|
||||
|
||||
@JsonProperty("location")
|
||||
private Location location;
|
||||
|
||||
@JsonProperty("face_probability")
|
||||
private double faceProbability;
|
||||
|
||||
@JsonProperty("angle")
|
||||
private Angle angle;
|
||||
|
||||
@JsonProperty("face_type")
|
||||
private FaceType faceType;
|
||||
|
||||
@JsonProperty("quality")
|
||||
private Quality quality;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Location {
|
||||
@JsonProperty("left")
|
||||
private double left;
|
||||
|
||||
@JsonProperty("top")
|
||||
private double top;
|
||||
|
||||
@JsonProperty("width")
|
||||
private int width;
|
||||
|
||||
@JsonProperty("height")
|
||||
private int height;
|
||||
|
||||
@JsonProperty("rotation")
|
||||
private int rotation;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Angle {
|
||||
@JsonProperty("yaw")
|
||||
private double yaw;
|
||||
|
||||
@JsonProperty("pitch")
|
||||
private double pitch;
|
||||
|
||||
@JsonProperty("roll")
|
||||
private double roll;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class FaceType {
|
||||
@JsonProperty("type")
|
||||
private String type;
|
||||
|
||||
@JsonProperty("probability")
|
||||
private double probability;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Quality {
|
||||
@JsonProperty("occlusion")
|
||||
private Occlusion occlusion;
|
||||
|
||||
@JsonProperty("blur")
|
||||
private double blur;
|
||||
|
||||
@JsonProperty("illumination")
|
||||
private double illumination;
|
||||
|
||||
@JsonProperty("completeness")
|
||||
private long completeness;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Occlusion {
|
||||
@JsonProperty("left_eye")
|
||||
private double leftEye;
|
||||
|
||||
@JsonProperty("right_eye")
|
||||
private double rightEye;
|
||||
|
||||
@JsonProperty("nose")
|
||||
private double nose;
|
||||
|
||||
@JsonProperty("mouth")
|
||||
private double mouth;
|
||||
|
||||
@JsonProperty("left_cheek")
|
||||
private double leftCheek;
|
||||
|
||||
@JsonProperty("right_cheek")
|
||||
private double rightCheek;
|
||||
|
||||
@JsonProperty("chin_contour")
|
||||
private double chinContour;
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.ocr;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 10:58
|
||||
* @Version 1.0
|
||||
*
|
||||
* 银行卡具体信息
|
||||
*/
|
||||
@Data
|
||||
//public class BankData {
|
||||
// private String valid_date; // 有效期
|
||||
// private String bank_card_number; // 卡号
|
||||
// private String bank_name; // 银行名称
|
||||
// private int bank_card_type; // 卡类型(0未知,1借记卡,2贷记卡等)
|
||||
// private String holder_name; // 持卡人姓名(可能为空)
|
||||
//}
|
||||
|
||||
|
||||
public class BankData {
|
||||
|
||||
@JSONField(name = "bank_card_number",label = "银行卡卡号")
|
||||
private String bankCardNumber;
|
||||
|
||||
@JSONField(name = "valid_date",label = "有效期")
|
||||
private String validDate;
|
||||
|
||||
@JSONField(name = "bank_card_type",label = "银行卡类型,0:不能识别; 1:借记卡; 2:贷记卡(原信用卡大部分为贷记卡); 3:准贷记卡; 4:预付费卡")
|
||||
private int bankCardType;
|
||||
|
||||
@JSONField(name = "bank_name",label = "银行名,不能识别时为空")
|
||||
private String bankName;
|
||||
|
||||
@JSONField(name = "holder_name",label = "持卡人姓名,不能识别时为空")
|
||||
private String holderName;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.ocr;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 10:55
|
||||
* @Version 1.0
|
||||
*
|
||||
* 单个识别字段(含文字和位置)
|
||||
*/
|
||||
@Data
|
||||
public class Field {
|
||||
private Location location; // 位置信息
|
||||
private String words; // 识别文字
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.ocr;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 10:50
|
||||
* @Version 1.0
|
||||
*
|
||||
* 身份证识别结果
|
||||
*/
|
||||
@Data
|
||||
public class IDCardInfo {
|
||||
@JSONField(name = "words_result")
|
||||
private WordsResult wordsResult; // 识别字段集合(姓名、身份证号等)
|
||||
|
||||
@JSONField(name = "words_result_num")
|
||||
private int wordsResultNum; // 识别字段数量
|
||||
|
||||
@JSONField(name = "idcard_number_type")
|
||||
private int idCardNumberType; // 身份证类型(如18位/15位)
|
||||
|
||||
private String imageStatus; // 图像状态(如是否颠倒)
|
||||
|
||||
@JSONField(name = "log_id")
|
||||
private long logId; // 请求唯一标识(日志ID)
|
||||
|
||||
private String photo; // 身份证照片base64(若检测)
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.ocr;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 10:56
|
||||
* @Version 1.0
|
||||
*
|
||||
* 位置信息(坐标)
|
||||
*/
|
||||
@Data
|
||||
public class Location {
|
||||
private int top; // 顶部坐标
|
||||
private int left; // 左侧坐标
|
||||
private int width; // 宽度
|
||||
private int height; // 高度
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.ocr;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 10:47
|
||||
* @Version 1.0
|
||||
*
|
||||
* OCR请求参数(身份证/银行卡通用)
|
||||
*/
|
||||
@Data
|
||||
public class OcrReq {
|
||||
private String image; // 图像base64(与url二选一)
|
||||
|
||||
private String url; // 图像URL(与image二选一)
|
||||
|
||||
@JSONField(name = "id_card_side")
|
||||
private String idCardSide; // 身份证正反面(front/back,银行卡无需)
|
||||
|
||||
@JSONField(name = "detect_photo")
|
||||
private boolean detectPhoto;// 是是否开启银行卡质量类型(清晰模糊、边框/四角不完整)检测功能,默认不开启,即:false。
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.ocr;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 11:20
|
||||
* @Version 1.0
|
||||
*
|
||||
* 银行卡识别的完整返回结果
|
||||
*/
|
||||
@Data
|
||||
public class Result {
|
||||
@JSONField(name = "result")
|
||||
private BankData res;
|
||||
|
||||
private int direction;
|
||||
|
||||
@JSONField(name = "log_id")
|
||||
private long logId;
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package org.dromara.common.utils.baiduUtil.entity.ocr;
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author 铁憨憨
|
||||
* @Date 2025/7/18 10:50
|
||||
* @Version 1.0
|
||||
*
|
||||
* 身份证识别字段集合
|
||||
*/
|
||||
@Data
|
||||
public class WordsResult {
|
||||
@JSONField(name = "姓名")
|
||||
private Field name; // 姓名
|
||||
@JSONField(name = "民族")
|
||||
private Field nation; // 民族
|
||||
@JSONField(name = "住址")
|
||||
private Field address; // 住址
|
||||
@JSONField(name = "公民身份号码")
|
||||
private Field citizenIdentification; // 身份证号
|
||||
@JSONField(name = "出生")
|
||||
private Field birth; // 出生日期
|
||||
@JSONField(name = "性别")
|
||||
private Field gender; // 性别
|
||||
@JSONField(name = "失效日期")
|
||||
private Field expirationDate; // 失效日期
|
||||
@JSONField(name = "签发机关")
|
||||
private Field issuingAuthority; // 签发机关
|
||||
@JSONField(name = "签发日期")
|
||||
private Field issueDate; // 签发日期
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user