| @@ -1,61 +0,0 @@ | |||
| .resource-item { | |||
| position: relative; | |||
| width: calc(25% - 15px); | |||
| padding: 20px; | |||
| background: white; | |||
| border: 1px solid #eaeaea; | |||
| border-radius: 4px; | |||
| cursor: pointer; | |||
| @media screen and (max-width: 1860px) { | |||
| & { | |||
| width: calc(33.33% - 13.33px); | |||
| } | |||
| } | |||
| &__name { | |||
| position: relative; | |||
| display: inline-block; | |||
| height: 24px; | |||
| margin: 0 10px 0 0 !important; | |||
| color: @text-color; | |||
| font-size: 16px; | |||
| } | |||
| &__description { | |||
| height: 44px; | |||
| margin-bottom: 20px; | |||
| color: @text-color-secondary; | |||
| font-size: 14px; | |||
| .multiLine(2); | |||
| } | |||
| &__time { | |||
| display: flex; | |||
| flex: 0 1 content; | |||
| align-items: center; | |||
| width: 100%; | |||
| color: #808080; | |||
| font-size: 13px; | |||
| } | |||
| &:hover { | |||
| border-color: @primary-color; | |||
| box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1); | |||
| .resource-item__name { | |||
| color: @primary-color; | |||
| } | |||
| } | |||
| } | |||
| .resource-item__name { | |||
| &::after { | |||
| position: absolute; | |||
| top: 14px; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 6px; | |||
| background: linear-gradient(to right, rgba(22, 100, 255, 0.3) 0, rgba(22, 100, 255, 0) 100%); | |||
| content: ''; | |||
| } | |||
| } | |||
| @@ -1,54 +0,0 @@ | |||
| import clock from '@/assets/img/clock.png'; | |||
| import creatByImg from '@/assets/img/creatBy.png'; | |||
| import KFIcon from '@/components/KFIcon'; | |||
| import { formatDate } from '@/utils/date'; | |||
| import { Button, Flex, Typography } from 'antd'; | |||
| import { ResourceData } from '../../config'; | |||
| import styles from './index.less'; | |||
| type ResourceItemProps = { | |||
| item: ResourceData; | |||
| isPublic: boolean; | |||
| onRemove: (item: ResourceData) => void; | |||
| onClick: (item: ResourceData) => void; | |||
| }; | |||
| function ResourceItem({ item, isPublic, onClick, onRemove }: ResourceItemProps) { | |||
| return ( | |||
| <div className={styles['resource-item']} onClick={() => onClick(item)}> | |||
| <Flex justify="space-between" align="center" style={{ marginBottom: '20px', height: '32px' }}> | |||
| <Typography.Paragraph | |||
| className={styles['resource-item__name']} | |||
| ellipsis={{ tooltip: item.name }} | |||
| > | |||
| {item.name} | |||
| </Typography.Paragraph> | |||
| {!isPublic && ( | |||
| <Button | |||
| type="text" | |||
| shape="circle" | |||
| onClick={(e) => { | |||
| e.stopPropagation(); | |||
| onRemove(item); | |||
| }} | |||
| > | |||
| <KFIcon type="icon-shanchu" font={17} /> | |||
| </Button> | |||
| )} | |||
| </Flex> | |||
| <div className={styles['resource-item__description']}>{item.description}</div> | |||
| <Flex justify="space-between"> | |||
| <div className={styles['resource-item__time']}> | |||
| <img style={{ width: '17px', marginRight: '6px' }} src={creatByImg} alt="" /> | |||
| <span>{item.create_by}</span> | |||
| </div> | |||
| <div className={styles['resource-item__time']}> | |||
| <img style={{ width: '12px', marginRight: '5px' }} src={clock} alt="" /> | |||
| <span>最近更新: {formatDate(item.update_time, 'YYYY-MM-DD')}</span> | |||
| </div> | |||
| </Flex> | |||
| </div> | |||
| ); | |||
| } | |||
| export default ResourceItem; | |||
| @@ -1,323 +1,344 @@ | |||
| package com.ruoyi.system.api.domain; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| import javax.validation.constraints.*; | |||
| import org.apache.commons.lang3.builder.ToStringBuilder; | |||
| import org.apache.commons.lang3.builder.ToStringStyle; | |||
| import com.ruoyi.common.core.annotation.Excel; | |||
| import com.ruoyi.common.core.annotation.Excel.ColumnType; | |||
| import com.ruoyi.common.core.annotation.Excel.Type; | |||
| import com.ruoyi.common.core.annotation.Excels; | |||
| import com.ruoyi.common.core.web.domain.BaseEntity; | |||
| import com.ruoyi.common.core.xss.Xss; | |||
| import org.apache.commons.lang3.builder.ToStringBuilder; | |||
| import org.apache.commons.lang3.builder.ToStringStyle; | |||
| import javax.validation.constraints.Email; | |||
| import javax.validation.constraints.NotBlank; | |||
| import javax.validation.constraints.Size; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| /** | |||
| * 用户对象 sys_user | |||
| * | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| public class SysUser extends BaseEntity | |||
| { | |||
| public class SysUser extends BaseEntity { | |||
| private static final long serialVersionUID = 1L; | |||
| /** 用户ID */ | |||
| /** | |||
| * 用户ID | |||
| */ | |||
| @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号") | |||
| private Long userId; | |||
| /** 部门ID */ | |||
| /** | |||
| * 部门ID | |||
| */ | |||
| @Excel(name = "部门编号", type = Type.IMPORT) | |||
| private Long deptId; | |||
| /** 用户账号 */ | |||
| /** | |||
| * 用户账号 | |||
| */ | |||
| @Excel(name = "登录名称") | |||
| private String userName; | |||
| /** 用户昵称 */ | |||
| /** | |||
| * 用户昵称 | |||
| */ | |||
| @Excel(name = "用户名称") | |||
| private String nickName; | |||
| /** 用户邮箱 */ | |||
| /** | |||
| * 用户邮箱 | |||
| */ | |||
| @Excel(name = "用户邮箱") | |||
| private String email; | |||
| /** 手机号码 */ | |||
| /** | |||
| * 手机号码 | |||
| */ | |||
| @Excel(name = "手机号码") | |||
| private String phonenumber; | |||
| /** 用户性别 */ | |||
| /** | |||
| * 用户性别 | |||
| */ | |||
| @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知") | |||
| private String sex; | |||
| /** 用户头像 */ | |||
| /** | |||
| * 用户头像 | |||
| */ | |||
| private String avatar; | |||
| /** 密码 */ | |||
| /** | |||
| * 密码 | |||
| */ | |||
| private String password; | |||
| /** 帐号状态(0正常 1停用) */ | |||
| /** | |||
| * 帐号状态(0正常 1停用) | |||
| */ | |||
| @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用") | |||
| private String status; | |||
| /** 删除标志(0代表存在 2代表删除) */ | |||
| /** | |||
| * 删除标志(0代表存在 2代表删除) | |||
| */ | |||
| private String delFlag; | |||
| /** 最后登录IP */ | |||
| /** | |||
| * 最后登录IP | |||
| */ | |||
| @Excel(name = "最后登录IP", type = Type.EXPORT) | |||
| private String loginIp; | |||
| /** 最后登录时间 */ | |||
| /** | |||
| * 最后登录时间 | |||
| */ | |||
| @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT) | |||
| private Date loginDate; | |||
| /** 部门对象 */ | |||
| /** | |||
| * 部门对象 | |||
| */ | |||
| @Excels({ | |||
| @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), | |||
| @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT) | |||
| @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), | |||
| @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT) | |||
| }) | |||
| private SysDept dept; | |||
| /** 角色对象 */ | |||
| /** | |||
| * 角色对象 | |||
| */ | |||
| private List<SysRole> roles; | |||
| /** 角色组 */ | |||
| /** | |||
| * 角色组 | |||
| */ | |||
| private Long[] roleIds; | |||
| /** 岗位组 */ | |||
| /** | |||
| * 岗位组 | |||
| */ | |||
| private Long[] postIds; | |||
| /** 角色ID */ | |||
| /** | |||
| * 角色ID | |||
| */ | |||
| private Long roleId; | |||
| public SysUser() | |||
| { | |||
| private String gitLinkUsername; | |||
| private String gitLinkPassword; | |||
| public SysUser() { | |||
| } | |||
| public SysUser(Long userId) | |||
| { | |||
| public SysUser(Long userId) { | |||
| this.userId = userId; | |||
| } | |||
| public Long getUserId() | |||
| { | |||
| public Long getUserId() { | |||
| return userId; | |||
| } | |||
| public void setUserId(Long userId) | |||
| { | |||
| public void setUserId(Long userId) { | |||
| this.userId = userId; | |||
| } | |||
| public boolean isAdmin() | |||
| { | |||
| public boolean isAdmin() { | |||
| return isAdmin(this.userId); | |||
| } | |||
| public static boolean isAdmin(Long userId) | |||
| { | |||
| public static boolean isAdmin(Long userId) { | |||
| return userId != null && 1L == userId; | |||
| } | |||
| public Long getDeptId() | |||
| { | |||
| public Long getDeptId() { | |||
| return deptId; | |||
| } | |||
| public void setDeptId(Long deptId) | |||
| { | |||
| public void setDeptId(Long deptId) { | |||
| this.deptId = deptId; | |||
| } | |||
| @Xss(message = "用户昵称不能包含脚本字符") | |||
| @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符") | |||
| public String getNickName() | |||
| { | |||
| public String getNickName() { | |||
| return nickName; | |||
| } | |||
| public void setNickName(String nickName) | |||
| { | |||
| public void setNickName(String nickName) { | |||
| this.nickName = nickName; | |||
| } | |||
| @Xss(message = "用户账号不能包含脚本字符") | |||
| @NotBlank(message = "用户账号不能为空") | |||
| @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符") | |||
| public String getUserName() | |||
| { | |||
| public String getUserName() { | |||
| return userName; | |||
| } | |||
| public void setUserName(String userName) | |||
| { | |||
| public void setUserName(String userName) { | |||
| this.userName = userName; | |||
| } | |||
| @Email(message = "邮箱格式不正确") | |||
| @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") | |||
| public String getEmail() | |||
| { | |||
| public String getEmail() { | |||
| return email; | |||
| } | |||
| public void setEmail(String email) | |||
| { | |||
| public void setEmail(String email) { | |||
| this.email = email; | |||
| } | |||
| @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符") | |||
| public String getPhonenumber() | |||
| { | |||
| public String getPhonenumber() { | |||
| return phonenumber; | |||
| } | |||
| public void setPhonenumber(String phonenumber) | |||
| { | |||
| public void setPhonenumber(String phonenumber) { | |||
| this.phonenumber = phonenumber; | |||
| } | |||
| public String getSex() | |||
| { | |||
| public String getSex() { | |||
| return sex; | |||
| } | |||
| public void setSex(String sex) | |||
| { | |||
| public void setSex(String sex) { | |||
| this.sex = sex; | |||
| } | |||
| public String getAvatar() | |||
| { | |||
| public String getAvatar() { | |||
| return avatar; | |||
| } | |||
| public void setAvatar(String avatar) | |||
| { | |||
| public void setAvatar(String avatar) { | |||
| this.avatar = avatar; | |||
| } | |||
| public String getPassword() | |||
| { | |||
| public String getPassword() { | |||
| return password; | |||
| } | |||
| public void setPassword(String password) | |||
| { | |||
| public void setPassword(String password) { | |||
| this.password = password; | |||
| } | |||
| public String getStatus() | |||
| { | |||
| public String getStatus() { | |||
| return status; | |||
| } | |||
| public void setStatus(String status) | |||
| { | |||
| public void setStatus(String status) { | |||
| this.status = status; | |||
| } | |||
| public String getDelFlag() | |||
| { | |||
| public String getDelFlag() { | |||
| return delFlag; | |||
| } | |||
| public void setDelFlag(String delFlag) | |||
| { | |||
| public void setDelFlag(String delFlag) { | |||
| this.delFlag = delFlag; | |||
| } | |||
| public String getLoginIp() | |||
| { | |||
| public String getLoginIp() { | |||
| return loginIp; | |||
| } | |||
| public void setLoginIp(String loginIp) | |||
| { | |||
| public void setLoginIp(String loginIp) { | |||
| this.loginIp = loginIp; | |||
| } | |||
| public Date getLoginDate() | |||
| { | |||
| public Date getLoginDate() { | |||
| return loginDate; | |||
| } | |||
| public void setLoginDate(Date loginDate) | |||
| { | |||
| public void setLoginDate(Date loginDate) { | |||
| this.loginDate = loginDate; | |||
| } | |||
| public SysDept getDept() | |||
| { | |||
| public SysDept getDept() { | |||
| return dept; | |||
| } | |||
| public void setDept(SysDept dept) | |||
| { | |||
| public void setDept(SysDept dept) { | |||
| this.dept = dept; | |||
| } | |||
| public List<SysRole> getRoles() | |||
| { | |||
| public List<SysRole> getRoles() { | |||
| return roles; | |||
| } | |||
| public void setRoles(List<SysRole> roles) | |||
| { | |||
| public void setRoles(List<SysRole> roles) { | |||
| this.roles = roles; | |||
| } | |||
| public Long[] getRoleIds() | |||
| { | |||
| public Long[] getRoleIds() { | |||
| return roleIds; | |||
| } | |||
| public void setRoleIds(Long[] roleIds) | |||
| { | |||
| public void setRoleIds(Long[] roleIds) { | |||
| this.roleIds = roleIds; | |||
| } | |||
| public Long[] getPostIds() | |||
| { | |||
| public Long[] getPostIds() { | |||
| return postIds; | |||
| } | |||
| public void setPostIds(Long[] postIds) | |||
| { | |||
| public void setPostIds(Long[] postIds) { | |||
| this.postIds = postIds; | |||
| } | |||
| public Long getRoleId() | |||
| { | |||
| public Long getRoleId() { | |||
| return roleId; | |||
| } | |||
| public void setRoleId(Long roleId) | |||
| { | |||
| public void setRoleId(Long roleId) { | |||
| this.roleId = roleId; | |||
| } | |||
| public void setGitLinkUsername(String gitLinkUsername) { | |||
| this.gitLinkUsername = gitLinkUsername; | |||
| } | |||
| public String getGitLinkUsername() { | |||
| return gitLinkUsername; | |||
| } | |||
| public void setGitLinkPassword(String gitLinkPassword) { | |||
| this.gitLinkPassword = gitLinkPassword; | |||
| } | |||
| public String getGitLinkPassword() { | |||
| return gitLinkPassword; | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) | |||
| .append("userId", getUserId()) | |||
| .append("deptId", getDeptId()) | |||
| .append("userName", getUserName()) | |||
| .append("nickName", getNickName()) | |||
| .append("email", getEmail()) | |||
| .append("phonenumber", getPhonenumber()) | |||
| .append("sex", getSex()) | |||
| .append("avatar", getAvatar()) | |||
| .append("password", getPassword()) | |||
| .append("status", getStatus()) | |||
| .append("delFlag", getDelFlag()) | |||
| .append("loginIp", getLoginIp()) | |||
| .append("loginDate", getLoginDate()) | |||
| .append("createBy", getCreateBy()) | |||
| .append("createTime", getCreateTime()) | |||
| .append("updateBy", getUpdateBy()) | |||
| .append("updateTime", getUpdateTime()) | |||
| .append("remark", getRemark()) | |||
| .append("dept", getDept()) | |||
| .toString(); | |||
| return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) | |||
| .append("userId", getUserId()) | |||
| .append("deptId", getDeptId()) | |||
| .append("userName", getUserName()) | |||
| .append("nickName", getNickName()) | |||
| .append("email", getEmail()) | |||
| .append("phonenumber", getPhonenumber()) | |||
| .append("sex", getSex()) | |||
| .append("avatar", getAvatar()) | |||
| .append("password", getPassword()) | |||
| .append("status", getStatus()) | |||
| .append("delFlag", getDelFlag()) | |||
| .append("loginIp", getLoginIp()) | |||
| .append("loginDate", getLoginDate()) | |||
| .append("createBy", getCreateBy()) | |||
| .append("createTime", getCreateTime()) | |||
| .append("updateBy", getUpdateBy()) | |||
| .append("updateTime", getUpdateTime()) | |||
| .append("remark", getRemark()) | |||
| .append("dept", getDept()) | |||
| .append("gitLinkUsername", getGitLinkUsername()) | |||
| .append("gitLinkPassword", getGitLinkPassword()) | |||
| .toString(); | |||
| } | |||
| } | |||
| @@ -15,6 +15,10 @@ spring: | |||
| discovery: | |||
| # 服务注册地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| username: nacos | |||
| password: nacos | |||
| retry: | |||
| enabled: true | |||
| config: | |||
| # 配置中心地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| @@ -22,4 +26,9 @@ spring: | |||
| file-extension: yml | |||
| # 共享配置 | |||
| shared-configs: | |||
| - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| - data-id: ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| @@ -15,6 +15,10 @@ spring: | |||
| discovery: | |||
| # 服务注册地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| username: nacos | |||
| password: nacos | |||
| retry: | |||
| enabled: true | |||
| config: | |||
| # 配置中心地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| @@ -22,7 +26,12 @@ spring: | |||
| file-extension: yml | |||
| # 共享配置 | |||
| shared-configs: | |||
| - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| - data-id: ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| sentinel: | |||
| # 取消控制台懒加载 | |||
| eager: true | |||
| @@ -33,7 +42,7 @@ spring: | |||
| datasource: | |||
| ds1: | |||
| nacos: | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:18848 | |||
| dataId: sentinel-ruoyi-gateway | |||
| groupId: DEFAULT_GROUP | |||
| data-type: json | |||
| @@ -140,7 +140,17 @@ | |||
| <dependency> | |||
| <groupId>com.github.docker-java</groupId> | |||
| <artifactId>docker-java</artifactId> | |||
| <version>3.1.1</version> | |||
| <version>3.2.13</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>commons-beanutils</groupId> | |||
| <artifactId>commons-beanutils</artifactId> | |||
| <version>1.9.4</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.github.docker-java</groupId> | |||
| <artifactId>docker-java-transport-httpclient5</artifactId> | |||
| <version>3.2.13</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>com.baomidou</groupId> | |||
| @@ -216,7 +226,22 @@ | |||
| <version>3.0.8</version> | |||
| <scope>compile</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>commons-lang</groupId> | |||
| <artifactId>commons-lang</artifactId> | |||
| <version>2.6</version> | |||
| <scope>compile</scope> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>org.eclipse.jgit</groupId> | |||
| <artifactId>org.eclipse.jgit</artifactId> | |||
| <version>5.13.0.202109080827-r</version> | |||
| </dependency> | |||
| <dependency> | |||
| <groupId>redis.clients</groupId> | |||
| <artifactId>jedis</artifactId> | |||
| <version>3.6.0</version> | |||
| </dependency> | |||
| </dependencies> | |||
| @@ -0,0 +1,21 @@ | |||
| package com.ruoyi.platform.constant; | |||
| public class Constant { | |||
| public final static int Image_Type_Pub = 1; // 公共镜像 | |||
| public final static int Image_Type_Pri = 0; // 私有镜像 | |||
| public final static int Code_Repo_Pub = 1; // 代码仓库可见性-公开 | |||
| public final static int Code_Repo_Pri = 0; // 代码仓库可见性-私有 | |||
| public final static int State_valid = 1; // 有效 | |||
| public final static int State_invalid = 0; // 无效 | |||
| public final static int Used_State_used = 1; // 已占用 | |||
| public final static int Used_State_unused = 0; // 未占用 | |||
| public final static String Computing_Resource_CPU = "CPU"; // 计算资源_CPU | |||
| public final static String Computing_Resource_GPU = "GPU"; // 计算资源_GPU | |||
| } | |||
| @@ -0,0 +1,69 @@ | |||
| package com.ruoyi.platform.controller.codeConfig; | |||
| import com.ruoyi.common.core.web.controller.BaseController; | |||
| import com.ruoyi.common.core.web.domain.GenericsAjaxResult; | |||
| import com.ruoyi.platform.domain.CodeConfig; | |||
| import com.ruoyi.platform.service.CodeConfigService; | |||
| import io.swagger.annotations.Api; | |||
| import org.springframework.data.domain.Page; | |||
| import org.springframework.data.domain.PageRequest; | |||
| import org.springframework.http.ResponseEntity; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import javax.annotation.Resource; | |||
| @RestController | |||
| @RequestMapping("codeConfig") | |||
| @Api("代码配置") | |||
| public class CodeConfigController extends BaseController { | |||
| @Resource | |||
| private CodeConfigService codeConfigService; | |||
| /** | |||
| * 分页查询 | |||
| * | |||
| * @param codeConfig 筛选条件 | |||
| * @param page 页数 | |||
| * @param size 每页大小 | |||
| * @return 查询结果 | |||
| */ | |||
| @GetMapping | |||
| public GenericsAjaxResult<Page<CodeConfig>> queryByPage(@RequestParam("page") int page, | |||
| @RequestParam("size") int size, | |||
| @RequestParam(value = "code_repo_name", required = false) String codeRepoName, | |||
| @RequestParam(value = "code_repo_vis", required = false)Integer codeRepoVis) { | |||
| PageRequest pageRequest = PageRequest.of(page, size); | |||
| CodeConfig codeConfig = new CodeConfig(); | |||
| codeConfig.setCodeRepoName(codeRepoName); | |||
| codeConfig.setCodeRepoVis(codeRepoVis); | |||
| return genericsSuccess(this.codeConfigService.queryByPage(codeConfig, pageRequest)); | |||
| } | |||
| /** | |||
| * 通过主键查询单条数据 | |||
| * | |||
| * @param id | |||
| * @return 单条数据 | |||
| */ | |||
| @GetMapping("{id}") | |||
| public GenericsAjaxResult<CodeConfig> queryById(@PathVariable("id") Long id) { | |||
| return genericsSuccess(this.codeConfigService.queryById(id)); | |||
| } | |||
| @PostMapping | |||
| public GenericsAjaxResult<CodeConfig> add(@RequestBody CodeConfig codeConfig) { | |||
| return genericsSuccess(this.codeConfigService.insert(codeConfig)); | |||
| } | |||
| @PutMapping | |||
| public GenericsAjaxResult<CodeConfig> update(@RequestBody CodeConfig codeConfig) { | |||
| return genericsSuccess(this.codeConfigService.update(codeConfig)); | |||
| } | |||
| @DeleteMapping("{id}") | |||
| public GenericsAjaxResult<String> delete(@PathVariable("id") Long id) { | |||
| return genericsSuccess(this.codeConfigService.removeById(id)); | |||
| } | |||
| } | |||
| @@ -224,5 +224,7 @@ public class DatasetController { | |||
| public AjaxResult uploadDatasetPipeline(@RequestBody(required =false) DatasetVersion datasetVersion) throws Exception { | |||
| return AjaxResult.success(this.datasetService.uploadDatasetPipeline(datasetVersion)); | |||
| } | |||
| } | |||
| @@ -0,0 +1,115 @@ | |||
| package com.ruoyi.platform.controller.dataset; | |||
| import com.ruoyi.common.core.web.domain.AjaxResult; | |||
| import com.ruoyi.platform.domain.Dataset; | |||
| import com.ruoyi.platform.service.DatasetService; | |||
| import com.ruoyi.platform.vo.DatasetVo; | |||
| import io.swagger.annotations.Api; | |||
| import io.swagger.annotations.ApiOperation; | |||
| import org.springframework.core.io.InputStreamResource; | |||
| import org.springframework.data.domain.PageRequest; | |||
| import org.springframework.http.ResponseEntity; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import javax.annotation.Resource; | |||
| @RestController | |||
| @RequestMapping("newdataset") | |||
| @Api(value = "新数据集管理") | |||
| public class NewDatasetFromGitController { | |||
| /** | |||
| * 服务对象 | |||
| */ | |||
| @Resource | |||
| private DatasetService datasetService; | |||
| /** | |||
| * 新增数据集与版本新 | |||
| * | |||
| * @param datasetVo 实体 | |||
| * @return 新增结果 | |||
| */ | |||
| @PostMapping("/addDatasetAndVersion") | |||
| @ApiOperation("添加数据集和版本") | |||
| public AjaxResult addDatasetAndVersion(@RequestBody DatasetVo datasetVo) throws Exception { | |||
| return AjaxResult.success(this.datasetService.newCreateDataset(datasetVo)); | |||
| } | |||
| /** | |||
| * 新增数据集与版本新 | |||
| * | |||
| * @param datasetVo 实体 | |||
| * @return 新增结果 | |||
| */ | |||
| @PostMapping("/addVersion") | |||
| @ApiOperation("添加版本") | |||
| public AjaxResult addVersion(@RequestBody DatasetVo datasetVo) throws Exception { | |||
| return AjaxResult.success(this.datasetService.newCreateVersion(datasetVo)); | |||
| } | |||
| /** | |||
| * 上传数据集 | |||
| * | |||
| * @param files 上传的数据集文件 | |||
| * @param uuid 上传唯一标识,构建url | |||
| * @return 上传结果 | |||
| */ | |||
| @CrossOrigin(origins = "*", allowedHeaders = "*") | |||
| @PostMapping("/upload") | |||
| @ApiOperation(value = "上传数据集") | |||
| public AjaxResult uploadDataset(@RequestParam("file") MultipartFile[] files, @RequestParam("uuid") String uuid) throws Exception { | |||
| return AjaxResult.success(this.datasetService.uploadDatasetlocal(files,uuid)); | |||
| } | |||
| /** | |||
| * 数据集打包下载 | |||
| * | |||
| * @param version 数据集版本 | |||
| * @return 单条数据 | |||
| */ | |||
| @GetMapping("/downloadAllFiles") | |||
| @ApiOperation(value = "下载同一版本下所有数据集,并打包") | |||
| public ResponseEntity<InputStreamResource> downloadAllDatasetFiles(@RequestParam("repository_name") String repositoryName, @RequestParam("version") String version) throws Exception { | |||
| return datasetService.downloadAllDatasetFilesNew(repositoryName, version); | |||
| } | |||
| /** | |||
| * 下载数据集 | |||
| * | |||
| * @param dataset_version_id ps:这里的id是dataset_version表的主键 | |||
| * @return 单条数据 | |||
| */ | |||
| @GetMapping("/download/{dataset_version_id}") | |||
| @ApiOperation(value = "下载单个数据集文件", notes = "根据数据集版本表id下载单个数据集文件") | |||
| public ResponseEntity<InputStreamResource> downloadDataset(@PathVariable("dataset_version_id") Integer dataset_version_id) throws Exception { | |||
| return datasetService.downloadDataset(dataset_version_id); | |||
| } | |||
| @GetMapping("/queryDatasets") | |||
| @ApiOperation("数据集广场公开数据集分页查询,根据data_type,data_tag筛选,true公开false私有") | |||
| public AjaxResult queryDatasets(Dataset dataset, @RequestParam("page") int page, | |||
| @RequestParam("size") int size, | |||
| @RequestParam(value = "is_public") Boolean isPublic, | |||
| @RequestParam(value = "data_type", required = false) String dataType, | |||
| @RequestParam(value = "data_tag", required = false) String dataTag) throws Exception { | |||
| PageRequest pageRequest = PageRequest.of(page, size); | |||
| if(isPublic){ | |||
| return AjaxResult.success(this.datasetService.newPubilcQueryByPage(dataset, pageRequest)); | |||
| }else { | |||
| return AjaxResult.success(this.datasetService.newPersonalQueryByPage(dataset, pageRequest)); | |||
| } | |||
| } | |||
| @GetMapping("/getdatasetDetail") | |||
| @ApiOperation(value = "获取数据集详情") | |||
| public AjaxResult getDatasetVersions(@PathVariable("datasetId") Integer datasetId) throws Exception { | |||
| return AjaxResult.success(this.datasetService.getDatasetVersions(datasetId)); | |||
| } | |||
| } | |||
| @@ -45,7 +45,7 @@ public class ImageController extends BaseController { | |||
| @RequestParam("size") int size, | |||
| @RequestParam(value = "image_type") int imageType) { | |||
| image.setImageType(imageType); | |||
| PageRequest pageRequest = PageRequest.of(page,size); | |||
| PageRequest pageRequest = PageRequest.of(page, size); | |||
| return genericsSuccess(this.imageService.queryByPage(image, pageRequest)); | |||
| } | |||
| @@ -72,22 +72,21 @@ public class ImageController extends BaseController { | |||
| public GenericsAjaxResult<Page<Image>> queryByName(@PathVariable("name") String name) { | |||
| return genericsSuccess(this.imageService.queryByName(name)); | |||
| } | |||
| /** | |||
| * 新增数据 | |||
| * | |||
| * @param image 实体 | |||
| * @return 新增结果 | |||
| */ | |||
| @PostMapping | |||
| @ApiOperation("新增镜像,不包含镜像版本") | |||
| public GenericsAjaxResult<Image> add(@RequestBody Image image) { | |||
| return genericsSuccess(this.imageService.insert(image)); | |||
| } | |||
| /** | |||
| * 新增镜像和版本 | |||
| * | |||
| * @param imageVo 实体 | |||
| * 新增镜像和版本 @PostMapping | |||
| * @return 新增结果 | |||
| */ | |||
| @PostMapping("/addImageAndVersion") | |||
| @@ -123,21 +122,20 @@ public class ImageController extends BaseController { | |||
| @PostMapping("/net") | |||
| @ApiOperation("从网络上传构建镜像") | |||
| public GenericsAjaxResult<Map<String, String>> createImageFromNet(@RequestParam("name") String imageName, | |||
| @RequestParam("tag") String imageTag, | |||
| @RequestParam("path") String path) throws Exception { | |||
| return genericsSuccess(this.imageService.createImageFromNet(imageName,imageTag,path)); | |||
| @RequestParam("tag") String imageTag, | |||
| @RequestParam("path") String path) throws Exception { | |||
| return genericsSuccess(this.imageService.createImageFromNet(imageName, imageTag, path)); | |||
| } | |||
| @PostMapping("/local") | |||
| @ApiOperation("从本地上传构建镜像") | |||
| public GenericsAjaxResult<Map<String, String>> createImageFromLocal(@RequestParam("name") String imageName, | |||
| @RequestParam("tag") String imageTag, | |||
| @RequestParam("path") String path) throws Exception { | |||
| return genericsSuccess(this.imageService.createImageFromLocal(imageName,imageTag,path)); | |||
| @RequestParam("tag") String imageTag, | |||
| @RequestParam("path") String path) throws Exception { | |||
| return genericsSuccess(this.imageService.createImageFromLocal(imageName, imageTag, path)); | |||
| } | |||
| /** | |||
| * 镜像上传 | |||
| * | |||
| @@ -146,8 +144,14 @@ public class ImageController extends BaseController { | |||
| @PostMapping("/upload") | |||
| @ApiOperation(value = "上传镜像文件", notes = "上传镜像tar包,返回存储路径") | |||
| public GenericsAjaxResult<Map<String, String>> uploadImageFiles(@RequestParam("file") MultipartFile file) throws Exception { | |||
| return genericsSuccess(this.imageService.uploadImageFiles(file)); | |||
| return genericsSuccess(this.imageService.uploadImageFiles(file)); | |||
| } | |||
| @PostMapping("/saveImage") | |||
| @ApiOperation(value = "保存环境为镜像", notes = "docker commit方式保存,并推送到horbor") | |||
| public void saveImage(@RequestBody ImageVo imageVo) { | |||
| this.imageService.saveImage(imageVo); | |||
| } | |||
| } | |||
| @@ -4,9 +4,12 @@ import com.ruoyi.common.core.web.controller.BaseController; | |||
| import com.ruoyi.common.core.web.domain.AjaxResult; | |||
| import com.ruoyi.common.core.web.domain.GenericsAjaxResult; | |||
| import com.ruoyi.platform.domain.DevEnvironment; | |||
| import com.ruoyi.platform.service.DatasetService; | |||
| import com.ruoyi.platform.service.JupyterService; | |||
| import com.ruoyi.platform.vo.DatasetVo; | |||
| import com.ruoyi.platform.vo.FrameLogPathVo; | |||
| import com.ruoyi.platform.vo.PodStatusVo; | |||
| import com.ruoyi.platform.vo.VersionVo; | |||
| import io.swagger.annotations.Api; | |||
| import io.swagger.annotations.ApiOperation; | |||
| import io.swagger.v3.oas.annotations.responses.ApiResponse; | |||
| @@ -17,6 +20,8 @@ import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| @RestController | |||
| @RequestMapping("/jupyter") | |||
| @@ -24,6 +29,8 @@ import java.io.InputStream; | |||
| public class JupyterController extends BaseController { | |||
| @Resource | |||
| private JupyterService jupyterService; | |||
| @Resource | |||
| private DatasetService datasetService; | |||
| @GetMapping(value = "/getURL") | |||
| @ApiOperation("得到访问地址") | |||
| public GenericsAjaxResult<String> getURL() throws IOException { | |||
| @@ -79,4 +86,21 @@ public class JupyterController extends BaseController { | |||
| jupyterService.mlflow(); | |||
| return AjaxResult.success(); | |||
| } | |||
| @GetMapping(value = "/testdvc") | |||
| public AjaxResult testdvc() throws Exception { | |||
| DatasetVo datasetVo = new DatasetVo(); | |||
| datasetVo.setName("testdassad23"); | |||
| datasetVo.setDescription("sss"); | |||
| datasetVo.setAvailableRange(0); | |||
| datasetVo.setDataTag("计算机视觉"); | |||
| datasetVo.setDataType("机器翻译"); | |||
| datasetVo.setVersion("dev"); | |||
| List<VersionVo> datasetVersionVos = new ArrayList<>(); | |||
| VersionVo versionVo = new VersionVo(); | |||
| versionVo.setUrl("E:/test/bb/data/xssa.doc"); | |||
| datasetVersionVos.add(versionVo); | |||
| datasetVo.setDatasetVersionVos(datasetVersionVos); | |||
| return AjaxResult.success(datasetService.newCreateDataset(datasetVo)); | |||
| } | |||
| } | |||
| @@ -0,0 +1,57 @@ | |||
| package com.ruoyi.platform.domain; | |||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.Data; | |||
| import java.io.Serializable; | |||
| import java.util.Date; | |||
| @Data | |||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||
| public class CodeConfig implements Serializable { | |||
| private Long id; | |||
| @ApiModelProperty(name = "code_repo_name",value = "代码仓库名称") | |||
| private String codeRepoName; | |||
| @ApiModelProperty(name = "code_repo_vis", value = "代码仓库可见性(1-公开,0-私有)") | |||
| private Integer codeRepoVis; | |||
| @ApiModelProperty(name = "git_url", value = "Git地址") | |||
| private String gitUrl; | |||
| @ApiModelProperty(name = "git_branch", value = "代码分支/Tag") | |||
| private String gitBranch; | |||
| @ApiModelProperty(name = "verify_mode", value = "验证方式(0-用户名密码,1-SSH-Key)") | |||
| private Integer verifyMode; | |||
| @ApiModelProperty(name = "git_user_name", value = "Git用户名") | |||
| private String gitUserName; | |||
| @ApiModelProperty(name = "git_password", value = "Git密码") | |||
| private String gitPassword; | |||
| @ApiModelProperty(name = "ssh_key",value = "SSH Key") | |||
| private String sshKey; | |||
| @ApiModelProperty(name = "create_by", value = "创建者") | |||
| private String createBy; | |||
| @ApiModelProperty(name = "create_time", value = "创建时间") | |||
| private Date createTime; | |||
| @ApiModelProperty(name = "update_by", value = "更新者") | |||
| private String updateBy; | |||
| @ApiModelProperty(name = "update_time", value = "更新时间") | |||
| private Date updateTime; | |||
| @ApiModelProperty(name = "state", value = "状态,0失效1生效") | |||
| private Integer state; | |||
| } | |||
| @@ -46,7 +46,11 @@ private Integer id; | |||
| @ApiModelProperty(value = "状态标识", notes = "0表示失效,1表示生效") | |||
| private Integer state; | |||
| @ApiModelProperty(value = "占用情况(1-占用,0-未占用)") | |||
| private Integer usedState; | |||
| @ApiModelProperty(value = "节点") | |||
| private String node; | |||
| public Integer getId() { | |||
| return id; | |||
| @@ -122,5 +126,20 @@ private Integer id; | |||
| this.state = state; | |||
| } | |||
| public Integer getUsedState() { | |||
| return usedState; | |||
| } | |||
| public void setUsedState(Integer usedState) { | |||
| this.usedState = usedState; | |||
| } | |||
| public String getNode() { | |||
| return node; | |||
| } | |||
| public void setNode(String node) { | |||
| this.node = node; | |||
| } | |||
| } | |||
| @@ -3,6 +3,7 @@ package com.ruoyi.platform.domain; | |||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.Data; | |||
| import java.util.Date; | |||
| import java.io.Serializable; | |||
| @@ -14,6 +15,7 @@ import java.io.Serializable; | |||
| * @since 2024-03-05 15:00:02 | |||
| */ | |||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||
| @Data | |||
| public class ImageVersion implements Serializable { | |||
| private static final long serialVersionUID = 251017725389874890L; | |||
| /** | |||
| @@ -56,102 +58,7 @@ public class ImageVersion implements Serializable { | |||
| @ApiModelProperty(value = "状态,0失效,1生效") | |||
| private Integer state; | |||
| public Integer getId() { | |||
| return id; | |||
| } | |||
| public void setId(Integer id) { | |||
| this.id = id; | |||
| } | |||
| public Integer getImageId() { | |||
| return imageId; | |||
| } | |||
| public void setImageId(Integer imageId) { | |||
| this.imageId = imageId; | |||
| } | |||
| public String getVersion() { | |||
| return version; | |||
| } | |||
| public void setVersion(String version) { | |||
| this.version = version; | |||
| } | |||
| public String getUrl() { | |||
| return url; | |||
| } | |||
| public void setUrl(String url) { | |||
| this.url = url; | |||
| } | |||
| public String getTagName() { | |||
| return tagName; | |||
| } | |||
| public void setTagName(String tagName) { | |||
| this.tagName = tagName; | |||
| } | |||
| public String getFileSize() { | |||
| return fileSize; | |||
| } | |||
| public void setFileSize(String fileSize) { | |||
| this.fileSize = fileSize; | |||
| } | |||
| public String getStatus() { | |||
| return status; | |||
| } | |||
| public void setStatus(String status) { | |||
| this.status = status; | |||
| } | |||
| public String getCreateBy() { | |||
| return createBy; | |||
| } | |||
| public void setCreateBy(String createBy) { | |||
| this.createBy = createBy; | |||
| } | |||
| public Date getCreateTime() { | |||
| return createTime; | |||
| } | |||
| public void setCreateTime(Date createTime) { | |||
| this.createTime = createTime; | |||
| } | |||
| public String getUpdateBy() { | |||
| return updateBy; | |||
| } | |||
| public void setUpdateBy(String updateBy) { | |||
| this.updateBy = updateBy; | |||
| } | |||
| public Date getUpdateTime() { | |||
| return updateTime; | |||
| } | |||
| public void setUpdateTime(Date updateTime) { | |||
| this.updateTime = updateTime; | |||
| } | |||
| public Integer getState() { | |||
| return state; | |||
| } | |||
| public void setState(Integer state) { | |||
| this.state = state; | |||
| } | |||
| @ApiModelProperty(value = "镜像所在主机ip") | |||
| private String hostIp; | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| package com.ruoyi.platform.mapper; | |||
| import com.ruoyi.platform.domain.CodeConfig; | |||
| import org.apache.ibatis.annotations.Param; | |||
| import org.springframework.data.domain.Pageable; | |||
| import java.util.List; | |||
| public interface CodeConfigDao { | |||
| long count(@Param("codeConfig") CodeConfig codeConfig); | |||
| List<CodeConfig> queryAllByLimit(@Param("codeConfig") CodeConfig codeConfig, @Param("pageable") Pageable pageable); | |||
| CodeConfig queryById(Long id); | |||
| Long queryByCodeRepoName(@Param("codeRepoName") String codeRepoName); | |||
| int insert(@Param("codeConfig") CodeConfig codeConfig); | |||
| int update(@Param("codeConfig") CodeConfig codeConfig); | |||
| } | |||
| @@ -73,6 +73,8 @@ public interface ComputingResourceDao { | |||
| */ | |||
| int update(@Param("computingResource") ComputingResource computingResource); | |||
| int updateUsedStateByNode(@Param("node")String node, @Param("usedState") Integer usedState); | |||
| /** | |||
| * 通过主键删除数据 | |||
| * | |||
| @@ -0,0 +1,19 @@ | |||
| package com.ruoyi.platform.service; | |||
| import com.ruoyi.platform.domain.CodeConfig; | |||
| import org.springframework.data.domain.Page; | |||
| import org.springframework.data.domain.PageRequest; | |||
| public interface CodeConfigService { | |||
| Page<CodeConfig> queryByPage(CodeConfig codeConfig, PageRequest pageRequest); | |||
| CodeConfig queryById(Long id); | |||
| CodeConfig insert(CodeConfig codeConfig); | |||
| CodeConfig update(CodeConfig codeConfig); | |||
| String removeById(Long id); | |||
| } | |||
| @@ -3,14 +3,17 @@ package com.ruoyi.platform.service; | |||
| import com.ruoyi.platform.domain.Dataset; | |||
| import com.ruoyi.platform.domain.DatasetVersion; | |||
| import com.ruoyi.platform.vo.DatasetVo; | |||
| import com.ruoyi.platform.vo.NewDatasetVo; | |||
| import org.springframework.core.io.InputStreamResource; | |||
| import org.springframework.data.domain.Page; | |||
| import org.springframework.data.domain.PageRequest; | |||
| import org.springframework.http.ResponseEntity; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import java.io.IOException; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.concurrent.CompletableFuture; | |||
| /** | |||
| * (Dataset)表服务接口 | |||
| @@ -84,4 +87,19 @@ DatasetService { | |||
| ResponseEntity<InputStreamResource> downloadAllDatasetFiles(Integer datasetId, String version) throws Exception; | |||
| List<Map<String, String>> exportDataset(String path, String uuid) throws Exception; | |||
| CompletableFuture<String> newCreateDataset(DatasetVo datasetVo) throws Exception; | |||
| CompletableFuture<String> newCreateVersion(DatasetVo datasetVo); | |||
| List<Map<String, String>> uploadDatasetlocal(MultipartFile[] files, String uuid) throws Exception; | |||
| ResponseEntity<InputStreamResource> downloadAllDatasetFilesNew(String repositoryName, String version) throws IOException, Exception; | |||
| Page<NewDatasetVo> newPersonalQueryByPage(Dataset dataset, PageRequest pageRequest) throws Exception; | |||
| Page<NewDatasetVo> newPubilcQueryByPage(Dataset dataset, PageRequest pageRequest) throws Exception; | |||
| } | |||
| @@ -0,0 +1,8 @@ | |||
| package com.ruoyi.platform.service; | |||
| public interface DvcService { | |||
| //使用dvc初始化,跟踪,push到远程仓库的接口 | |||
| public void initaddpushDvc(String localPath) throws Exception ; | |||
| } | |||
| @@ -31,7 +31,7 @@ public interface ExperimentInsService { | |||
| /** | |||
| * 根据实验ID查找所有具有相同ID的实例,并将它们添加到实验列表中 | |||
| * | |||
| * @param experimentId 实验id,不是实例id | |||
| * @param experimentId 实验id,不是实验实例id | |||
| * @return 实例列表 | |||
| */ | |||
| List<ExperimentIns> getByExperimentId(Integer experimentId) throws IOException; | |||
| @@ -0,0 +1,17 @@ | |||
| package com.ruoyi.platform.service; | |||
| import com.ruoyi.platform.vo.GitProjectVo; | |||
| import java.util.Map; | |||
| public interface GitService { | |||
| //登录方法,返回token | |||
| String login(String username, String password); | |||
| //输入token,项目名,tag,创建新项目,返回项目地址 | |||
| Map createProject(String token, GitProjectVo gitProjectVo) throws Exception; | |||
| void createBranch(String token,String owner, String projectName, String branchName, String oldBranchName) throws Exception; | |||
| void createTopic(String token, Integer id, String topicName) throws Exception; | |||
| } | |||
| @@ -93,6 +93,5 @@ public interface ImageService { | |||
| Map<String, String> createImageFromNet(String imageName, String imageTag, String NetPath) throws Exception; | |||
| Map<String, String> uploadImageFiles(MultipartFile file) throws Exception; | |||
| void saveImage(ImageVo imageVo); | |||
| } | |||
| @@ -0,0 +1,89 @@ | |||
| package com.ruoyi.platform.service.impl; | |||
| import com.ruoyi.common.security.utils.SecurityUtils; | |||
| import com.ruoyi.platform.constant.Constant; | |||
| import com.ruoyi.platform.domain.CodeConfig; | |||
| import com.ruoyi.platform.mapper.CodeConfigDao; | |||
| import com.ruoyi.platform.service.CodeConfigService; | |||
| import com.ruoyi.system.api.model.LoginUser; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.springframework.data.domain.Page; | |||
| import org.springframework.data.domain.PageImpl; | |||
| import org.springframework.data.domain.PageRequest; | |||
| import org.springframework.stereotype.Service; | |||
| import javax.annotation.Resource; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| @Service("codeConfigService") | |||
| public class CodeConfigServiceImpl implements CodeConfigService { | |||
| @Resource | |||
| private CodeConfigDao codeConfigDao; | |||
| @Override | |||
| public Page<CodeConfig> queryByPage(CodeConfig codeConfig, PageRequest pageRequest) { | |||
| long total = this.codeConfigDao.count(codeConfig); | |||
| List<CodeConfig> codeConfigList = this.codeConfigDao.queryAllByLimit(codeConfig, pageRequest); | |||
| return new PageImpl<>(codeConfigList, pageRequest, total); | |||
| } | |||
| @Override | |||
| public CodeConfig queryById(Long id) { | |||
| return this.codeConfigDao.queryById(id); | |||
| } | |||
| @Override | |||
| public CodeConfig insert(CodeConfig codeConfig) { | |||
| Long id = this.codeConfigDao.queryByCodeRepoName(codeConfig.getCodeRepoName()); | |||
| if(id != null){ | |||
| throw new IllegalStateException("代码仓库名称已存在"); | |||
| } | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| codeConfig.setCreateBy(loginUser.getUsername()); | |||
| codeConfig.setUpdateBy(loginUser.getUsername()); | |||
| codeConfig.setCreateTime(new Date()); | |||
| codeConfig.setUpdateTime(new Date()); | |||
| this.codeConfigDao.insert(codeConfig); | |||
| return codeConfig; | |||
| } | |||
| @Override | |||
| public CodeConfig update(CodeConfig codeConfig) { | |||
| Long id = this.codeConfigDao.queryByCodeRepoName(codeConfig.getCodeRepoName()); | |||
| if(id != null && !id.equals(codeConfig.getId())){ | |||
| throw new IllegalStateException("代码仓库名称已存在"); | |||
| } | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| codeConfig.setUpdateBy(loginUser.getUsername()); | |||
| if (codeConfig.getCodeRepoVis().equals(Constant.Code_Repo_Pub)) { | |||
| codeConfig.setVerifyMode(null); | |||
| codeConfig.setGitUserName(null); | |||
| codeConfig.setGitPassword(null); | |||
| codeConfig.setSshKey(null); | |||
| } | |||
| this.codeConfigDao.update(codeConfig); | |||
| return this.codeConfigDao.queryById(codeConfig.getId()); | |||
| } | |||
| @Override | |||
| public String removeById(Long id) { | |||
| CodeConfig codeConfig = this.codeConfigDao.queryById(id); | |||
| if (codeConfig == null) { | |||
| return "代码配置不存在"; | |||
| } | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String username = loginUser.getUsername(); | |||
| String createBy = codeConfig.getCreateBy(); | |||
| if (!(StringUtils.equals(username, "admin") || StringUtils.equals(username, createBy))) { | |||
| return "无权限删除该代码配置"; | |||
| } | |||
| codeConfig.setState(Constant.State_invalid); | |||
| return this.codeConfigDao.update(codeConfig) > 0 ? "删除成功" : "删除失败"; | |||
| } | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| package com.ruoyi.platform.service.impl; | |||
| import com.ruoyi.common.core.utils.DateUtils; | |||
| import com.ruoyi.common.security.utils.SecurityUtils; | |||
| import com.ruoyi.platform.annotations.CheckDuplicate; | |||
| import com.ruoyi.platform.domain.AssetIcon; | |||
| @@ -8,17 +8,15 @@ import com.ruoyi.platform.domain.Dataset; | |||
| import com.ruoyi.platform.domain.DatasetVersion; | |||
| import com.ruoyi.platform.mapper.DatasetDao; | |||
| import com.ruoyi.platform.mapper.DatasetVersionDao; | |||
| import com.ruoyi.platform.service.AssetIconService; | |||
| import com.ruoyi.platform.service.DatasetService; | |||
| import com.ruoyi.platform.service.DatasetVersionService; | |||
| import com.ruoyi.platform.service.MinioService; | |||
| import com.ruoyi.platform.utils.BeansUtils; | |||
| import com.ruoyi.platform.utils.FileUtil; | |||
| import com.ruoyi.platform.utils.MinioUtil; | |||
| import com.ruoyi.platform.vo.VersionVo; | |||
| import com.ruoyi.platform.service.*; | |||
| import com.ruoyi.platform.utils.*; | |||
| import com.ruoyi.platform.vo.DatasetVo; | |||
| import com.ruoyi.platform.vo.GitProjectVo; | |||
| import com.ruoyi.platform.vo.NewDatasetVo; | |||
| import com.ruoyi.platform.vo.VersionVo; | |||
| import com.ruoyi.system.api.model.LoginUser; | |||
| import io.minio.messages.Item; | |||
| import org.apache.commons.io.FileUtils; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.core.io.InputStreamResource; | |||
| @@ -32,14 +30,17 @@ import org.springframework.http.ResponseEntity; | |||
| import org.springframework.stereotype.Service; | |||
| import org.springframework.transaction.annotation.Transactional; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import redis.clients.jedis.Jedis; | |||
| import javax.annotation.Resource; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.ByteArrayOutputStream; | |||
| import java.io.InputStream; | |||
| import java.io.*; | |||
| import java.lang.reflect.Field; | |||
| import java.nio.file.Files; | |||
| import java.nio.file.Path; | |||
| import java.nio.file.Paths; | |||
| import java.text.SimpleDateFormat; | |||
| import java.util.*; | |||
| import java.util.concurrent.CompletableFuture; | |||
| import java.util.stream.Collectors; | |||
| import java.util.zip.ZipEntry; | |||
| import java.util.zip.ZipOutputStream; | |||
| @@ -67,6 +68,12 @@ public class DatasetServiceImpl implements DatasetService { | |||
| @Resource | |||
| private MinioService minioService; | |||
| @Resource | |||
| private GitService gitService; | |||
| @Resource | |||
| private DvcService dvcService; | |||
| // 固定存储桶名 | |||
| @Value("${minio.dataReleaseBucketName}") | |||
| private String bucketName; | |||
| @@ -74,7 +81,16 @@ public class DatasetServiceImpl implements DatasetService { | |||
| @Resource | |||
| private MinioUtil minioUtil; | |||
| @Value("${spring.redis.host}") | |||
| private String redisHost; | |||
| @Value("${minio.accessKey}") | |||
| String accessKeyId; | |||
| @Value("${minio.secretKey}") | |||
| String secretAccessKey; | |||
| @Value("${minio.endpoint}") | |||
| String endpoint; | |||
| @Value("${git.endpoint}") | |||
| String gitendpoint; | |||
| /** | |||
| * 通过ID查询单条数据 | |||
| @@ -370,7 +386,7 @@ public class DatasetServiceImpl implements DatasetService { | |||
| } | |||
| @Override | |||
| public ResponseEntity<InputStreamResource> downloadAllDatasetFiles(Integer datasetId, String version) throws Exception { | |||
| public ResponseEntity<InputStreamResource> downloadAllDatasetFiles(Integer datasetId, String version) throws Exception { | |||
| // 根据数据集id查数据名 | |||
| Dataset dataset = this.datasetDao.queryById(datasetId); | |||
| String datasetName = dataset.getName(); | |||
| @@ -440,4 +456,294 @@ public class DatasetServiceImpl implements DatasetService { | |||
| return results; | |||
| } | |||
| @Override | |||
| public CompletableFuture<String> newCreateDataset(DatasetVo datasetVo) { | |||
| return CompletableFuture.supplyAsync(() -> { | |||
| try { | |||
| String token = gitService.login("fanshuai", "h1n2x3j4y5@"); | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String ci4sUsername = loginUser.getUsername(); | |||
| Jedis jedis = new Jedis(redisHost); | |||
| String userReq = jedis.get(ci4sUsername + "_gitUserInfo"); | |||
| Map<String, Object> userInfo = JsonUtils.jsonToMap(userReq); | |||
| Integer userId = (Integer) userInfo.get("user_id"); | |||
| // 拼接project | |||
| String repositoryName = ci4sUsername + "_dataset_" + DateUtils.dateTimeNow(); | |||
| GitProjectVo gitProjectVo = new GitProjectVo(); | |||
| gitProjectVo.setRepositoryName(repositoryName); | |||
| gitProjectVo.setName(datasetVo.getName()); | |||
| gitProjectVo.setDescription(datasetVo.getDescription()); | |||
| gitProjectVo.setPrivate(datasetVo.getAvailableRange() == 0); | |||
| gitProjectVo.setUserId(userId); | |||
| // 创建项目 | |||
| Map project = gitService.createProject(token, gitProjectVo); | |||
| // 创建分支 | |||
| String branchName = datasetVo.getVersion(); | |||
| gitService.createBranch(token, (String) userInfo.get("login"), repositoryName, branchName, "master"); | |||
| // 定义标签 标签1:ci4s_dataset 标签2:DataTag 标签3:DataType | |||
| gitService.createTopic(token, (Integer) project.get("id"), "ci4s_dataset"); | |||
| gitService.createTopic(token, (Integer) project.get("id"), "DataTag_" + datasetVo.getDataTag()); | |||
| gitService.createTopic(token, (Integer) project.get("id"), "DataType_" + datasetVo.getDataType()); | |||
| // 得到项目地址 | |||
| String projectUrl = gitendpoint + "/" +(String) userInfo.get("login") + "/" + repositoryName + ".git"; | |||
| // 得到用户操作的路径 | |||
| String url = datasetVo.getDatasetVersionVos().get(0).getUrl(); | |||
| String localPath = "E:/test/" + datasetVo.getName(); | |||
| String sourcePath = url.substring(0, url.lastIndexOf("/")); | |||
| // 命令行操作 git clone 项目地址 | |||
| DVCUtils.gitClone(localPath, projectUrl, branchName, "fanshuai", "h1n2x3j4y5@"); | |||
| String s3Path = "management-platform-files/" + ci4sUsername + "/datasets/" + repositoryName + "/" + branchName; | |||
| //拼接生产的元数据后写入yaml文件 | |||
| YamlUtils.generateYamlFile(JsonUtils.objectToMap(datasetVo),sourcePath, "dataset"); | |||
| DVCUtils.moveFiles(sourcePath, localPath); | |||
| // dvc init 初始化 | |||
| DVCUtils.dvcInit(localPath); | |||
| // 配置远程S3地址 | |||
| DVCUtils.dvcRemoteAdd(localPath, s3Path); | |||
| DVCUtils.dvcConfigS3Credentials(localPath, endpoint); | |||
| DVCUtils.dvcConfigS3Credentials2(localPath, accessKeyId); | |||
| DVCUtils.dvcConfigS3Credentials3(localPath, secretAccessKey); | |||
| // dvc 跟踪 | |||
| DVCUtils.dvcAdd(localPath, "data"); | |||
| // git commit | |||
| DVCUtils.gitAdd(localPath, "."); | |||
| DVCUtils.gitCommit(localPath, "commit from ci4s with " + loginUser.getUsername()); | |||
| DVCUtils.gitPush(localPath, "fanshuai", "h1n2x3j4y5@"); | |||
| // dvc push 到远程S3 | |||
| DVCUtils.dvcPush(localPath); | |||
| return "新增数据集成功"; | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| }); | |||
| } | |||
| @Override | |||
| public CompletableFuture<String> newCreateVersion(DatasetVo datasetVo) { | |||
| return CompletableFuture.supplyAsync(() -> { | |||
| try { | |||
| String token = gitService.login("fanshuai", "h1n2x3j4y5@"); | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String ci4sUsername = loginUser.getUsername(); | |||
| Jedis jedis = new Jedis(redisHost); | |||
| String userReq = jedis.get(ci4sUsername + "_gitUserInfo"); | |||
| Map<String, Object> userInfo = JsonUtils.jsonToMap(userReq); | |||
| // 创建分支 | |||
| String branchName = StringUtils.isEmpty(datasetVo.getVersion())? "master" : datasetVo.getVersion(); | |||
| String repositoryName = datasetVo.getRepositoryName(); | |||
| if (StringUtils.equals(branchName, "master")) { | |||
| gitService.createBranch(token, (String) userInfo.get("login"), repositoryName, branchName, "master"); | |||
| } | |||
| // 得到项目地址 | |||
| String projectUrl = gitendpoint + "/" +(String) userInfo.get("login") + "/" + repositoryName + ".git"; | |||
| // 得到用户操作的路径 | |||
| String url = datasetVo.getDatasetVersionVos().get(0).getUrl(); | |||
| String localPath = "E:/test/"+ loginUser.getUsername()+"/datasets/"+ datasetVo.getName(); | |||
| String sourcePath = url.substring(0, url.lastIndexOf("/")); | |||
| // 命令行操作 git clone 项目地址 | |||
| DVCUtils.gitClone(localPath, projectUrl, branchName, "fanshuai", "h1n2x3j4y5@"); | |||
| String s3Path = "management-platform-files/" + ci4sUsername + "/datasets/" + repositoryName + "/" + branchName; | |||
| //拼接生产的元数据后写入yaml文件 | |||
| YamlUtils.generateYamlFile(JsonUtils.objectToMap(datasetVo),sourcePath, "dataset"); | |||
| DVCUtils.moveFiles(sourcePath, localPath); | |||
| // dvc init 初始化 | |||
| DVCUtils.dvcInit(localPath); | |||
| // 配置远程S3地址 | |||
| DVCUtils.dvcRemoteAdd(localPath, s3Path); | |||
| DVCUtils.dvcConfigS3Credentials(localPath, endpoint); | |||
| DVCUtils.dvcConfigS3Credentials2(localPath, accessKeyId); | |||
| DVCUtils.dvcConfigS3Credentials3(localPath, secretAccessKey); | |||
| // dvc 跟踪 | |||
| DVCUtils.dvcAdd(localPath, "data"); | |||
| // git commit | |||
| DVCUtils.gitAdd(localPath, "."); | |||
| DVCUtils.gitCommit(localPath, "commit from ci4s with " + loginUser.getUsername()); | |||
| DVCUtils.gitPush(localPath, "fanshuai", "h1n2x3j4y5@"); | |||
| // dvc push 到远程S3 | |||
| DVCUtils.dvcPush(localPath); | |||
| return "新增数据集成功"; | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| }); | |||
| } | |||
| @Override | |||
| public Page<NewDatasetVo> newPersonalQueryByPage(Dataset dataset, PageRequest pageRequest) throws Exception { | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String token = gitService.login("fanshuai", "h1n2x3j4y5@"); | |||
| String ci4sUsername = loginUser.getUsername(); | |||
| Jedis jedis = new Jedis(redisHost); | |||
| String userReq = jedis.get(ci4sUsername + "_gitUserInfo"); | |||
| Map<String, Object> userInfo = JsonUtils.jsonToMap(userReq); | |||
| //拼接查询url | |||
| String datasetTagName = dataset.getDatasetTagName(); | |||
| String datasetTypeName = dataset.getDatasetTypeName(); | |||
| String topic_name = "ci4s_dataset"; | |||
| topic_name =StringUtils.isEmpty(datasetTagName)?topic_name : topic_name+",datatag_" + datasetTagName; | |||
| topic_name =StringUtils.isEmpty(datasetTagName)?topic_name : topic_name+",datatype_" + datasetTypeName; | |||
| String url = gitendpoint + "/api/users/"+(String) userInfo.get("login")+"/projects.json?page="+pageRequest.getPageNumber()+"&limit="+pageRequest.getPageSize()+"&category=manage&topic_name="+topic_name; | |||
| String req = HttpUtils.sendGetWithToken(url,null,token); | |||
| Map<String, Object> stringObjectMap = JacksonUtil.parseJSONStr2Map(req); | |||
| Integer total = (Integer) stringObjectMap.get("count"); | |||
| List<Map<String, Object>> projects = (List<Map<String, Object>>) stringObjectMap.get("projects"); | |||
| return new PageImpl<>(convert(projects), pageRequest, total); | |||
| } | |||
| @Override | |||
| public Page<NewDatasetVo> newPubilcQueryByPage(Dataset dataset, PageRequest pageRequest) throws Exception { | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String token = gitService.login("fanshuai", "h1n2x3j4y5@"); | |||
| String ci4sUsername = loginUser.getUsername(); | |||
| Jedis jedis = new Jedis(redisHost); | |||
| String userReq = jedis.get(ci4sUsername + "_gitUserInfo"); | |||
| Map<String, Object> userInfo = JsonUtils.jsonToMap(userReq); | |||
| Integer userId = (Integer) userInfo.get("user_id"); | |||
| //拼接查询url | |||
| String datasetTagName = dataset.getDatasetTagName(); | |||
| String datasetTypeName = dataset.getDatasetTypeName(); | |||
| String topic_name = "ci4s_dataset"; | |||
| topic_name =StringUtils.isEmpty(datasetTagName)?topic_name : topic_name+",datatag_" + datasetTagName; | |||
| topic_name =StringUtils.isEmpty(datasetTagName)?topic_name : topic_name+",datatype_" + datasetTypeName; | |||
| String url = gitendpoint + "/api/projects.json?user_id="+userId+"&page="+pageRequest.getPageNumber()+"&limit="+pageRequest.getPageSize()+"&sort_by=praises_count&topic_name="+topic_name; | |||
| String req = HttpUtils.sendGetWithToken(url,null,token); | |||
| Map<String, Object> stringObjectMap = JacksonUtil.parseJSONStr2Map(req); | |||
| Integer total = (Integer) stringObjectMap.get("total_count"); | |||
| List<Map<String, Object>> projects = (List<Map<String, Object>>) stringObjectMap.get("projects"); | |||
| return new PageImpl<>(convert(projects), pageRequest, total); | |||
| } | |||
| @Override | |||
| public List<Map<String, String>> uploadDatasetlocal(MultipartFile[] files, String uuid) throws Exception { | |||
| List<Map<String, String>> results = new ArrayList<>(); | |||
| for (MultipartFile file:files){ | |||
| // 构建objectName | |||
| String username = SecurityUtils.getLoginUser().getUsername(); | |||
| String fileName = file.getOriginalFilename(); | |||
| String path = "/temp/"+ username +"/datasets/"+ uuid + "/"+"/data/" + fileName; | |||
| long sizeInBytes = file.getSize(); | |||
| String formattedSize = FileUtil.formatFileSize(sizeInBytes); | |||
| File targetFile = new File(path, file.getOriginalFilename()); | |||
| // 确保目录存在 | |||
| targetFile.getParentFile().mkdirs(); | |||
| // 保存文件到目标路径 | |||
| FileUtils.copyInputStreamToFile(file.getInputStream(), targetFile); | |||
| // 返回上传文件的路径 | |||
| String absolutePath = targetFile.getAbsolutePath(); | |||
| Map<String, String> result = new HashMap<>(); | |||
| result.put("fileName", fileName); | |||
| result.put("url", absolutePath); // objectName根据实际情况定义 | |||
| result.put("fileSize", formattedSize); | |||
| results.add(result); | |||
| } | |||
| return results; | |||
| } | |||
| @Override | |||
| public ResponseEntity<InputStreamResource> downloadAllDatasetFilesNew(String repositoryName, String version) throws Exception { | |||
| // 命令行操作 git clone 项目地址 | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String token = gitService.login("fanshuai", "h1n2x3j4y5@"); | |||
| String ci4sUsername = loginUser.getUsername(); | |||
| Jedis jedis = new Jedis(redisHost); | |||
| String userReq = jedis.get(ci4sUsername + "_gitUserInfo"); | |||
| Map<String, Object> userInfo = JsonUtils.jsonToMap(userReq); | |||
| Integer userId = (Integer) userInfo.get("user_id"); | |||
| String projectUrl = gitendpoint + "/" +(String) userInfo.get("login") + "/" + repositoryName + ".git"; | |||
| String localPath = "E:/test/"+ loginUser.getUsername()+"/datasets/" +repositoryName; | |||
| File folder = new File(localPath); | |||
| if(folder.exists() && folder.isDirectory()){ | |||
| //切换分支 | |||
| DVCUtils.gitCheckoutBranch(localPath, version); | |||
| //pull | |||
| DVCUtils.gitPull(localPath,"fanshuai", "h1n2x3j4y5@"); | |||
| //dvc pull | |||
| DVCUtils.dvcPull(localPath); | |||
| }else { | |||
| DVCUtils.gitClone(localPath, projectUrl, version, "fanshuai", "h1n2x3j4y5@"); | |||
| } | |||
| // 打包 data 文件夹 | |||
| String dataFolderPath = localPath + "/data"; | |||
| String zipFilePath = localPath + "/data.zip"; | |||
| try (FileOutputStream fos = new FileOutputStream(zipFilePath); | |||
| ZipOutputStream zos = new ZipOutputStream(fos)) { | |||
| Path sourcePath = Paths.get(dataFolderPath); | |||
| Files.walk(sourcePath).forEach(path -> { | |||
| if (!Files.isDirectory(path)) { | |||
| ZipEntry zipEntry = new ZipEntry(sourcePath.relativize(path).toString()); | |||
| try { | |||
| zos.putNextEntry(zipEntry); | |||
| Files.copy(path, zos); | |||
| zos.closeEntry(); | |||
| } catch (IOException e) { | |||
| throw new RuntimeException("Error while zipping: " + path, e); | |||
| } | |||
| } | |||
| }); | |||
| } | |||
| // 返回压缩文件的输入流 | |||
| File zipFile = new File(zipFilePath); | |||
| InputStreamResource resource = new InputStreamResource(new FileInputStream(zipFile)); | |||
| return ResponseEntity.ok() | |||
| .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=data.zip") | |||
| .contentType(MediaType.APPLICATION_OCTET_STREAM) | |||
| .contentLength(zipFile.length()) | |||
| .body(resource); | |||
| } | |||
| public List<NewDatasetVo> convert(List<Map<String, Object>> lst) { | |||
| if (lst != null && lst.size() > 0) { | |||
| List<NewDatasetVo> newDatasetVos = ConvertUtil.convertListMapToObjectList(lst, NewDatasetVo.class); | |||
| for (NewDatasetVo newDatasetVo : newDatasetVos) { | |||
| Map<String, Object> map = lst.stream() | |||
| .filter(m -> m.get("repo_id").equals(newDatasetVo.getRepoId())) | |||
| .findFirst() | |||
| .orElse(null); | |||
| if (map != null) { | |||
| List<Map<String, Object>> topics = (List<Map<String, Object>>) map.get("topics"); | |||
| if (topics != null) { | |||
| topics.forEach(topic -> { | |||
| String name = (String) topic.get("name"); | |||
| if (name != null) { | |||
| if (name.startsWith("datatag_")) { | |||
| newDatasetVo.setDataTag(name.substring("datatag_".length())); | |||
| } else if (name.startsWith("datatype_")) { | |||
| newDatasetVo.setDataType(name.substring("datatype_".length())); | |||
| } | |||
| } | |||
| }); | |||
| } | |||
| Map<String, Object> author = (Map<String, Object>) map.get("author"); | |||
| newDatasetVo.setCreateBy((String) author.get("name")); | |||
| } | |||
| } | |||
| return newDatasetVos; | |||
| } | |||
| return new ArrayList<>(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| package com.ruoyi.platform.service.impl; | |||
| import com.ruoyi.common.security.utils.SecurityUtils; | |||
| import com.ruoyi.platform.service.DvcService; | |||
| import com.ruoyi.platform.utils.DVCUtils; | |||
| import com.ruoyi.system.api.model.LoginUser; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.stereotype.Service; | |||
| @Service | |||
| public class DvcServiceImpl implements DvcService { | |||
| @Value("${minio.accessKey}") | |||
| String accessKeyId; | |||
| @Value("${minio.secretKey}") | |||
| String secretAccessKey; | |||
| @Value("${minio.endpoint}") | |||
| String endpoint; | |||
| @Override | |||
| public void initaddpushDvc(String localPath) throws Exception { | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| // dvc init 初始化 | |||
| DVCUtils.dvcInit(localPath); | |||
| // 配置远程S3地址 | |||
| DVCUtils.dvcRemoteAdd(localPath,""); | |||
| // DVCUtils.dvcConfigS3Credentials(localPath,endpoint, accessKeyId, secretAccessKey); | |||
| // dvc 跟踪 | |||
| DVCUtils.dvcAdd(localPath , "data"); | |||
| // git commit | |||
| DVCUtils.gitCommit(localPath, "commit from ci4s with "+loginUser.getUsername()); | |||
| // dvc push 到远程S3 | |||
| DVCUtils.dvcPush(localPath); | |||
| } | |||
| } | |||
| @@ -0,0 +1,98 @@ | |||
| package com.ruoyi.platform.service.impl; | |||
| import com.fasterxml.jackson.core.JsonProcessingException; | |||
| import com.ruoyi.common.security.utils.SecurityUtils; | |||
| import com.ruoyi.platform.service.GitService; | |||
| import com.ruoyi.platform.utils.HttpUtils; | |||
| import com.ruoyi.platform.utils.JsonUtils; | |||
| import com.ruoyi.platform.vo.GitProjectVo; | |||
| import com.ruoyi.system.api.model.LoginUser; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.stereotype.Service; | |||
| import redis.clients.jedis.Jedis; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| @Service | |||
| public class GitServiceImpl implements GitService { | |||
| @Value("${spring.redis.host}") | |||
| private String redisHost; | |||
| private static final Logger log = LoggerFactory.getLogger(GitServiceImpl.class); | |||
| @Override | |||
| public String login(String username, String password) { | |||
| // 构建请求参数 | |||
| Map<String, Object> params = new HashMap<>(); | |||
| params.put("grant_type", "password"); | |||
| params.put("username", username); | |||
| params.put("password", password); | |||
| params.put("client_id", "jEdGwrIJixCUIJM9vj2MwA6zmoTVhUdXxiSAaaCiXwA"); | |||
| params.put("client_secret", "L3wBKTNnRo-wPen7bxR3F1myCvtVDgpWa6MnpfyWeJE"); | |||
| try { | |||
| // 发送POST请求 | |||
| String req = HttpUtils.sendPostRequest("https://www.gitlink.org.cn/oauth/token",null, JsonUtils.mapToJson(params)); | |||
| // 解析响应JSON | |||
| if (StringUtils.isEmpty(req)) { | |||
| throw new RuntimeException("终止响应内容为空。"); | |||
| } | |||
| // 将响应的JSON字符串转换为Map对象 | |||
| Map<String, Object> runResMap = JsonUtils.jsonToMap(req); | |||
| // 提取access_token | |||
| // 提取access_token | |||
| String accessToken = (String) runResMap.get("access_token"); | |||
| //通过access_token获取用户信息 | |||
| String userReq = HttpUtils.sendGetWithToken("https://www.gitlink.org.cn/api/users/get_user_info.json",null, accessToken); | |||
| if (StringUtils.isEmpty(userReq)) { | |||
| throw new RuntimeException("终止响应内容为空。"); | |||
| } | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String ci4sUsername = loginUser.getUsername(); | |||
| // 将access_token存入Redis | |||
| Jedis jedis = new Jedis(redisHost); | |||
| jedis.set(ci4sUsername+"_gitToken", accessToken); | |||
| jedis.set(ci4sUsername+"_gitUserInfo", userReq); | |||
| return accessToken; | |||
| } catch (Exception e) { | |||
| log.error("登录GitLink失败。", e); | |||
| return null; | |||
| } | |||
| } | |||
| @Override | |||
| public Map createProject(String token, GitProjectVo gitProjectVo) throws Exception { | |||
| String userReq = HttpUtils.sendPostWithToken("https://www.gitlink.org.cn/api/projects.json",JsonUtils.objectToJson(gitProjectVo),token); | |||
| return JsonUtils.jsonToMap(userReq); | |||
| } | |||
| @Override | |||
| public void createBranch(String token,String owner, String projectName, String branchName, String oldBranchName) throws Exception { | |||
| //https://www.gitlink.org.cn/api/v1/fanshuai/testdssa8755/branches.json | |||
| // { | |||
| // "new_branch_name": "SsS", | |||
| // "old_branch_name": "master" | |||
| // } | |||
| String createBranchUrl = "https://www.gitlink.org.cn/api/v1/"+ owner + "/" + projectName + "/branches.json"; | |||
| Map<String, Object> resMap = new HashMap<>(); | |||
| resMap.put("new_branch_name", branchName); | |||
| resMap.put("old_branch_name", oldBranchName); | |||
| String req = HttpUtils.sendPostWithToken(createBranchUrl,JsonUtils.objectToJson(resMap),token); | |||
| System.out.println(req); | |||
| } | |||
| @Override | |||
| public void createTopic(String token, Integer id, String topicName) throws Exception { | |||
| // https://www.gitlink.org.cn/api/v1/project_topics.json | |||
| Map<String, Object> resMap = new HashMap<>(); | |||
| resMap.put("project_id", id); | |||
| resMap.put("name", topicName); | |||
| String req = HttpUtils.sendPostWithToken("https://www.gitlink.org.cn/api/v1/project_topics.json",JsonUtils.objectToJson(resMap),token); | |||
| System.out.println(req); | |||
| } | |||
| } | |||
| @@ -2,24 +2,29 @@ package com.ruoyi.platform.service.impl; | |||
| import com.alibaba.fastjson2.util.DateUtils; | |||
| import com.ruoyi.common.security.utils.SecurityUtils; | |||
| import com.ruoyi.platform.constant.Constant; | |||
| import com.ruoyi.platform.domain.DevEnvironment; | |||
| import com.ruoyi.platform.domain.Image; | |||
| import com.ruoyi.platform.domain.ImageVersion; | |||
| import com.ruoyi.platform.mapper.DevEnvironmentDao; | |||
| import com.ruoyi.platform.mapper.ImageDao; | |||
| import com.ruoyi.platform.mapper.ImageVersionDao; | |||
| import com.ruoyi.platform.service.ImageService; | |||
| import com.ruoyi.platform.service.ImageVersionService; | |||
| import com.ruoyi.platform.service.MinioService; | |||
| import com.ruoyi.platform.utils.DockerClientUtil; | |||
| import com.ruoyi.platform.utils.FileUtil; | |||
| import com.ruoyi.platform.utils.K8sClientUtil; | |||
| import com.ruoyi.platform.vo.ImageVo; | |||
| import com.ruoyi.system.api.model.LoginUser; | |||
| import io.kubernetes.client.openapi.models.V1PersistentVolumeClaim; | |||
| import io.kubernetes.client.openapi.models.V1Pod; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.springframework.beans.BeanUtils; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.data.domain.Page; | |||
| import org.springframework.data.domain.PageImpl; | |||
| import org.springframework.data.domain.PageRequest; | |||
| import org.springframework.scheduling.annotation.Async; | |||
| import org.springframework.stereotype.Service; | |||
| import org.springframework.transaction.annotation.Transactional; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| @@ -27,6 +32,7 @@ import org.springframework.web.multipart.MultipartFile; | |||
| import javax.annotation.Resource; | |||
| import java.util.Date; | |||
| import java.util.HashMap; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| import java.util.concurrent.CompletableFuture; | |||
| @@ -40,16 +46,19 @@ import java.util.concurrent.CompletableFuture; | |||
| public class ImageServiceImpl implements ImageService { | |||
| @Resource | |||
| private ImageDao imageDao; | |||
| @Resource | |||
| private ImageVersionDao imageVersionDao; | |||
| @Resource | |||
| private DevEnvironmentDao devEnvironmentDao; | |||
| @Resource | |||
| private ImageVersionService imageVersionService; | |||
| @Resource | |||
| private ImageVersionDao imageVersionDao; | |||
| @Resource | |||
| private K8sClientUtil k8sClientUtil; | |||
| @Resource | |||
| private DockerClientUtil dockerClientUtil; | |||
| @Resource | |||
| private MinioService minioService; | |||
| @Value("${harbor.bucketName}") | |||
| @@ -75,6 +84,9 @@ public class ImageServiceImpl implements ImageService { | |||
| private String proxyUrl; | |||
| @Value("${minio.pvcName}") | |||
| private String pvcName; | |||
| @Value("${jupyter.namespace}") | |||
| private String namespace; | |||
| /** | |||
| * 通过ID查询单条数据 | |||
| * | |||
| @@ -89,8 +101,8 @@ public class ImageServiceImpl implements ImageService { | |||
| /** | |||
| * 分页查询 | |||
| * | |||
| * @param image 筛选条件 | |||
| * @param pageRequest 分页对象 | |||
| * @param image 筛选条件 | |||
| * @param pageRequest 分页对象 | |||
| * @return 查询结果 | |||
| */ | |||
| @Override | |||
| @@ -100,7 +112,6 @@ public class ImageServiceImpl implements ImageService { | |||
| } | |||
| /** | |||
| * 新增数据 | |||
| * | |||
| @@ -128,7 +139,7 @@ public class ImageServiceImpl implements ImageService { | |||
| @Override | |||
| public Image update(Image image) { | |||
| int currentState = image.getState(); | |||
| if(currentState == 0){ | |||
| if (currentState == 0) { | |||
| throw new RuntimeException("镜像已被删除,无法更新。"); | |||
| } | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| @@ -153,7 +164,7 @@ public class ImageServiceImpl implements ImageService { | |||
| @Override | |||
| public String removeById(Integer id) throws Exception { | |||
| Image image = this.imageDao.queryById(id); | |||
| if (image == null){ | |||
| if (image == null) { | |||
| throw new Exception("镜像不存在"); | |||
| } | |||
| @@ -163,14 +174,20 @@ public class ImageServiceImpl implements ImageService { | |||
| String createdBy = image.getCreateBy(); | |||
| if (!(StringUtils.equals(username,"admin") || !StringUtils.equals(username,createdBy))){ | |||
| if (!(StringUtils.equals(username, "admin") || !StringUtils.equals(username, createdBy))) { | |||
| throw new Exception("无权限删除该镜像"); | |||
| } | |||
| if (!imageVersionService.queryByImageId(id).isEmpty()){ | |||
| throw new Exception("请先删除该镜像下的版本文件"); | |||
| // if (!imageVersionService.queryByImageId(id).isEmpty()){ | |||
| // throw new Exception("请先删除该镜像下的版本文件"); | |||
| // } | |||
| List<ImageVersion> imageVersions = imageVersionService.queryByImageId(id); | |||
| for (ImageVersion imageVersion :imageVersions) { | |||
| dockerClientUtil.removeImage(imageVersion.getUrl(), imageVersion.getHostIp()); | |||
| } | |||
| image.setState(0); | |||
| return this.imageDao.update(image)>0?"删除成功":"删除失败"; | |||
| return this.imageDao.update(image) > 0 ? "删除成功" : "删除失败"; | |||
| } | |||
| @@ -197,7 +214,7 @@ public class ImageServiceImpl implements ImageService { | |||
| public String insertImageAndVersion(ImageVo imageVo) throws Exception { | |||
| Image existingImage = getByName(imageVo.getName()); | |||
| Image imageToUse; | |||
| if(existingImage == null) { | |||
| if (existingImage == null) { | |||
| // 如果不存在相同名称的镜像,则创建新的镜像记录 | |||
| Image newImage = new Image(); | |||
| newImage.setName(imageVo.getName()); | |||
| @@ -207,7 +224,7 @@ public class ImageServiceImpl implements ImageService { | |||
| if (imageToUse == null) { | |||
| throw new Exception("新增镜像失败"); | |||
| } | |||
| }else{ | |||
| } else { | |||
| // 如果已存在相同名称的镜像,使用已存在的镜像 | |||
| imageToUse = existingImage; | |||
| } | |||
| @@ -225,9 +242,9 @@ public class ImageServiceImpl implements ImageService { | |||
| CompletableFuture.supplyAsync(() -> { | |||
| Map<String, String> resultMap = new HashMap<>(); | |||
| try { | |||
| if(imageVo.getUploadType()==0){ | |||
| resultMap = createImageFromNet(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); | |||
| }else{ | |||
| if (imageVo.getUploadType() == 0) { | |||
| resultMap = createImageFromNet(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); | |||
| } else { | |||
| resultMap = createImageFromLocal(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); | |||
| } | |||
| } catch (Exception e) { | |||
| @@ -236,7 +253,7 @@ public class ImageServiceImpl implements ImageService { | |||
| throw new RuntimeException("镜像构建失败: " + e.getMessage(), e); | |||
| } | |||
| return resultMap; | |||
| }).thenAccept(resultMap ->{ | |||
| }).thenAccept(resultMap -> { | |||
| try { | |||
| String imageUrl = resultMap.get("url"); | |||
| String fileSize = resultMap.get("fileSize"); | |||
| @@ -262,27 +279,27 @@ public class ImageServiceImpl implements ImageService { | |||
| // 得到容器 | |||
| V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | |||
| if (pod == null) { | |||
| String podName = deploymentName+"-"+ DateUtils.formatYMD10(new Date()); | |||
| pod = k8sClientUtil.createPodWithEnv(podName,serviceNS,proxyUrl,mountPath,pvcName,image); | |||
| String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); | |||
| pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, pvcName, image); | |||
| } | |||
| String loginCmd = "docker login -u " + harborUser +" -p "+harborpassword+" "+harborUrl; | |||
| String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; | |||
| // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 | |||
| String loginlog = k8sClientUtil.executeCommand(pod,loginCmd); | |||
| String loginlog = k8sClientUtil.executeCommand(pod, loginCmd); | |||
| // 在这个容器的/data/admin 目录下执行命令 docker load -i fileName 得到返回的镜像名字name:tag | |||
| String username = SecurityUtils.getLoginUser().getUsername(); | |||
| // | |||
| String logs2 = k8sClientUtil.executeCommand(pod,"docker pull "+ netPath); | |||
| String logs2 = k8sClientUtil.executeCommand(pod, "docker pull " + netPath); | |||
| // 在容器里执行 docker tag name:tag nexus3.kube-system.svc:8083/imageName:imageTag | |||
| if (StringUtils.isNoneBlank(logs2)){ | |||
| if (StringUtils.isNoneBlank(logs2)) { | |||
| String[] lines = logs2.split("\n"); | |||
| String lastLine = lines[lines.length - 1].trim(); | |||
| String tagCmd = "docker tag " + lastLine + " " + harborUrl + "/" + repository + "/" + username + "/" + imageName + ":" + imageTag; | |||
| String imageUrl = harborUrl + "/" + repository + "/" + username + "/" + imageName + ":" + imageTag; | |||
| String pushCmd = "docker push " + imageUrl; | |||
| String pushCmd = "docker push " + imageUrl; | |||
| String sizeCmd = "docker inspect --format='{{.Size}}' " + imageUrl; | |||
| String s = k8sClientUtil.executeCommand(pod, tagCmd); | |||
| if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))){ | |||
| if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))) { | |||
| resultMap.put("url", imageUrl); | |||
| //得到镜像文件大小 | |||
| String imageSizeStr = k8sClientUtil.executeCommand(pod, sizeCmd); | |||
| @@ -291,10 +308,10 @@ public class ImageServiceImpl implements ImageService { | |||
| resultMap.put("fileSize", formattedImageSize); | |||
| return resultMap; | |||
| }else { | |||
| } else { | |||
| throw new Exception("拉取公网镜像失败,请检查网络或者镜像地址"); | |||
| } | |||
| }else { | |||
| } else { | |||
| throw new Exception("拉取公网镜像失败,请检查网络或者镜像地址"); | |||
| } | |||
| } | |||
| @@ -305,27 +322,27 @@ public class ImageServiceImpl implements ImageService { | |||
| // 得到容器 | |||
| V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); | |||
| if (pod == null) { | |||
| String podName = deploymentName+"-"+ DateUtils.formatYMD10(new Date()); | |||
| pod = k8sClientUtil.createPodWithEnv(podName,serviceNS,proxyUrl,mountPath,pvcName,image); | |||
| String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); | |||
| pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, pvcName, image); | |||
| } | |||
| String loginCmd = "docker login -u " + harborUser +" -p "+harborpassword+" "+harborUrl; | |||
| String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; | |||
| // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 | |||
| String loginlog = k8sClientUtil.executeCommand(pod,loginCmd); | |||
| String loginlog = k8sClientUtil.executeCommand(pod, loginCmd); | |||
| // 在这个容器的/data/admin 目录下执行命令 docker load -i fileName 得到返回的镜像名字name:tag | |||
| String username = SecurityUtils.getLoginUser().getUsername(); | |||
| // | |||
| String filePath = "/data/argo-workflow/" + bucketName + "/" +path; | |||
| String logs2 = k8sClientUtil.executeCommand(pod,"docker load -i "+filePath); | |||
| String filePath = "/data/argo-workflow/" + bucketName + "/" + path; | |||
| String logs2 = k8sClientUtil.executeCommand(pod, "docker load -i " + filePath); | |||
| // 在容器里执行 docker tag name:tag nexus3.kube-system.svc:8083/imageName:imageTag | |||
| if (StringUtils.isNoneBlank(logs2)){ | |||
| String substring = logs2.substring(logs2.indexOf(":")+1).trim(); | |||
| if (StringUtils.isNoneBlank(logs2)) { | |||
| String substring = logs2.substring(logs2.indexOf(":") + 1).trim(); | |||
| String tagCmd = "docker tag " + substring + " " + harborUrl + "/" + repository + "/" + username + "/" + imageName + ":" + imageTag; | |||
| String imageUrl = harborUrl + "/" + repository + "/" + username + "/" + imageName + ":" + imageTag; | |||
| String pushCmd = "docker push " + imageUrl; | |||
| String pushCmd = "docker push " + imageUrl; | |||
| String sizeCmd = "docker inspect --format='{{.Size}}' " + imageUrl; | |||
| String s = k8sClientUtil.executeCommand(pod, tagCmd); | |||
| if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))){ | |||
| if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))) { | |||
| resultMap.put("url", imageUrl); | |||
| //得到镜像文件大小 | |||
| String imageSizeStr = k8sClientUtil.executeCommand(pod, sizeCmd); | |||
| @@ -333,18 +350,79 @@ public class ImageServiceImpl implements ImageService { | |||
| String formattedImageSize = FileUtil.formatFileSize(sizeInBytes); // 格式化镜像文件大小 | |||
| resultMap.put("fileSize", formattedImageSize); | |||
| return resultMap; | |||
| }else { | |||
| } else { | |||
| throw new Exception("解析镜像压缩包失败,请检查镜像文件"); | |||
| } | |||
| }else { | |||
| } else { | |||
| throw new Exception("解析镜像压缩包失败,请检查镜像文件"); | |||
| } | |||
| } | |||
| @Override | |||
| public Map<String, String> uploadImageFiles(MultipartFile file) throws Exception { | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String path = loginUser.getUsername()+"/"+file.getOriginalFilename(); | |||
| String path = loginUser.getUsername() + "/" + file.getOriginalFilename(); | |||
| return minioService.uploadFile(bucketName, path, file); | |||
| } | |||
| @Override | |||
| @Transactional | |||
| @Async | |||
| public void saveImage(ImageVo imageVo) { | |||
| Image oldImage = imageDao.getByName(imageVo.getName()); | |||
| if (oldImage != null) { | |||
| List<ImageVersion> oldImageVersions = imageVersionDao.queryByImageId(oldImage.getId()); | |||
| for (ImageVersion oldImageVersion : oldImageVersions) { | |||
| if(oldImageVersion.getTagName().equals(imageVo.getTagName())){ | |||
| throw new IllegalStateException("镜像tag不能重复"); | |||
| } | |||
| } | |||
| } | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String username = loginUser.getUsername().toLowerCase(); | |||
| String podName = username + "-editor-pod" + "-" + imageVo.getDevEnvironmentId().toString(); | |||
| try { | |||
| String containerId = k8sClientUtil.getPodContainerId(podName, namespace); | |||
| String hostIp = k8sClientUtil.getHostIp(podName, namespace); | |||
| dockerClientUtil.commitImage(imageVo, containerId, hostIp, username); | |||
| HashMap<String, String> resultMap = dockerClientUtil.pushImageToHorbor(imageVo, hostIp); | |||
| Image image = new Image(); | |||
| BeanUtils.copyProperties(imageVo, image); | |||
| image.setImageType(Constant.Image_Type_Pri); | |||
| image.setCreateBy(username); | |||
| image.setUpdateBy(username); | |||
| image.setUpdateTime(new Date()); | |||
| image.setCreateTime(new Date()); | |||
| image.setState(1); | |||
| imageDao.insert(image); | |||
| ImageVersion imageVersion = new ImageVersion(); | |||
| imageVersion.setImageId(image.getId()); | |||
| imageVersion.setVersion(imageVo.getVersion()); | |||
| imageVersion.setUrl(resultMap.get("imageName")); | |||
| imageVersion.setTagName(imageVo.getTagName()); | |||
| imageVersion.setFileSize(resultMap.get("size")); | |||
| imageVersion.setCreateBy(username); | |||
| imageVersion.setUpdateBy(username); | |||
| imageVersion.setHostIp(hostIp); | |||
| imageVersion.setUpdateTime(new Date()); | |||
| imageVersion.setCreateTime(new Date()); | |||
| imageVersion.setState(1); | |||
| imageVersion.setStatus("available"); | |||
| imageVersionDao.insert(imageVersion); | |||
| //更新dev环境的镜像信息 | |||
| DevEnvironment devEnvironment = new DevEnvironment(); | |||
| devEnvironment.setId(imageVo.getDevEnvironmentId()); | |||
| devEnvironment.setImage(resultMap.get("imageName")); | |||
| devEnvironmentDao.update(devEnvironment); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException("保存镜像失败:" + e); | |||
| } | |||
| } | |||
| } | |||
| @@ -2,8 +2,10 @@ package com.ruoyi.platform.service.impl; | |||
| import com.ruoyi.common.redis.service.RedisService; | |||
| import com.ruoyi.common.security.utils.SecurityUtils; | |||
| import com.ruoyi.platform.constant.Constant; | |||
| import com.ruoyi.platform.domain.DevEnvironment; | |||
| import com.ruoyi.platform.domain.PodStatus; | |||
| import com.ruoyi.platform.mapper.ComputingResourceDao; | |||
| import com.ruoyi.platform.mapper.DevEnvironmentDao; | |||
| import com.ruoyi.platform.service.DevEnvironmentService; | |||
| import com.ruoyi.platform.service.JupyterService; | |||
| @@ -54,6 +56,9 @@ public class JupyterServiceImpl implements JupyterService { | |||
| @Resource | |||
| private DevEnvironmentDao devEnvironmentDao; | |||
| @Resource | |||
| private ComputingResourceDao computingResourceDao; | |||
| @Resource | |||
| @Lazy | |||
| private DevEnvironmentService devEnvironmentService; | |||
| @@ -70,27 +75,29 @@ public class JupyterServiceImpl implements JupyterService { | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String podName = loginUser.getUsername().toLowerCase() + "-editor-pod"; | |||
| String pvcName = loginUser.getUsername().toLowerCase() + "-editor-pvc"; | |||
| V1PersistentVolumeClaim pvc = k8sClientUtil.createPvc(namespace, pvcName, storage,storageClassName); | |||
| V1PersistentVolumeClaim pvc = k8sClientUtil.createPvc(namespace, pvcName, storage, storageClassName); | |||
| Integer podPort = k8sClientUtil.createPod(podName, namespace, port, mountPath, pvc, image); | |||
| return masterIp + ":" + podPort; | |||
| } | |||
| @Override | |||
| public String runJupyterService(Integer id) throws Exception { | |||
| DevEnvironment devEnvironment = this.devEnvironmentDao.queryById(id); | |||
| if(devEnvironment == null){ | |||
| if (devEnvironment == null) { | |||
| throw new Exception("开发环境配置不存在"); | |||
| } | |||
| // 提取数据集,模型信息,得到数据集模型的path | |||
| Map<String, Object> dataset = JacksonUtil.parseJSONStr2Map(devEnvironment.getDataset()); | |||
| String datasetPath = (String) dataset.get("path"); | |||
| String datasetPath = "argo-workflow" + "/" + dataset.get("path"); | |||
| Map<String, Object> model = JacksonUtil.parseJSONStr2Map(devEnvironment.getModel()); | |||
| String modelPath = (String) model.get("path"); | |||
| String modelPath = "argo-workflow" + "/" + model.get("path"); | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| //手动构造pod名称 | |||
| String podName = loginUser.getUsername().toLowerCase() +"-editor-pod" + "-" + id; | |||
| //构造pod名称 | |||
| String podName = loginUser.getUsername().toLowerCase() + "-editor-pod" + "-" + id; | |||
| String pvcName = loginUser.getUsername().toLowerCase() + "-editor-pvc"; | |||
| //新建编辑器的pvc | |||
| V1PersistentVolumeClaim pvc = k8sClientUtil.createPvc(namespace, pvcName, storage, storageClassName); | |||
| @@ -98,41 +105,46 @@ public class JupyterServiceImpl implements JupyterService { | |||
| //TODO 设置镜像可配置,这里先用默认镜像启动pod | |||
| // 调用修改后的 createPod 方法,传入额外的参数 | |||
| Integer podPort = k8sClientUtil.createConfiguredPod(podName, namespace, port, mountPath, pvc, image, minioPvcName, datasetPath, modelPath); | |||
| // // 简单的延迟,以便 Pod 有时间启动 | |||
| // Thread.sleep(2500); | |||
| // //查询pod状态,更新到数据库 | |||
| // String podStatus = k8sClientUtil.getPodStatus(podName, namespace); | |||
| Integer podPort = k8sClientUtil.createConfiguredPod(podName, namespace, port, mountPath, pvc, devEnvironment, minioPvcName, datasetPath, modelPath); | |||
| String url = masterIp + ":" + podPort; | |||
| redisService.setCacheObject(podName,masterIp + ":" + podPort); | |||
| redisService.setCacheObject(podName, masterIp + ":" + podPort); | |||
| devEnvironment.setStatus("Pending"); | |||
| devEnvironment.setUrl(url); | |||
| this.devEnvironmentService.update(devEnvironment); | |||
| return url ; | |||
| return url; | |||
| } | |||
| @Override | |||
| public String stopJupyterService(Integer id) throws Exception { | |||
| DevEnvironment devEnvironment = this.devEnvironmentDao.queryById(id); | |||
| if (devEnvironment==null){ | |||
| if (devEnvironment == null) { | |||
| throw new Exception("开发环境配置不存在"); | |||
| } | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| //手动构造pod名称 | |||
| String podName = loginUser.getUsername().toLowerCase() +"-editor-pod" + "-" + id; | |||
| //构造pod和svc名称 | |||
| String podName = loginUser.getUsername().toLowerCase() + "-editor-pod" + "-" + id; | |||
| String svcName = loginUser.getUsername().toLowerCase() + "-editor-pod" + "-" + id + "-svc"; | |||
| //得到pod | |||
| V1Pod pod = k8sClientUtil.getNSPodList(namespace, podName); | |||
| if(pod == null){ | |||
| if (pod == null) { | |||
| return "pod不存在!"; | |||
| } | |||
| if (Constant.Computing_Resource_GPU.equals(devEnvironment.getComputingResource())) { | |||
| computingResourceDao.updateUsedStateByNode(pod.getSpec().getNodeName(), Constant.Used_State_unused); | |||
| } | |||
| // 使用 Kubernetes API 删除 Pod | |||
| String deleteResult = k8sClientUtil.deletePod(podName, namespace); | |||
| // 删除service | |||
| k8sClientUtil.deleteService(svcName, namespace); | |||
| devEnvironment.setStatus("Terminated"); | |||
| this.devEnvironmentService.update(devEnvironment); | |||
| return deleteResult + ",编辑器已停止"; | |||
| } | |||
| @Override | |||
| @@ -140,11 +152,11 @@ public class JupyterServiceImpl implements JupyterService { | |||
| String status = PodStatus.Terminated.getName(); | |||
| PodStatusVo JupyterStatusVo = new PodStatusVo(); | |||
| JupyterStatusVo.setStatus(status); | |||
| if (devEnvironment==null){ | |||
| if (devEnvironment == null) { | |||
| return JupyterStatusVo; | |||
| } | |||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | |||
| String podName = loginUser.getUsername().toLowerCase() +"-editor-pod" + "-" + devEnvironment.getId(); | |||
| String podName = loginUser.getUsername().toLowerCase() + "-editor-pod" + "-" + devEnvironment.getId(); | |||
| try { | |||
| // 查询相应pod状态 | |||
| @@ -170,7 +182,7 @@ public class JupyterServiceImpl implements JupyterService { | |||
| @Override | |||
| public void upload(InputStream inputStream) { | |||
| try { | |||
| minioUtil.uploadObject("platform-data","/pytorch/testupload4008208820",inputStream); | |||
| minioUtil.uploadObject("platform-data", "/pytorch/testupload4008208820", inputStream); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| @@ -185,7 +197,4 @@ public class JupyterServiceImpl implements JupyterService { | |||
| } | |||
| } | |||
| @@ -19,58 +19,91 @@ public class AIM64EncoderUtil { | |||
| } | |||
| public static String aim64encode(Map<String, Object> value) { | |||
| // 将Map对象转换为JSON字符串 | |||
| String jsonEncoded = JSON.toJSONString(value); | |||
| // 将JSON字符串进行Base64编码 | |||
| String base64Encoded = Base64.getEncoder().encodeToString(jsonEncoded.getBytes()); | |||
| String aim64Encoded = base64Encoded; | |||
| // 替换Base64编码中的特定字符 | |||
| for (Map.Entry<String, String> entry : BS64_REPLACE_CHARACTERS_ENCODING.entrySet()) { | |||
| aim64Encoded = aim64Encoded.replace(entry.getKey(), entry.getValue()); | |||
| } | |||
| // 返回带有前缀的AIM64编码字符串 | |||
| return AIM64_ENCODING_PREFIX + aim64Encoded; | |||
| } | |||
| // 这是一个静态方法,用于将 Map 对象 value 编码为字符串 | |||
| public static String encode(Map<String, Object> value, boolean oneWayHashing) { | |||
| // 如果 oneWayHashing 参数为 true,表示使用一种不可逆的哈希算法 | |||
| if (oneWayHashing) { | |||
| // 使用 MD5 算法将 value 对象转换为字符串 | |||
| return md5(JSON.toJSONString(value)); | |||
| } | |||
| // 如果 oneWayHashing 参数为 false,表示使用一种可逆的编码算法 | |||
| return aim64encode(value); | |||
| } | |||
| // MD5 加密函数,用于将输入字符串转换为 MD5 加密后的字符串。 | |||
| private static String md5(String input) { | |||
| // 尝试获取 MD5 加密对象 | |||
| try { | |||
| java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); | |||
| // 使用 MD5 对象对输入字符串进行加密 | |||
| byte[] array = md.digest(input.getBytes()); | |||
| // 创建一个 StringBuilder 对象,用于将加密后的字节转换为字符串 | |||
| StringBuilder sb = new StringBuilder(); | |||
| // 遍历加密后的字节数组 | |||
| for (byte b : array) { | |||
| // 将每个字节转换为 16 进制字符串 | |||
| sb.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1, 3)); | |||
| } | |||
| // 返回加密后的字符串 | |||
| return sb.toString(); | |||
| } catch (java.security.NoSuchAlgorithmException e) { | |||
| // 如果在获取 MD5 加密对象时出现了错误,则打印错误信息 | |||
| e.printStackTrace(); | |||
| } | |||
| // 如果出现了错误,则返回 null | |||
| return null; | |||
| } | |||
| // 这是一个 decode 方法,用于将 runIds 列表转换为查询字符串 | |||
| public static String decode(List<String> runIds) { | |||
| // 确保 runIds 列表的大小为 3 | |||
| if (runIds == null || runIds.size() == 0) { | |||
| // 如果 runIds 为空,抛出 IllegalArgumentException 异常 | |||
| throw new IllegalArgumentException("runIds 不能为空"); | |||
| } | |||
| // 构建查询字符串 | |||
| StringBuilder queryBuilder = new StringBuilder("run.hash in ["); | |||
| // 遍历 runIds 列表 | |||
| for (int i = 0; i < runIds.size(); i++) { | |||
| // 如果当前不是第一个元素,添加逗号 | |||
| if (i > 0) { | |||
| queryBuilder.append(","); | |||
| } | |||
| // 将当前元素添加到查询字符串中,使用双引号括起来 | |||
| queryBuilder.append("\"").append(runIds.get(i)).append("\""); | |||
| } | |||
| // 将查询字符串闭合 | |||
| queryBuilder.append("]"); | |||
| // 将查询字符串转换为字符串 | |||
| String query = queryBuilder.toString(); | |||
| // 创建一个 Map 对象,用于存储查询参数 | |||
| Map<String, Object> map = new HashMap<>(); | |||
| // 将查询字符串添加到 Map 中 | |||
| map.put("query", query); | |||
| // 将 advancedMode 设置为 true | |||
| map.put("advancedMode", true); | |||
| // 将 advancedQuery 设置为查询字符串 | |||
| map.put("advancedQuery", query); | |||
| // 使用 encode 方法将 Map 对象转换为查询字符串 | |||
| String searchQuery = encode(map, false); | |||
| // 返回查询字符串 | |||
| return searchQuery; | |||
| } | |||
| } | |||
| @@ -9,19 +9,30 @@ import java.util.Set; | |||
| public class BeansUtils { | |||
| // 获取一个 Java 对象中所有为空的属性名称。: | |||
| public static String[] getNullPropertyNames(Object source) { | |||
| // 创建一个 BeanWrapper 对象,参数为给定的 Java 对象 | |||
| final BeanWrapper src = new BeanWrapperImpl(source); | |||
| // 获取该对象所有属性描述符 | |||
| java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); | |||
| // 创建一个集合,用于存储为空的属性名称 | |||
| Set<String> emptyNames = new HashSet<String>(); | |||
| // 遍历所有属性描述符 | |||
| for(java.beans.PropertyDescriptor pd : pds) { | |||
| // 获取属性值 | |||
| Object srcValue = src.getPropertyValue(pd.getName()); | |||
| // 如果属性值为空,则将属性名称添加到集合中 | |||
| if (srcValue == null) emptyNames.add(pd.getName()); | |||
| } | |||
| // 创建一个字符串数组,用于存储为空的属性名称 | |||
| String[] result = new String[emptyNames.size()]; | |||
| // 将为空的属性名称存储到字符串数组中 | |||
| return emptyNames.toArray(result); | |||
| } | |||
| public static void copyPropertiesIgnoreNull(Object src, Object target){ | |||
| // 使用 BeanUtils 工具类将源对象中的非空属性复制到目标对象中 | |||
| BeanUtils.copyProperties(src, target, getNullPropertyNames(src)); | |||
| } | |||
| } | |||
| @@ -4,10 +4,13 @@ package com.ruoyi.platform.utils; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import org.springframework.beans.BeanUtils; | |||
| import org.apache.commons.beanutils.PropertyUtils; | |||
| import java.lang.reflect.Field; | |||
| import java.lang.reflect.InvocationTargetException; | |||
| import java.util.ArrayList; | |||
| import java.util.Collection; | |||
| import java.util.List; | |||
| import java.util.Map; | |||
| /** | |||
| @@ -19,6 +22,13 @@ import java.util.List; | |||
| public class ConvertUtil { | |||
| public static final Logger logger = LoggerFactory.getLogger(ConvertUtil.class); | |||
| /** | |||
| * 将实体对象转换为VO对象 | |||
| * @param source 源实体对象 | |||
| * @param target 目标VO对象的类 | |||
| * @return 转换后的VO对象 | |||
| */ | |||
| public static <T> T entityToVo(Object source, Class<T> target) { | |||
| if (source == null) { | |||
| return null; | |||
| @@ -33,6 +43,8 @@ public class ConvertUtil { | |||
| return targetObject; | |||
| } | |||
| // 将实体对象列表转换为目标类型的列表 | |||
| public static <T> List<T> entityToVoList(Collection<?> sourceList, Class<T> target) { | |||
| if (sourceList == null) { | |||
| return null; | |||
| @@ -50,5 +62,65 @@ public class ConvertUtil { | |||
| } | |||
| return targetList; | |||
| } | |||
| public static <T> List<T> convertListMapToObjectList(List<Map<String, Object>> listMap, Class<T> targetClass) { | |||
| List<T> resultList = new ArrayList<>(); | |||
| if (listMap != null) { | |||
| for (Map<String, Object> map : listMap) { | |||
| T targetObject = convertMapToObject(map, targetClass); | |||
| if (targetObject != null) { | |||
| resultList.add(targetObject); | |||
| } | |||
| } | |||
| } | |||
| return resultList; | |||
| } | |||
| private static <T> T convertMapToObject(Map<String, Object> map, Class<T> targetClass) { | |||
| try { | |||
| T targetObject = targetClass.newInstance(); | |||
| for (Map.Entry<String, Object> entry : map.entrySet()) { | |||
| String key = entry.getKey(); | |||
| Object value = entry.getValue(); | |||
| String camelCaseKey = toCamelCase(key); | |||
| if (hasProperty(targetClass, camelCaseKey)) { | |||
| PropertyUtils.setProperty(targetObject, camelCaseKey, value); | |||
| } | |||
| } | |||
| return targetObject; | |||
| } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| return null; | |||
| } | |||
| private static boolean hasProperty(Class<?> clazz, String propertyName) { | |||
| try { | |||
| Field field = clazz.getDeclaredField(propertyName); | |||
| return field != null; | |||
| } catch (NoSuchFieldException e) { | |||
| return false; | |||
| } | |||
| } | |||
| private static String toCamelCase(String key) { | |||
| StringBuilder sb = new StringBuilder(); | |||
| boolean nextUpperCase = false; | |||
| for (char c : key.toCharArray()) { | |||
| if (c == '_') { | |||
| nextUpperCase = true; | |||
| } else { | |||
| if (nextUpperCase) { | |||
| sb.append(Character.toUpperCase(c)); | |||
| nextUpperCase = false; | |||
| } else { | |||
| sb.append(c); | |||
| } | |||
| } | |||
| } | |||
| return sb.toString(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,165 @@ | |||
| package com.ruoyi.platform.utils; | |||
| import org.eclipse.jgit.api.*; | |||
| import org.eclipse.jgit.api.errors.GitAPIException; | |||
| import org.eclipse.jgit.lib.Repository; | |||
| import org.eclipse.jgit.storage.file.FileRepositoryBuilder; | |||
| import org.eclipse.jgit.transport.CredentialsProvider; | |||
| import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; | |||
| import java.io.*; | |||
| import java.nio.file.*; | |||
| public class DVCUtils { | |||
| private static void runCommand(String command, String workingDir) throws Exception { | |||
| ProcessBuilder processBuilder = new ProcessBuilder(command.split(" ")); | |||
| processBuilder.directory(new File(workingDir)); | |||
| Process process = processBuilder.start(); | |||
| BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); | |||
| String line; | |||
| while ((line = reader.readLine()) != null) { | |||
| System.out.println(line); | |||
| } | |||
| int exitCode = process.waitFor(); | |||
| if (exitCode != 0) { | |||
| throw new Exception("Command failed with exit code " + exitCode); | |||
| } | |||
| } | |||
| public static void moveFiles(String sourcePath, String targetPath) throws Exception { | |||
| Path sourceDir = Paths.get(sourcePath); | |||
| Path targetDir = Paths.get(targetPath).resolve(sourceDir.getFileName()); | |||
| if (!Files.exists(targetDir)) { | |||
| Files.createDirectories(targetDir); | |||
| } | |||
| Files.move(sourceDir, targetDir, StandardCopyOption.REPLACE_EXISTING); | |||
| } | |||
| public static void gitClone(String localPath, String repoUrl, String branch, String username, String password) throws GitAPIException { | |||
| CloneCommand cloneCommand = Git.cloneRepository() | |||
| .setURI(repoUrl) | |||
| .setBranch(branch) | |||
| .setDirectory(new java.io.File(localPath)) | |||
| .setCredentialsProvider(new UsernamePasswordCredentialsProvider(username, password)); | |||
| cloneCommand.call(); | |||
| } | |||
| public static void gitAdd(String localPath, String filePath) throws IOException, GitAPIException { | |||
| FileRepositoryBuilder builder = new FileRepositoryBuilder(); | |||
| Repository repository = builder.setGitDir(new File(localPath, ".git")) | |||
| .readEnvironment() | |||
| .findGitDir() | |||
| .build(); | |||
| try (Git git = new Git(repository)) { | |||
| AddCommand addCommand = git.add(); | |||
| addCommand.addFilepattern(filePath).call(); | |||
| } | |||
| } | |||
| public static void gitCommit(String localPath, String commitMessage) throws IOException, GitAPIException { | |||
| FileRepositoryBuilder builder = new FileRepositoryBuilder(); | |||
| Repository repository = builder.setGitDir(new File(localPath, ".git")) | |||
| .readEnvironment() | |||
| .findGitDir() | |||
| .build(); | |||
| try (Git git = new Git(repository)) { | |||
| // 添加所有文件 | |||
| AddCommand addCommand = git.add(); | |||
| addCommand.addFilepattern(".").call(); | |||
| // 提交更改 | |||
| CommitCommand commitCommand = git.commit(); | |||
| commitCommand.setMessage(commitMessage).call(); | |||
| } | |||
| } | |||
| public static void gitPush(String localPath, String username, String password) throws IOException, GitAPIException { | |||
| FileRepositoryBuilder builder = new FileRepositoryBuilder(); | |||
| Repository repository = builder.setGitDir(new File(localPath, ".git")) | |||
| .readEnvironment() | |||
| .findGitDir() | |||
| .build(); | |||
| try (Git git = new Git(repository)) { | |||
| CredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider(username, password); | |||
| PushCommand pushCommand = git.push(); | |||
| pushCommand.setCredentialsProvider(credentialsProvider) | |||
| .setForce(true) | |||
| .call(); | |||
| } | |||
| } | |||
| public static void gitCheckoutBranch(String localPath, String branchName) throws IOException, GitAPIException { | |||
| FileRepositoryBuilder builder = new FileRepositoryBuilder(); | |||
| Repository repository = builder.setGitDir(new File(localPath, ".git")) | |||
| .readEnvironment() | |||
| .findGitDir() | |||
| .build(); | |||
| try (Git git = new Git(repository)) { | |||
| CheckoutCommand checkoutCommand = git.checkout(); | |||
| checkoutCommand.setName(branchName).call(); | |||
| } | |||
| } | |||
| public static void gitPull(String localPath, String username, String password) throws IOException, GitAPIException { | |||
| FileRepositoryBuilder builder = new FileRepositoryBuilder(); | |||
| Repository repository = builder.setGitDir(new File(localPath, ".git")) | |||
| .readEnvironment() | |||
| .findGitDir() | |||
| .build(); | |||
| try (Git git = new Git(repository)) { | |||
| CredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider(username, password); | |||
| PullCommand pullCommand = git.pull(); | |||
| pullCommand.setCredentialsProvider(credentialsProvider).call(); | |||
| } | |||
| } | |||
| public static void dvcInit(String localPath) throws Exception { | |||
| String command = "dvc init"; | |||
| runCommand(command, localPath); | |||
| } | |||
| public static void dvcAdd(String localPath, String filePath) throws Exception { | |||
| String command = "dvc add " + filePath; | |||
| runCommand(command, localPath); | |||
| } | |||
| public static void dvcRemoteAdd(String localPath, String s3RemoteUrl) throws Exception { | |||
| String command = "dvc remote add -d myremote s3://" + s3RemoteUrl; | |||
| runCommand(command, localPath); | |||
| } | |||
| public static void dvcConfigS3Credentials(String localPath, String endpointurl) throws Exception { | |||
| String command = "dvc remote modify myremote endpointurl " + endpointurl; | |||
| runCommand(command, localPath); | |||
| } | |||
| public static void dvcConfigS3Credentials2(String localPath, String accessKeyId) throws Exception { | |||
| String command = "dvc remote modify myremote access_key_id " + accessKeyId; | |||
| runCommand(command, localPath); | |||
| } | |||
| public static void dvcConfigS3Credentials3(String localPath, String secretAccessKey) throws Exception { | |||
| String command = "dvc remote modify myremote secret_access_key " + secretAccessKey; | |||
| runCommand(command, localPath); | |||
| } | |||
| public static void dvcPush(String localPath) throws Exception { | |||
| String command = "dvc push"; | |||
| runCommand(command, localPath); | |||
| } | |||
| // 更新的 dvcPull 方法 | |||
| public static void dvcPull(String localPath) throws Exception { | |||
| String command = "dvc pull"; | |||
| runCommand(command, localPath); | |||
| } | |||
| } | |||
| @@ -0,0 +1,114 @@ | |||
| package com.ruoyi.platform.utils; | |||
| import com.github.dockerjava.api.DockerClient; | |||
| import com.github.dockerjava.api.command.CommitCmd; | |||
| import com.github.dockerjava.api.command.InspectImageResponse; | |||
| import com.github.dockerjava.api.model.AuthConfig; | |||
| import com.github.dockerjava.core.DefaultDockerClientConfig; | |||
| import com.github.dockerjava.core.DockerClientConfig; | |||
| import com.github.dockerjava.core.DockerClientImpl; | |||
| import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; | |||
| import com.github.dockerjava.transport.DockerHttpClient; | |||
| import com.ruoyi.platform.vo.ImageVo; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.stereotype.Component; | |||
| import java.time.Duration; | |||
| import java.util.HashMap; | |||
| @Slf4j | |||
| @Component | |||
| public class DockerClientUtil { | |||
| @Value("${harbor.bucketName}") | |||
| private String bucketName; | |||
| @Value("${harbor.repository}") | |||
| private String repository; | |||
| @Value("${harbor.harborUrl}") | |||
| private String harborUrl; | |||
| @Value("${harbor.harborUser}") | |||
| private String harborUser; | |||
| @Value("${harbor.harborpassword}") | |||
| private String harborpassword; | |||
| public DockerClient getDockerClient(String dockerServerUrl) { | |||
| //创建DefaultDockerClientConfig(指定docker服务器的配置) | |||
| DockerClientConfig config = DefaultDockerClientConfig | |||
| .createDefaultConfigBuilder() | |||
| .withDockerHost("tcp://" + dockerServerUrl + ":2375") | |||
| .withDockerTlsVerify(false) | |||
| .withApiVersion("1.40") | |||
| // .withDockerCertPath(dcokerCertPath) | |||
| // .withRegistryUsername(registryUser) | |||
| // .withRegistryPassword(registryPass) | |||
| // .withRegistryEmail(registryMail) | |||
| // .withRegistryUrl(registryUrl) | |||
| .build(); | |||
| //创建DockerHttpClient | |||
| DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder() | |||
| .dockerHost(config.getDockerHost()) | |||
| .sslConfig(config.getSSLConfig()) | |||
| .maxConnections(1000) | |||
| .connectionTimeout(Duration.ofSeconds(300)) | |||
| .responseTimeout(Duration.ofSeconds(450)) | |||
| .build(); | |||
| //创建DockerClient | |||
| return DockerClientImpl.getInstance(config, httpClient); | |||
| } | |||
| public String commitImage(ImageVo imageVo, String containerId, String hostIp, String userName) { | |||
| DockerClient dockerClient = getDockerClient(hostIp); | |||
| // 提交容器为镜像,这里的"new_image"和"new_tag"是新镜像的名字和标签 | |||
| CommitCmd commitCmd = dockerClient.commitCmd(containerId) | |||
| .withRepository(imageVo.getName()) | |||
| .withTag(imageVo.getTagName()) | |||
| .withAuthor(userName) | |||
| .withMessage(imageVo.getDescription()); | |||
| return commitCmd.exec(); | |||
| } | |||
| public HashMap<String, String> pushImageToHorbor(ImageVo imageVo, String hostIp) { | |||
| DockerClient dockerClient = getDockerClient(hostIp); | |||
| //Harbor登录信息 | |||
| AuthConfig autoConfig = new AuthConfig().withRegistryAddress(harborUrl).withUsername(harborUser).withPassword(harborpassword); | |||
| String localImageName = imageVo.getName() + ":" + imageVo.getTagName(); | |||
| String imageName = harborUrl + "/" + bucketName + "/" + imageVo.getName(); | |||
| //给镜像打上tag | |||
| dockerClient.tagImageCmd(localImageName, imageName, imageVo.getTagName()).exec(); | |||
| //推送镜像至镜像仓库 | |||
| try { | |||
| dockerClient.pushImageCmd(imageName).withAuthConfig(autoConfig).start().awaitCompletion(); | |||
| //push成功后,删除本地加载的镜像 | |||
| dockerClient.removeImageCmd(localImageName).exec(); | |||
| String totalImageName = imageName + ":" + imageVo.getTagName(); | |||
| InspectImageResponse exec = dockerClient.inspectImageCmd(totalImageName).exec(); | |||
| String size = String.format("%.1f GB", (float) exec.getSize() / 1073741824.0); | |||
| HashMap<String, String> resultMap = new HashMap<>(); | |||
| resultMap.put("imageName",totalImageName); | |||
| resultMap.put("size",size); | |||
| return resultMap; | |||
| } catch (InterruptedException e) { | |||
| throw new RuntimeException("推送镜像失败:" + e); | |||
| } | |||
| } | |||
| public void removeImage(String imageName, String hostIp){ | |||
| DockerClient dockerClient = getDockerClient(hostIp); | |||
| dockerClient.removeImageCmd(imageName).withForce(true).exec(); | |||
| } | |||
| } | |||
| @@ -2,20 +2,29 @@ package com.ruoyi.platform.utils; | |||
| public class FileUtil { | |||
| // 格式化文件大小为可读的字符串表示 | |||
| public static String formatFileSize(long sizeInBytes) { | |||
| // 检查文件大小是否为负数 | |||
| if (sizeInBytes < 0) { | |||
| throw new IllegalArgumentException("File size cannot be negative."); | |||
| } | |||
| // 如果文件大小小于1KB,直接返回字节数 | |||
| if (sizeInBytes < 1024) { | |||
| return sizeInBytes + " B"; | |||
| } else if (sizeInBytes < 1024 * 1024) { | |||
| } | |||
| // 如果文件大小小于1MB,转换为KB并返回 | |||
| else if (sizeInBytes < 1024 * 1024) { | |||
| double sizeInKB = sizeInBytes / 1024.0; | |||
| return String.format("%.2f KB", sizeInKB); | |||
| } else if (sizeInBytes < 1024 * 1024 * 1024) { | |||
| } | |||
| // 如果文件大小小于1GB,转换为MB并返回 | |||
| else if (sizeInBytes < 1024 * 1024 * 1024) { | |||
| double sizeInMB = sizeInBytes / (1024.0 * 1024); | |||
| return String.format("%.2f MB", sizeInMB); | |||
| } else { | |||
| } | |||
| // 如果文件大小大于或等于1GB,转换为GB并返回 | |||
| else { | |||
| double sizeInGB = sizeInBytes / (1024.0 * 1024 * 1024); | |||
| return String.format("%.2f GB", sizeInGB); | |||
| } | |||
| @@ -11,6 +11,7 @@ import org.apache.http.client.entity.UrlEncodedFormEntity; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import org.apache.http.client.methods.HttpGet; | |||
| import org.apache.http.client.methods.HttpPost; | |||
| import org.apache.http.client.utils.URIBuilder; | |||
| import org.apache.http.entity.StringEntity; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import org.apache.http.impl.client.DefaultHttpClient; | |||
| @@ -89,6 +90,110 @@ public class HttpUtils { | |||
| public static String sendGet(String url, String param) { | |||
| return sendGet(url, param, "UTF-8"); | |||
| } | |||
| // /** | |||
| // * 向指定 URL 发送带token的GET方法的请求 | |||
| // * | |||
| // * @param url 发送请求的 URL | |||
| // * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 | |||
| // * @return 所代表远程资源的响应结果 | |||
| // */ | |||
| // public static String sendGetWithToken(String url, String param,String token) { | |||
| // return sendGet(url, param, "UTF-8",token); | |||
| // } | |||
| /** | |||
| * 向指定 URL 发送带 token 的 GET 方法的请求,使用 Apache HttpClient | |||
| * | |||
| * @param url 发送请求的 URL | |||
| * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 | |||
| * @param token 认证 token | |||
| * @return 所代表远程资源的响应结果 | |||
| */ | |||
| public static String sendGetWithToken(String url, String param, String token) { | |||
| String result = ""; | |||
| try (CloseableHttpClient httpClient = HttpClients.createDefault()) { | |||
| URIBuilder uriBuilder = new URIBuilder(url); | |||
| if (param != null && !param.isEmpty()) { | |||
| String[] pairs = param.split("&"); | |||
| for (String pair : pairs) { | |||
| int idx = pair.indexOf("="); | |||
| if (idx != -1) { | |||
| uriBuilder.setParameter(pair.substring(0, idx), pair.substring(idx + 1)); | |||
| } | |||
| } | |||
| } | |||
| URI uri = uriBuilder.build(); | |||
| HttpGet httpGet = new HttpGet(uri); | |||
| httpGet.setHeader("Content-Type", "application/json"); | |||
| httpGet.setHeader("Authorization", "Bearer " + token); | |||
| log.info("Executing request: " + httpGet.getRequestLine()); | |||
| try (CloseableHttpResponse response = httpClient.execute(httpGet)) { | |||
| int statusCode = response.getStatusLine().getStatusCode(); | |||
| if (statusCode == 200) { | |||
| result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); | |||
| } else { | |||
| throw new IOException("HTTP request failed with response code: " + statusCode); | |||
| } | |||
| log.info("Response: " + result); | |||
| } | |||
| } catch (URISyntaxException e) { | |||
| log.error("URISyntaxException, url=" + url + ", param=" + param, e); | |||
| } catch (IOException e) { | |||
| log.error("IOException, url=" + url + ", param=" + param, e); | |||
| } | |||
| return result; | |||
| } | |||
| /** | |||
| * 向指定 URL 发送带token的GET方法的请求 | |||
| * | |||
| * @param url 发送请求的 URL | |||
| * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 | |||
| * @param contentType 编码类型 | |||
| * @return 所代表远程资源的响应结果 | |||
| */ | |||
| public static String sendGet(String url, String param, String contentType,String token) { | |||
| StringBuilder result = new StringBuilder(); | |||
| BufferedReader in = null; | |||
| try { | |||
| String urlNameString = url + "?" + param; | |||
| log.info("sendGet - {}", urlNameString); | |||
| URL realUrl = new URL(urlNameString); | |||
| URLConnection connection = realUrl.openConnection(); | |||
| connection.setRequestProperty("accept", "*/*"); | |||
| connection.setRequestProperty("connection", "Keep-Alive"); | |||
| connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); | |||
| connection.setRequestProperty("Authorization", "Bearer " + token); | |||
| connection.connect(); | |||
| in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); | |||
| String line; | |||
| while ((line = in.readLine()) != null) { | |||
| result.append(line); | |||
| } | |||
| log.info("recv - {}", result); | |||
| } catch (ConnectException e) { | |||
| log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e); | |||
| } catch (SocketTimeoutException e) { | |||
| log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e); | |||
| } catch (IOException e) { | |||
| log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e); | |||
| } catch (Exception e) { | |||
| log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e); | |||
| } finally { | |||
| try { | |||
| if (in != null) { | |||
| in.close(); | |||
| } | |||
| } catch (Exception ex) { | |||
| log.error("调用in.close Exception, url=" + url + ",param=" + param, ex); | |||
| } | |||
| } | |||
| return result.toString(); | |||
| } | |||
| /** | |||
| * 向指定 URL 发送GET方法的请求 | |||
| @@ -108,7 +213,6 @@ public class HttpUtils { | |||
| URLConnection connection = realUrl.openConnection(); | |||
| connection.setRequestProperty("accept", "*/*"); | |||
| connection.setRequestProperty("connection", "Keep-Alive"); | |||
| connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); | |||
| connection.connect(); | |||
| in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType)); | |||
| String line; | |||
| @@ -136,6 +240,42 @@ public class HttpUtils { | |||
| return result.toString(); | |||
| } | |||
| /** | |||
| * 向指定 URL 发送带token的POST方法的请求 | |||
| * | |||
| * @param url 发送请求的 URL | |||
| * @param | |||
| * @return 所代表远程资源的响应结果 | |||
| */ | |||
| public static String sendPostWithToken(String url, Object params, String token) throws Exception { | |||
| String resultStr = null; | |||
| HttpPost httpPost = new HttpPost(url); | |||
| if (params != null) { | |||
| StringEntity entity; | |||
| if (params instanceof Map) { | |||
| entity = new StringEntity(dealPostParams((HashMap<String, String>) params, "UTF-8")); | |||
| } else if (params instanceof String) { | |||
| entity = new StringEntity((String) params, "UTF-8"); | |||
| } else if (params instanceof List) { | |||
| entity = new UrlEncodedFormEntity((List<? extends NameValuePair>) params, "UTF-8"); | |||
| } else { | |||
| throw new Exception("参数有误!"); | |||
| } | |||
| httpPost.setHeader("Content-Type", "application/json"); | |||
| httpPost.setHeader("Authorization", "Bearer " + token); | |||
| httpPost.setEntity(entity); | |||
| } | |||
| try { | |||
| HttpResponse response = httpClient.execute(httpPost); | |||
| if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { | |||
| resultStr = EntityUtils.toString(response.getEntity()); | |||
| } | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| return resultStr; | |||
| } | |||
| /** | |||
| * 向指定 URL 发送POST方法的请求 | |||
| * | |||
| @@ -37,10 +37,8 @@ public class JsonUtils { | |||
| // 将JSON字符串转换为扁平化的Map | |||
| public static Map<String, Object> flattenJson(String prefix, Map<String, Object> map) { | |||
| Map<String, Object> flatMap = new HashMap<>(); | |||
| Iterator<Map.Entry<String, Object>> entries = map.entrySet().iterator(); | |||
| while (entries.hasNext()) { | |||
| Map.Entry<String, Object> entry = entries.next(); | |||
| for (Map.Entry<String, Object> entry : map.entrySet()) { | |||
| String key = entry.getKey(); | |||
| Object value = entry.getValue(); | |||
| @@ -53,4 +51,9 @@ public class JsonUtils { | |||
| return flatMap; | |||
| } | |||
| // 将Object转换为Map | |||
| public static Map<String, Object> objectToMap(Object object) throws IOException { | |||
| return objectMapper.convertValue(object, Map.class); | |||
| } | |||
| } | |||
| @@ -1,25 +1,25 @@ | |||
| package com.ruoyi.platform.utils; | |||
| import com.alibaba.nacos.shaded.com.google.gson.reflect.TypeToken; | |||
| import com.ruoyi.platform.constant.Constant; | |||
| import com.ruoyi.platform.domain.DevEnvironment; | |||
| import com.ruoyi.platform.mapper.ComputingResourceDao; | |||
| import io.kubernetes.client.Exec; | |||
| import io.kubernetes.client.custom.IntOrString; | |||
| import io.kubernetes.client.custom.Quantity; | |||
| import io.kubernetes.client.openapi.ApiClient; | |||
| import io.kubernetes.client.openapi.ApiException; | |||
| import io.kubernetes.client.openapi.ApiResponse; | |||
| import io.kubernetes.client.openapi.apis.CoreV1Api; | |||
| import io.kubernetes.client.openapi.models.*; | |||
| import io.kubernetes.client.util.ClientBuilder; | |||
| import io.kubernetes.client.util.Watch; | |||
| import io.kubernetes.client.util.credentials.AccessTokenAuthentication; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.apache.commons.lang.StringUtils; | |||
| import org.apache.poi.ss.formula.functions.T; | |||
| import org.json.JSONObject; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.beans.factory.annotation.Value; | |||
| import org.springframework.stereotype.Component; | |||
| import javax.annotation.PostConstruct; | |||
| import javax.annotation.Resource; | |||
| import java.io.BufferedReader; | |||
| import java.io.InputStreamReader; | |||
| import java.util.*; | |||
| @@ -40,6 +40,9 @@ public class K8sClientUtil { | |||
| */ | |||
| private static ApiClient apiClient; | |||
| @Resource | |||
| private ComputingResourceDao computingResourceDao; | |||
| /** | |||
| * 构建集群POD内通过SA访问的客户端 | |||
| * loading the in-cluster config, including: | |||
| @@ -133,11 +136,11 @@ public class K8sClientUtil { | |||
| } catch (ApiException e) { | |||
| log.error("获取 SVC 异常:", e); | |||
| } | |||
| if (v1ServiceList!=null) { | |||
| if (v1ServiceList != null) { | |||
| for (V1Service svc : v1ServiceList.getItems()) { | |||
| if (StringUtils.equals(svc.getMetadata().getName(), serviceName)) { | |||
| // PVC 已存在 | |||
| return svc; | |||
| // SVC 已存在 | |||
| return svc; | |||
| } | |||
| } | |||
| } | |||
| @@ -177,22 +180,22 @@ public class K8sClientUtil { | |||
| /** | |||
| * 创建k8s PVC | |||
| * | |||
| * @param namespace 命名空间 | |||
| * @param pvcName 服务名称 | |||
| * @param namespace 命名空间 | |||
| * @param pvcName 服务名称 | |||
| * @return 创建成功的service对象 | |||
| */ | |||
| public V1PersistentVolumeClaim createPvc(String namespace, String pvcName ,String storage, String storageClassName){ | |||
| public V1PersistentVolumeClaim createPvc(String namespace, String pvcName, String storage, String storageClassName) { | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| V1PersistentVolumeClaimList pvcList = null; | |||
| try { | |||
| pvcList = api.listNamespacedPersistentVolumeClaim(namespace, null,null, null, null, null,null,null, null, null, null); | |||
| pvcList = api.listNamespacedPersistentVolumeClaim(namespace, null, null, null, null, null, null, null, null, null, null); | |||
| } catch (ApiException e) { | |||
| log.error("获取 PVC 异常:", e); | |||
| } | |||
| if (pvcList!=null) { | |||
| if (pvcList != null) { | |||
| for (V1PersistentVolumeClaim pvc1 : pvcList.getItems()) { | |||
| if (StringUtils.equals(pvc1.getMetadata().getName(),pvcName)) { | |||
| if (StringUtils.equals(pvc1.getMetadata().getName(), pvcName)) { | |||
| // PVC 已存在 | |||
| return pvc1; | |||
| } | |||
| @@ -227,16 +230,17 @@ public class K8sClientUtil { | |||
| /** | |||
| * 创建k8s 临时POD | |||
| * | |||
| * @param podName pod name | |||
| * @param namespace 命名空间 | |||
| * @param port port | |||
| * @param namespace 命名空间 | |||
| * @param port port | |||
| * @param mountPath 映射路径 | |||
| * @param pvc 存储 | |||
| * @param image 镜像 | |||
| * @param pvc 存储 | |||
| * @param image 镜像 | |||
| * @return 创建成功的pod,的nodePort端口 | |||
| */ | |||
| public Integer createPod(String podName, String namespace, Integer port ,String mountPath, V1PersistentVolumeClaim pvc, String image){ | |||
| public Integer createPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, String image) { | |||
| Map<String, String> selector = new LinkedHashMap<String, String>(); | |||
| selector.put("k8s-jupyter", podName); | |||
| @@ -248,7 +252,7 @@ public class K8sClientUtil { | |||
| } catch (ApiException e) { | |||
| log.error("获取 POD 异常:", e); | |||
| } | |||
| if (v1PodList!=null) { | |||
| if (v1PodList != null) { | |||
| for (V1Pod pod1 : v1PodList.getItems()) { | |||
| if (StringUtils.equals(pod1.getMetadata().getName(), podName)) { | |||
| // PVC 已存在 | |||
| @@ -296,17 +300,18 @@ public class K8sClientUtil { | |||
| /** | |||
| * 创建k8s 临时POD | |||
| * | |||
| * @param podName pod name | |||
| * @param namespace 命名空间 | |||
| * @param port port | |||
| * @param namespace 命名空间 | |||
| * @param port port | |||
| * @param mountPath 映射路径 | |||
| * @param subPath pvc子路径 | |||
| * @param pvcName 存储名 | |||
| * @param image 镜像 | |||
| * @param subPath pvc子路径 | |||
| * @param pvcName 存储名 | |||
| * @param image 镜像 | |||
| * @return 创建成功的pod,的nodePort端口 | |||
| */ | |||
| public Integer createPodWithSubPath(String podName, String namespace, Integer port ,String mountPath,String subPath,String pvcName, String image){ | |||
| public Integer createPodWithSubPath(String podName, String namespace, Integer port, String mountPath, String subPath, String pvcName, String image) { | |||
| Map<String, String> selector = new LinkedHashMap<String, String>(); | |||
| selector.put("k8s-jupyter", podName); | |||
| @@ -318,7 +323,7 @@ public class K8sClientUtil { | |||
| } catch (ApiException e) { | |||
| log.error("获取 POD 异常:", e); | |||
| } | |||
| if (v1PodList!=null) { | |||
| if (v1PodList != null) { | |||
| for (V1Pod pod1 : v1PodList.getItems()) { | |||
| if (StringUtils.equals(pod1.getMetadata().getName(), podName)) { | |||
| // PVC 已存在 | |||
| @@ -375,11 +380,51 @@ public class K8sClientUtil { | |||
| return service.getSpec().getPorts().get(0).getNodePort(); | |||
| } | |||
| // 创建配置好的Pod | |||
| public Integer createConfiguredPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, DevEnvironment devEnvironment, String dataPvcName, String datasetPath, String modelPath) { | |||
| public Integer createConfiguredPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, String image, String dataPvcName, String datasetPath, String modelPath) { | |||
| //设置选择节点,pod反亲和性 | |||
| Map<String, String> selector = new LinkedHashMap<>(); | |||
| selector.put("k8s-jupyter", podName); | |||
| Map<String, String> nodeSelector = new LinkedHashMap<>(); | |||
| V1Affinity v1Affinity = new V1Affinity(); | |||
| if (Constant.Computing_Resource_GPU.equals(devEnvironment.getComputingResource())) { | |||
| selector.put("k8s-jupyter", "CPU-GPU"); | |||
| nodeSelector.put("resource-type", "CPU-GPU"); | |||
| V1LabelSelectorRequirement labelSelectorRequirement = new V1LabelSelectorRequirement() | |||
| .key("k8s-jupyter").operator("NotIn").values(Collections.singletonList("CPU-GPU")); | |||
| V1LabelSelector labelSelector = new V1LabelSelector() | |||
| .matchExpressions(Collections.singletonList(labelSelectorRequirement)); | |||
| V1PodAffinityTerm podAffinityTerm = new V1PodAffinityTerm() | |||
| .labelSelector(labelSelector) | |||
| .namespaces(Collections.singletonList(namespace)) | |||
| .topologyKey("kubernetes.io/hostname"); | |||
| V1PodAffinity podAffinity = new V1PodAffinity() | |||
| .requiredDuringSchedulingIgnoredDuringExecution(Collections.singletonList(podAffinityTerm)); | |||
| V1LabelSelectorRequirement antiLabelSelectorRequirement = new V1LabelSelectorRequirement() | |||
| .key("k8s-jupyter").operator("In").values(Collections.singletonList("CPU-GPU")); | |||
| V1LabelSelector antiLabelSelector = new V1LabelSelector() | |||
| .matchExpressions(Collections.singletonList(antiLabelSelectorRequirement)); | |||
| V1PodAffinityTerm antiPodAffinityTerm = new V1PodAffinityTerm() | |||
| .labelSelector(antiLabelSelector) | |||
| .namespaces(Collections.singletonList(namespace)) | |||
| .topologyKey("kubernetes.io/hostname"); | |||
| V1PodAntiAffinity podAntiAffinity = new V1PodAntiAffinity() | |||
| .requiredDuringSchedulingIgnoredDuringExecution(Collections.singletonList(antiPodAffinityTerm)); | |||
| v1Affinity.podAffinity(podAffinity).podAntiAffinity(podAntiAffinity); | |||
| } else { | |||
| selector.put("k8s-jupyter", "CPU"); | |||
| } | |||
| // 创建Pod | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| V1PodList v1PodList = null; | |||
| try { | |||
| @@ -402,14 +447,34 @@ public class K8sClientUtil { | |||
| // 配置卷和卷挂载 | |||
| List<V1VolumeMount> volumeMounts = new ArrayList<>(); | |||
| volumeMounts.add(new V1VolumeMount().name("workspace").mountPath(mountPath)); | |||
| volumeMounts.add(new V1VolumeMount().name("minio-pvc").mountPath("/datasets").subPath(datasetPath).readOnly(true)); | |||
| volumeMounts.add(new V1VolumeMount().name("minio-pvc").mountPath("/model").subPath(modelPath).readOnly(true)); | |||
| volumeMounts.add(new V1VolumeMount().name("minio-pvc").mountPath("/opt/data").subPath(datasetPath).readOnly(true)); | |||
| volumeMounts.add(new V1VolumeMount().name("minio-pvc").mountPath("/opt/model").subPath(modelPath).readOnly(true)); | |||
| List<V1Volume> volumes = new ArrayList<>(); | |||
| volumes.add(new V1Volume().name("workspace").persistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(pvc.getMetadata().getName()))); | |||
| volumes.add(new V1Volume().name("minio-pvc").persistentVolumeClaim(new V1PersistentVolumeClaimVolumeSource().claimName(dataPvcName))); | |||
| //配置资源 | |||
| JSONObject standardJson = new JSONObject(devEnvironment.getStandard()); | |||
| JSONObject valueJson = (JSONObject) standardJson.get("value"); | |||
| int cpu = (int) valueJson.get("cpu"); | |||
| String memory = (String) valueJson.get("memory"); | |||
| memory = memory.substring(0, memory.length() - 1).concat("i"); | |||
| int gpu = (int) valueJson.get("gpu"); | |||
| HashMap<String, Quantity> limitMap = new HashMap<>(); | |||
| if (Constant.Computing_Resource_GPU.equals(devEnvironment.getComputingResource())) { | |||
| limitMap.put("nvidia.com/gpu", new Quantity(String.valueOf(gpu))); | |||
| } | |||
| limitMap.put("cpu", new Quantity(String.valueOf(cpu))); | |||
| limitMap.put("memory", new Quantity(memory)); | |||
| limitMap.put("ephemeral-storage", new Quantity("100Gi")); | |||
| V1ResourceRequirements v1ResourceRequirements = new V1ResourceRequirements(); | |||
| v1ResourceRequirements.setRequests(limitMap); | |||
| v1ResourceRequirements.setLimits(limitMap); | |||
| V1Pod pod = new V1PodBuilder() | |||
| .withNewMetadata() | |||
| .withName(podName) | |||
| @@ -418,21 +483,27 @@ public class K8sClientUtil { | |||
| .withNewSpec() | |||
| .addNewContainer() | |||
| .withName(podName) | |||
| .withImage(image) | |||
| .withImage(devEnvironment.getImage()) | |||
| .withPorts(new V1ContainerPort().containerPort(port).protocol("TCP")) | |||
| .withVolumeMounts(volumeMounts) | |||
| .withResources(v1ResourceRequirements) | |||
| .endContainer() | |||
| .withVolumes(volumes) | |||
| .withTerminationGracePeriodSeconds(14400L) | |||
| .withNodeSelector(nodeSelector) | |||
| .withAffinity(v1Affinity) | |||
| .endSpec() | |||
| .build(); | |||
| try { | |||
| pod = api.createNamespacedPod(namespace, pod, null, null, null); | |||
| String nodeName = getNodeName(podName, namespace); | |||
| if (Constant.Computing_Resource_GPU.equals(devEnvironment.getComputingResource())) { | |||
| computingResourceDao.updateUsedStateByNode(nodeName, Constant.Used_State_used); | |||
| } | |||
| } catch (ApiException e) { | |||
| log.error("创建pod异常:" + e.getResponseBody(), e); | |||
| throw new RuntimeException("创建pod异常:" + e.getResponseBody()); | |||
| } catch (Exception e) { | |||
| log.error("创建pod系统异常:", e); | |||
| throw new RuntimeException("创建pod系统异常:", e); | |||
| } | |||
| V1Service service = createService(namespace, podName + "-svc", port, selector); | |||
| @@ -440,14 +511,12 @@ public class K8sClientUtil { | |||
| } | |||
| /** | |||
| * 根据获取namespace,deploymentName的Pod Name | |||
| * | |||
| * @return podList | |||
| */ | |||
| public V1Pod getNSPodList(String namespace,String deploymentName) throws Exception { | |||
| public V1Pod getNSPodList(String namespace, String deploymentName) throws Exception { | |||
| // new a CoreV1Api | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| V1PodList v1PodList = null; | |||
| @@ -468,12 +537,12 @@ public class K8sClientUtil { | |||
| return null; | |||
| } | |||
| public String executeCommand(V1Pod item, String command) { | |||
| public String executeCommand(V1Pod item, String command) { | |||
| try { | |||
| // 创建API实例 | |||
| // 创建Exec实例 | |||
| Exec exec = new Exec(apiClient); | |||
| String[] cmd = { "/bin/sh", "-c", command}; | |||
| String[] cmd = {"/bin/sh", "-c", command}; | |||
| Process proc = exec.exec(item, cmd, false); | |||
| // 读取输出 | |||
| BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream())); | |||
| @@ -498,19 +567,49 @@ public class K8sClientUtil { | |||
| /** | |||
| * 根据Pod的名称和Namespace查询Pod的状态 | |||
| * @param podName Pod的名称 | |||
| * | |||
| * @param podName Pod的名称 | |||
| * @param namespace Pod所在的Namespace | |||
| */ | |||
| public String getPodStatus(String podName, String namespace) throws Exception { | |||
| public String getPodStatus(String podName, String namespace) throws Exception { | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| V1Pod pod = api.readNamespacedPod(podName, namespace, null, null, null); | |||
| return pod.getStatus().getPhase(); | |||
| } | |||
| public String getPodLogs(String podName,String namespace,String container,int line) { | |||
| /** | |||
| * 根据Pod的名称和Namespace查询Pod的容器信息 | |||
| * | |||
| * @param podName Pod的名称 | |||
| * @param namespace Pod所在的Namespace | |||
| */ | |||
| public String getPodContainerId(String podName, String namespace) throws Exception { | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| V1Pod pod = api.readNamespacedPod(podName, namespace, null, null, null); | |||
| if (pod.getStatus().getContainerStatuses().size() != 1) { | |||
| throw new RuntimeException("容器错误"); | |||
| } | |||
| String containerId = pod.getStatus().getContainerStatuses().get(0).getContainerID().split("//")[1]; | |||
| return containerId; | |||
| } | |||
| public String getHostIp(String podName, String namespace) throws Exception { | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| V1Pod pod = api.readNamespacedPod(podName, namespace, null, null, null); | |||
| return pod.getStatus().getHostIP(); | |||
| } | |||
| public String getNodeName(String podName, String namespace) throws Exception { | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| V1Pod pod = api.readNamespacedPod(podName, namespace, null, null, null); | |||
| return pod.getSpec().getNodeName(); | |||
| } | |||
| public String getPodLogs(String podName, String namespace, String container, int line) { | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| try { | |||
| String log = api.readNamespacedPodLog(podName, namespace, StringUtils.isEmpty(container)?null:container, null, null, null, null,null, null, line, null); | |||
| String log = api.readNamespacedPodLog(podName, namespace, StringUtils.isEmpty(container) ? null : container, null, null, null, null, null, null, line, null); | |||
| return log; | |||
| } catch (ApiException e) { | |||
| throw new RuntimeException("获取Pod日志异常", e); | |||
| @@ -519,7 +618,7 @@ public class K8sClientUtil { | |||
| } | |||
| public V1Pod createPodWithEnv(String podName,String namespace,String proxyUrl ,String mountPath,String pvcName, String image){ | |||
| public V1Pod createPodWithEnv(String podName, String namespace, String proxyUrl, String mountPath, String pvcName, String image) { | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| V1PodList v1PodList = null; | |||
| V1Pod pod = new V1PodBuilder() | |||
| @@ -563,7 +662,7 @@ public class K8sClientUtil { | |||
| /** | |||
| * 删除 Pod | |||
| * | |||
| * @param podName Pod 名称 | |||
| * @param podName Pod 名称 | |||
| * @param namespace 命名空间 | |||
| * @throws ApiException 异常 | |||
| */ | |||
| @@ -578,10 +677,30 @@ public class K8sClientUtil { | |||
| } | |||
| } | |||
| /** | |||
| * 删除 Service | |||
| * | |||
| * @param svcName Service 名称 | |||
| * @param namespace 命名空间 | |||
| * @throws ApiException 异常 | |||
| */ | |||
| public String deleteService(String svcName, String namespace) throws ApiException { | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| try { | |||
| V1Status result = api.deleteNamespacedService(svcName, namespace, null, null, null, null, null, null); | |||
| return "Service " + svcName + " 删除请求已发送"; | |||
| } catch (ApiException e) { | |||
| log.error("删除service异常:" + e.getResponseBody(), e); | |||
| throw e; | |||
| } | |||
| } | |||
| /** | |||
| * 检查 Pod 是否存在 | |||
| * | |||
| * @param podName Pod 名称 | |||
| * @param podName Pod 名称 | |||
| * @param namespace 命名空间 | |||
| * @return 是否存在 | |||
| * @throws ApiException 异常 | |||
| @@ -589,7 +708,7 @@ public class K8sClientUtil { | |||
| public boolean checkPodExists(String podName, String namespace) throws ApiException { | |||
| CoreV1Api api = new CoreV1Api(apiClient); | |||
| try { | |||
| api.readNamespacedPod(podName, namespace, null,false,false); | |||
| api.readNamespacedPod(podName, namespace, null, false, false); | |||
| return true; | |||
| } catch (ApiException e) { | |||
| if (e.getCode() == 404) { | |||
| @@ -7,7 +7,8 @@ import org.springframework.stereotype.Component; | |||
| import java.util.List; | |||
| @Component | |||
| public class MlflowUtil { | |||
| public class | |||
| MlflowUtil { | |||
| private static String trackingUri = "http://172.20.32.181:32005"; | |||
| private MlflowClient client; | |||
| @@ -0,0 +1,28 @@ | |||
| package com.ruoyi.platform.utils; | |||
| import org.yaml.snakeyaml.Yaml; | |||
| import java.io.FileWriter; | |||
| import java.io.IOException; | |||
| import java.util.Map; | |||
| public class YamlUtils { | |||
| /** | |||
| * 将Map对象转换为YAML格式并写入指定路径的文件中 | |||
| * | |||
| * @param data Map对象 | |||
| * @param path 文件路径 | |||
| * @param fileName 文件名 | |||
| */ | |||
| public static void generateYamlFile(Map<String, Object> data, String path, String fileName) { | |||
| Yaml yaml = new Yaml(); | |||
| String fullPath = path + "/" + fileName + ".yaml"; | |||
| try (FileWriter writer = new FileWriter(fullPath)) { | |||
| yaml.dump(data, writer); | |||
| } catch (IOException e) { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| } | |||
| @@ -3,11 +3,13 @@ package com.ruoyi.platform.vo; | |||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.Data; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||
| @Data | |||
| public class DatasetVo implements Serializable { | |||
| @@ -25,6 +27,7 @@ public class DatasetVo implements Serializable { | |||
| private String dataType; | |||
| @ApiModelProperty(name = "data_tag") | |||
| private String dataTag; | |||
| /** | |||
| * 版本 | |||
| */ | |||
| @@ -33,73 +36,17 @@ public class DatasetVo implements Serializable { | |||
| @ApiModelProperty(name = "dataset_version_vos") | |||
| private List<VersionVo> datasetVersionVos; | |||
| /** | |||
| * 可用集群 | |||
| */ | |||
| @ApiModelProperty(name = "available_cluster") | |||
| private String availableCluster; | |||
| public String getName() { | |||
| return name; | |||
| } | |||
| public void setName(String name) { | |||
| this.name = name; | |||
| } | |||
| public String getDescription() { | |||
| return description; | |||
| } | |||
| public void setDescription(String description) { | |||
| this.description = description; | |||
| } | |||
| public int getAvailableRange() { | |||
| return availableRange; | |||
| } | |||
| public void setAvailableRange(int availableRange) { | |||
| this.availableRange = availableRange; | |||
| } | |||
| public String getDataType() { | |||
| return dataType; | |||
| } | |||
| public void setDataType(String dataType) { | |||
| this.dataType = dataType; | |||
| } | |||
| public String getDataTag() { | |||
| return dataTag; | |||
| } | |||
| public void setDataTag(String dataTag) { | |||
| this.dataTag = dataTag; | |||
| } | |||
| public String getVersion() { | |||
| return version; | |||
| } | |||
| public void setVersion(String version) { | |||
| this.version = version; | |||
| } | |||
| public List<VersionVo> getDatasetVersionVos() { | |||
| return datasetVersionVos; | |||
| } | |||
| public void setDatasetVersionVos(List<VersionVo> datasetVersionVos) { | |||
| this.datasetVersionVos = datasetVersionVos; | |||
| } | |||
| public String getAvailableCluster() { | |||
| return availableCluster; | |||
| } | |||
| public void setAvailableCluster(String availableCluster) { | |||
| this.availableCluster = availableCluster; | |||
| } | |||
| /** | |||
| * 数据集仓库名称 | |||
| */ | |||
| @ApiModelProperty(name = "repository_name") | |||
| private String repositoryName; | |||
| } | |||
| @@ -0,0 +1,67 @@ | |||
| package com.ruoyi.platform.vo; | |||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||
| import io.swagger.annotations.ApiModel; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.Data; | |||
| import java.io.Serializable; | |||
| @ApiModel(description = "Git项目信息") | |||
| @Data | |||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||
| public class GitProjectVo implements Serializable { | |||
| @ApiModelProperty(value = "用户或组织ID", required = true) | |||
| private int userId; | |||
| @ApiModelProperty(value = "项目名称", required = true) | |||
| private String name; | |||
| @ApiModelProperty(value = "项目描述", required = false) | |||
| private String description; | |||
| @ApiModelProperty(value = "项目标识", required = true) | |||
| private String repositoryName; | |||
| // @ApiModelProperty(value = "项目分类ID", required = false) | |||
| // private int projectCategoryId; | |||
| // | |||
| // @ApiModelProperty(value = "项目语言ID", required = false) | |||
| // private int projectLanguageId; | |||
| // @ApiModelProperty(value = "项目忽略文件ID", required = false) | |||
| // private int ignoreId; | |||
| // @ApiModelProperty(value = "项目许可证ID", required = false) | |||
| // private int licenseId; | |||
| @ApiModelProperty(value = "项目是否为私有项目", required = false) | |||
| private boolean isPrivate; | |||
| // @ApiModelProperty(value = "是否为区块链激励项目", required = false) | |||
| // private boolean blockchain; | |||
| // | |||
| // @ApiModelProperty(value = "区块链激励金额总数", required = false) | |||
| // private int blockchainTokenAll; | |||
| // | |||
| // @Override | |||
| // public String toString() { | |||
| // return "GitProjectVo{" + | |||
| // "userId=" + userId + | |||
| // ", name='" + name + '\'' + | |||
| // ", description='" + description + '\'' + | |||
| // ", repositoryName='" + repositoryName + '\'' + | |||
| // ", projectCategoryId=" + projectCategoryId + | |||
| // ", projectLanguageId=" + projectLanguageId + | |||
| // ", ignoreId=" + ignoreId + | |||
| // ", licenseId=" + licenseId + | |||
| // ", isPrivate=" + isPrivate + | |||
| // ", blockchain=" + blockchain + | |||
| // ", blockchainTokenAll=" + blockchainTokenAll + | |||
| // '}'; | |||
| // } | |||
| } | |||
| @@ -57,13 +57,16 @@ public class ImageVo implements Serializable { | |||
| @ApiModelProperty(name = "status") | |||
| private String status; | |||
| @ApiModelProperty(value = "上传方式, 基于公网上传0,基于本地上传1") | |||
| @ApiModelProperty(name = "upload_type", value = "上传方式, 基于公网上传0,基于本地上传1") | |||
| private Integer uploadType; | |||
| @ApiModelProperty(value = "镜像上传路径") | |||
| private String path; | |||
| @ApiModelProperty(name = "dev_environment_id", value = "环境id") | |||
| private Integer devEnvironmentId; | |||
| // public Integer getId() { | |||
| // return id; | |||
| // } | |||
| @@ -147,7 +150,17 @@ public class ImageVo implements Serializable { | |||
| public String getPath() { | |||
| return path; | |||
| } | |||
| public void setPath(String path) { | |||
| this.path = path; | |||
| } | |||
| public Integer getDevEnvironmentId() { | |||
| return devEnvironmentId; | |||
| } | |||
| public void setDevEnvironmentId(Integer devEnvironmentId) { | |||
| this.devEnvironmentId = devEnvironmentId; | |||
| } | |||
| } | |||
| @@ -0,0 +1,43 @@ | |||
| package com.ruoyi.platform.vo; | |||
| import com.fasterxml.jackson.databind.PropertyNamingStrategy; | |||
| import com.fasterxml.jackson.databind.annotation.JsonNaming; | |||
| import io.swagger.annotations.ApiModelProperty; | |||
| import lombok.Data; | |||
| import org.apache.ibatis.annotations.MapKey; | |||
| import java.io.Serializable; | |||
| import java.util.List; | |||
| @JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) | |||
| @Data | |||
| public class NewDatasetVo implements Serializable { | |||
| @ApiModelProperty(name = "name") | |||
| private String name; | |||
| /** | |||
| * 数据集仓库名称 | |||
| */ | |||
| @ApiModelProperty(name = "identifier") | |||
| private String identifier; | |||
| @ApiModelProperty(name = "description") | |||
| private String description; | |||
| /** | |||
| * 是否公开1公开,0私有 | |||
| */ | |||
| @ApiModelProperty(name = "is_public") | |||
| private Boolean isPublic; | |||
| @ApiModelProperty(name = "data_type") | |||
| private String dataType; | |||
| @ApiModelProperty(name = "data_tag") | |||
| private String dataTag; | |||
| @ApiModelProperty(name = "time_ago") | |||
| private String timeAgo; | |||
| @ApiModelProperty(name = "repo_id") | |||
| private Integer repoId; | |||
| @ApiModelProperty(name = "visits") | |||
| private Integer visits; | |||
| @ApiModelProperty(name = "create_by") | |||
| private String createBy; | |||
| } | |||
| @@ -15,6 +15,10 @@ spring: | |||
| discovery: | |||
| # 服务注册地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| username: nacos | |||
| password: nacos | |||
| retry: | |||
| enabled: true | |||
| config: | |||
| # 配置中心地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| @@ -22,4 +26,9 @@ spring: | |||
| file-extension: yml | |||
| # 共享配置 | |||
| shared-configs: | |||
| - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| - data-id: management-platform-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| @@ -0,0 +1,115 @@ | |||
| <?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="com.ruoyi.platform.mapper.CodeConfigDao"> | |||
| <insert id="insert"> | |||
| insert into code_config(code_repo_name, code_repo_vis, git_url, git_branch, verify_mode, git_user_name, | |||
| git_password, ssh_key, create_by, create_time, update_by, update_time) | |||
| values (#{codeConfig.codeRepoName}, #{codeConfig.codeRepoVis}, #{codeConfig.gitUrl}, #{codeConfig.gitBranch}, | |||
| #{codeConfig.verifyMode}, #{codeConfig.gitUserName}, #{codeConfig.gitPassword}, | |||
| #{codeConfig.sshKey}, #{codeConfig.createBy}, #{codeConfig.createTime}, #{codeConfig.updateBy}, | |||
| #{codeConfig.updateTime}) | |||
| </insert> | |||
| <update id="update"> | |||
| update code_config | |||
| <set> | |||
| <if test="codeConfig.codeRepoName != null and codeConfig.codeRepoName != ''"> | |||
| code_repo_name = #{codeConfig.codeRepoName}, | |||
| </if> | |||
| <if test="codeConfig.codeRepoVis != null"> | |||
| code_repo_vis = #{codeConfig.codeRepoVis}, | |||
| </if> | |||
| <if test="codeConfig.gitUrl != null"> | |||
| git_url = #{codeConfig.gitUrl}, | |||
| </if> | |||
| <if test="codeConfig.gitBranch != null and codeConfig.gitBranch != ''"> | |||
| git_branch = #{codeConfig.gitBranch}, | |||
| </if> | |||
| verify_mode = #{codeConfig.verifyMode}, | |||
| git_user_name = #{codeConfig.gitUserName}, | |||
| git_password = #{codeConfig.gitPassword}, | |||
| ssh_key = #{codeConfig.sshKey}, | |||
| <if test="codeConfig.createBy != null and codeConfig.createBy != ''"> | |||
| create_by = #{codeConfig.createBy}, | |||
| </if> | |||
| <if test="codeConfig.createTime != null"> | |||
| create_time = #{codeConfig.createTime}, | |||
| </if> | |||
| <if test="codeConfig.updateBy != null and codeConfig.updateBy != ''"> | |||
| update_by = #{codeConfig.updateBy}, | |||
| </if> | |||
| <if test="codeConfig.state != null"> | |||
| state = #{codeConfig.state}, | |||
| </if> | |||
| update_time = sysdate() | |||
| </set> | |||
| where id = #{codeConfig.id} | |||
| </update> | |||
| <select id="count" resultType="java.lang.Long"> | |||
| select count(1) | |||
| from code_config | |||
| <include refid="common_condition"></include> | |||
| </select> | |||
| <select id="queryAllByLimit" resultType="com.ruoyi.platform.domain.CodeConfig"> | |||
| select * from code_config | |||
| <include refid="common_condition"></include> | |||
| limit #{pageable.offset}, #{pageable.pageSize} | |||
| </select> | |||
| <select id="queryById" resultType="com.ruoyi.platform.domain.CodeConfig"> | |||
| select * | |||
| from code_config | |||
| where id = #{id} | |||
| and state = 1 | |||
| </select> | |||
| <select id="queryByCodeRepoName" resultType="java.lang.Long"> | |||
| select id | |||
| from code_config | |||
| where code_repo_name = #{codeRepoName} | |||
| and state = 1 | |||
| </select> | |||
| <sql id="common_condition"> | |||
| <where> | |||
| state = 1 | |||
| <if test="codeConfig.id != null"> | |||
| and id = #{codeConfig.id} | |||
| </if> | |||
| <if test="codeConfig.codeRepoName != null and codeConfig.codeRepoName != ''"> | |||
| and code_repo_name LIKE CONCAT('%', #{codeConfig.codeRepoName}, '%') | |||
| </if> | |||
| <if test="codeConfig.codeRepoVis != null"> | |||
| and code_repo_vis = #{codeConfig.codeRepoVis} | |||
| </if> | |||
| <if test="codeConfig.gitUrl != null"> | |||
| and git_url = #{codeConfig.gitUrl} | |||
| </if> | |||
| <if test="codeConfig.gitBranch != null and codeConfig.gitBranch != ''"> | |||
| and git_branch = #{codeConfig.gitBranch} | |||
| </if> | |||
| <if test="codeConfig.verifyMode != null"> | |||
| and verify_mode = #{codeConfig.verifyMode} | |||
| </if> | |||
| <if test="codeConfig.gitUserName != null and codeConfig.gitUserName != ''"> | |||
| and git_user_name = #{codeConfig.gitUserName} | |||
| </if> | |||
| <if test="codeConfig.createBy != null and codeConfig.createBy != ''"> | |||
| and create_by = #{codeConfig.createBy} | |||
| </if> | |||
| <if test="codeConfig.createTime != null"> | |||
| and create_time = #{codeConfig.createTime} | |||
| </if> | |||
| <if test="codeConfig.updateBy != null and codeConfig.updateBy != ''"> | |||
| and update_by = #{codeConfig.updateBy} | |||
| </if> | |||
| <if test="codeConfig.updateTime != null"> | |||
| and update_time = #{codeConfig.updateTime} | |||
| </if> | |||
| </where> | |||
| </sql> | |||
| </mapper> | |||
| @@ -156,6 +156,10 @@ computing_resource = values(computing_resource)standard = values(standard)descri | |||
| where id = #{computingResource.id} | |||
| </update> | |||
| <update id="updateUsedStateByNode"> | |||
| update computing_resource set used_state = #{usedState} where node = #{node} | |||
| </update> | |||
| <!--通过主键删除--> | |||
| <delete id="deleteById"> | |||
| delete from computing_resource where id = #{id} | |||
| @@ -15,6 +15,7 @@ | |||
| <result property="updateBy" column="update_by" jdbcType="VARCHAR"/> | |||
| <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/> | |||
| <result property="state" column="state" jdbcType="INTEGER"/> | |||
| <result property="hostIp" column="host_ip" jdbcType="VARCHAR"/> | |||
| </resultMap> | |||
| <!--根据模型id返回版本列表--> | |||
| @@ -15,6 +15,10 @@ spring: | |||
| discovery: | |||
| # 服务注册地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| username: nacos | |||
| password: nacos | |||
| retry: | |||
| enabled: true | |||
| config: | |||
| # 配置中心地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| @@ -22,4 +26,6 @@ spring: | |||
| file-extension: yml | |||
| # 共享配置 | |||
| shared-configs: | |||
| - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| @@ -15,6 +15,10 @@ spring: | |||
| discovery: | |||
| # 服务注册地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| username: nacos | |||
| password: nacos | |||
| retry: | |||
| enabled: true | |||
| config: | |||
| # 配置中心地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| @@ -22,4 +26,6 @@ spring: | |||
| file-extension: yml | |||
| # 共享配置 | |||
| shared-configs: | |||
| - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| @@ -65,7 +65,7 @@ | |||
| <groupId>com.mysql</groupId> | |||
| <artifactId>mysql-connector-j</artifactId> | |||
| </dependency> | |||
| <!-- RuoYi Common Log --> | |||
| <dependency> | |||
| <groupId>com.ruoyi</groupId> | |||
| @@ -77,7 +77,13 @@ | |||
| <groupId>com.ruoyi</groupId> | |||
| <artifactId>ruoyi-common-swagger</artifactId> | |||
| </dependency> | |||
| <!-- RuoYi Common DataSource --> | |||
| <dependency> | |||
| <groupId>com.ruoyi</groupId> | |||
| <artifactId>ruoyi-common-datasource</artifactId> | |||
| </dependency> | |||
| </dependencies> | |||
| <build> | |||
| @@ -3,7 +3,7 @@ server: | |||
| port: 9203 | |||
| # Spring | |||
| spring: | |||
| spring: | |||
| application: | |||
| # 应用名称 | |||
| name: ruoyi-job | |||
| @@ -15,6 +15,10 @@ spring: | |||
| discovery: | |||
| # 服务注册地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| username: nacos | |||
| password: nacos | |||
| retry: | |||
| enabled: true | |||
| config: | |||
| # 配置中心地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| @@ -22,4 +26,9 @@ spring: | |||
| file-extension: yml | |||
| # 共享配置 | |||
| shared-configs: | |||
| - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| - data-id: ${spring.application.name}-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| @@ -1,22 +1,5 @@ | |||
| package com.ruoyi.system.controller; | |||
| import java.io.IOException; | |||
| import java.util.List; | |||
| import java.util.Set; | |||
| import java.util.stream.Collectors; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| import org.apache.commons.lang3.ArrayUtils; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.DeleteMapping; | |||
| import org.springframework.web.bind.annotation.GetMapping; | |||
| import org.springframework.web.bind.annotation.PathVariable; | |||
| import org.springframework.web.bind.annotation.PostMapping; | |||
| import org.springframework.web.bind.annotation.PutMapping; | |||
| import org.springframework.web.bind.annotation.RequestBody; | |||
| import org.springframework.web.bind.annotation.RequestMapping; | |||
| import org.springframework.web.bind.annotation.RestController; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import com.ruoyi.common.core.domain.R; | |||
| import com.ruoyi.common.core.utils.StringUtils; | |||
| import com.ruoyi.common.core.utils.poi.ExcelUtil; | |||
| @@ -32,22 +15,27 @@ import com.ruoyi.system.api.domain.SysDept; | |||
| import com.ruoyi.system.api.domain.SysRole; | |||
| import com.ruoyi.system.api.domain.SysUser; | |||
| import com.ruoyi.system.api.model.LoginUser; | |||
| import com.ruoyi.system.service.ISysConfigService; | |||
| import com.ruoyi.system.service.ISysDeptService; | |||
| import com.ruoyi.system.service.ISysPermissionService; | |||
| import com.ruoyi.system.service.ISysPostService; | |||
| import com.ruoyi.system.service.ISysRoleService; | |||
| import com.ruoyi.system.service.ISysUserService; | |||
| import com.ruoyi.system.service.*; | |||
| import org.apache.commons.lang3.ArrayUtils; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.validation.annotation.Validated; | |||
| import org.springframework.web.bind.annotation.*; | |||
| import org.springframework.web.multipart.MultipartFile; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| import java.io.IOException; | |||
| import java.util.List; | |||
| import java.util.Set; | |||
| import java.util.stream.Collectors; | |||
| /** | |||
| * 用户信息 | |||
| * | |||
| * | |||
| * @author ruoyi | |||
| */ | |||
| @RestController | |||
| @RequestMapping("/user") | |||
| public class SysUserController extends BaseController | |||
| { | |||
| public class SysUserController extends BaseController { | |||
| @Autowired | |||
| private ISysUserService userService; | |||
| @@ -71,8 +59,7 @@ public class SysUserController extends BaseController | |||
| */ | |||
| @RequiresPermissions("system:user:list") | |||
| @GetMapping("/list") | |||
| public TableDataInfo list(SysUser user) | |||
| { | |||
| public TableDataInfo list(SysUser user) { | |||
| startPage(); | |||
| List<SysUser> list = userService.selectUserList(user); | |||
| return getDataTable(list); | |||
| @@ -81,8 +68,7 @@ public class SysUserController extends BaseController | |||
| @Log(title = "用户管理", businessType = BusinessType.EXPORT) | |||
| @RequiresPermissions("system:user:export") | |||
| @PostMapping("/export") | |||
| public void export(HttpServletResponse response, SysUser user) | |||
| { | |||
| public void export(HttpServletResponse response, SysUser user) { | |||
| List<SysUser> list = userService.selectUserList(user); | |||
| ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class); | |||
| util.exportExcel(response, list, "用户数据"); | |||
| @@ -91,8 +77,7 @@ public class SysUserController extends BaseController | |||
| @Log(title = "用户管理", businessType = BusinessType.IMPORT) | |||
| @RequiresPermissions("system:user:import") | |||
| @PostMapping("/importData") | |||
| public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception | |||
| { | |||
| public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception { | |||
| ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class); | |||
| List<SysUser> userList = util.importExcel(file.getInputStream()); | |||
| String operName = SecurityUtils.getUsername(); | |||
| @@ -101,8 +86,7 @@ public class SysUserController extends BaseController | |||
| } | |||
| @PostMapping("/importTemplate") | |||
| public void importTemplate(HttpServletResponse response) throws IOException | |||
| { | |||
| public void importTemplate(HttpServletResponse response) throws IOException { | |||
| ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class); | |||
| util.importTemplateExcel(response, "用户数据"); | |||
| } | |||
| @@ -112,11 +96,9 @@ public class SysUserController extends BaseController | |||
| */ | |||
| @InnerAuth | |||
| @GetMapping("/info/{username}") | |||
| public R<LoginUser> info(@PathVariable("username") String username) | |||
| { | |||
| public R<LoginUser> info(@PathVariable("username") String username) { | |||
| SysUser sysUser = userService.selectUserByUserName(username); | |||
| if (StringUtils.isNull(sysUser)) | |||
| { | |||
| if (StringUtils.isNull(sysUser)) { | |||
| return R.fail("用户名或密码错误"); | |||
| } | |||
| // 角色集合 | |||
| @@ -135,15 +117,12 @@ public class SysUserController extends BaseController | |||
| */ | |||
| @InnerAuth | |||
| @PostMapping("/register") | |||
| public R<Boolean> register(@RequestBody SysUser sysUser) | |||
| { | |||
| public R<Boolean> register(@RequestBody SysUser sysUser) { | |||
| String username = sysUser.getUserName(); | |||
| if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) | |||
| { | |||
| if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) { | |||
| return R.fail("当前系统没有开启注册功能!"); | |||
| } | |||
| if (!userService.checkUserNameUnique(sysUser)) | |||
| { | |||
| if (!userService.checkUserNameUnique(sysUser)) { | |||
| return R.fail("保存用户'" + username + "'失败,注册账号已存在"); | |||
| } | |||
| return R.ok(userService.registerUser(sysUser)); | |||
| @@ -151,12 +130,11 @@ public class SysUserController extends BaseController | |||
| /** | |||
| * 获取用户信息 | |||
| * | |||
| * | |||
| * @return 用户信息 | |||
| */ | |||
| @GetMapping("getInfo") | |||
| public AjaxResult getInfo() | |||
| { | |||
| public AjaxResult getInfo() { | |||
| SysUser user = userService.selectUserById(SecurityUtils.getUserId()); | |||
| // 角色集合 | |||
| Set<String> roles = permissionService.getRolePermission(user); | |||
| @@ -173,16 +151,15 @@ public class SysUserController extends BaseController | |||
| * 根据用户编号获取详细信息 | |||
| */ | |||
| @RequiresPermissions("system:user:query") | |||
| @GetMapping(value = { "/", "/{userId}" }) | |||
| public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) | |||
| { | |||
| @GetMapping(value = {"/", "/{userId}"}) | |||
| public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) { | |||
| userService.checkUserDataScope(userId); | |||
| AjaxResult ajax = AjaxResult.success(); | |||
| List<SysRole> roles = roleService.selectRoleAll(); | |||
| ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); | |||
| ajax.put("roles", roles); | |||
| // ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList())); | |||
| ajax.put("posts", postService.selectPostAll()); | |||
| if (StringUtils.isNotNull(userId)) | |||
| { | |||
| if (StringUtils.isNotNull(userId)) { | |||
| SysUser sysUser = userService.selectUserById(userId); | |||
| ajax.put(AjaxResult.DATA_TAG, sysUser); | |||
| ajax.put("postIds", postService.selectPostListByUserId(userId)); | |||
| @@ -197,22 +174,19 @@ public class SysUserController extends BaseController | |||
| @RequiresPermissions("system:user:add") | |||
| @Log(title = "用户管理", businessType = BusinessType.INSERT) | |||
| @PostMapping | |||
| public AjaxResult add(@Validated @RequestBody SysUser user) | |||
| { | |||
| if (!userService.checkUserNameUnique(user)) | |||
| { | |||
| public AjaxResult add(@Validated @RequestBody SysUser user) { | |||
| if (!userService.checkUserNameUnique(user)) { | |||
| return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在"); | |||
| } | |||
| else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) | |||
| { | |||
| } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { | |||
| return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在"); | |||
| } | |||
| else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) | |||
| { | |||
| } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { | |||
| return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在"); | |||
| } else if (StringUtils.isNotEmpty(user.getGitLinkUsername()) && !userService.checktGitLinkUsernameUnique(user)) { | |||
| return error("新增用户'" + user.getUserName() + "'失败,gitLink用户名已存在"); | |||
| } | |||
| user.setCreateBy(SecurityUtils.getUsername()); | |||
| user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); | |||
| user.setGitLinkPassword(SecurityUtils.encryptPassword(user.getGitLinkPassword())); | |||
| return toAjax(userService.insertUser(user)); | |||
| } | |||
| @@ -222,23 +196,25 @@ public class SysUserController extends BaseController | |||
| @RequiresPermissions("system:user:edit") | |||
| @Log(title = "用户管理", businessType = BusinessType.UPDATE) | |||
| @PutMapping | |||
| public AjaxResult edit(@Validated @RequestBody SysUser user) | |||
| { | |||
| public AjaxResult edit(@Validated @RequestBody SysUser user) { | |||
| userService.checkUserAllowed(user); | |||
| userService.checkUserDataScope(user.getUserId()); | |||
| if (!userService.checkUserNameUnique(user)) | |||
| { | |||
| if (!userService.checkUserNameUnique(user)) { | |||
| return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在"); | |||
| } | |||
| else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) | |||
| { | |||
| } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) { | |||
| return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在"); | |||
| } | |||
| else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) | |||
| { | |||
| } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) { | |||
| return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在"); | |||
| } else if (StringUtils.isNotEmpty(user.getGitLinkUsername()) && !userService.checktGitLinkUsernameUnique(user)) { | |||
| return error("新增用户'" + user.getUserName() + "'失败,gitLink用户名已存在"); | |||
| } | |||
| user.setUpdateBy(SecurityUtils.getUsername()); | |||
| if(StringUtils.isNotEmpty(user.getPassword())){ | |||
| user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); | |||
| } | |||
| if(StringUtils.isNotEmpty(user.getGitLinkPassword())){ | |||
| user.setGitLinkPassword(SecurityUtils.encryptPassword(user.getGitLinkPassword())); | |||
| } | |||
| return toAjax(userService.updateUser(user)); | |||
| } | |||
| @@ -248,10 +224,8 @@ public class SysUserController extends BaseController | |||
| @RequiresPermissions("system:user:remove") | |||
| @Log(title = "用户管理", businessType = BusinessType.DELETE) | |||
| @DeleteMapping("/{userIds}") | |||
| public AjaxResult remove(@PathVariable Long[] userIds) | |||
| { | |||
| if (ArrayUtils.contains(userIds, SecurityUtils.getUserId())) | |||
| { | |||
| public AjaxResult remove(@PathVariable Long[] userIds) { | |||
| if (ArrayUtils.contains(userIds, SecurityUtils.getUserId())) { | |||
| return error("当前用户不能删除"); | |||
| } | |||
| return toAjax(userService.deleteUserByIds(userIds)); | |||
| @@ -263,8 +237,7 @@ public class SysUserController extends BaseController | |||
| @RequiresPermissions("system:user:edit") | |||
| @Log(title = "用户管理", businessType = BusinessType.UPDATE) | |||
| @PutMapping("/resetPwd") | |||
| public AjaxResult resetPwd(@RequestBody SysUser user) | |||
| { | |||
| public AjaxResult resetPwd(@RequestBody SysUser user) { | |||
| userService.checkUserAllowed(user); | |||
| userService.checkUserDataScope(user.getUserId()); | |||
| user.setPassword(SecurityUtils.encryptPassword(user.getPassword())); | |||
| @@ -278,8 +251,7 @@ public class SysUserController extends BaseController | |||
| @RequiresPermissions("system:user:edit") | |||
| @Log(title = "用户管理", businessType = BusinessType.UPDATE) | |||
| @PutMapping("/changeStatus") | |||
| public AjaxResult changeStatus(@RequestBody SysUser user) | |||
| { | |||
| public AjaxResult changeStatus(@RequestBody SysUser user) { | |||
| userService.checkUserAllowed(user); | |||
| userService.checkUserDataScope(user.getUserId()); | |||
| user.setUpdateBy(SecurityUtils.getUsername()); | |||
| @@ -291,8 +263,7 @@ public class SysUserController extends BaseController | |||
| */ | |||
| @RequiresPermissions("system:user:query") | |||
| @GetMapping("/authRole/{userId}") | |||
| public AjaxResult authRole(@PathVariable("userId") Long userId) | |||
| { | |||
| public AjaxResult authRole(@PathVariable("userId") Long userId) { | |||
| AjaxResult ajax = AjaxResult.success(); | |||
| SysUser user = userService.selectUserById(userId); | |||
| List<SysRole> roles = roleService.selectRolesByUserId(userId); | |||
| @@ -307,8 +278,7 @@ public class SysUserController extends BaseController | |||
| @RequiresPermissions("system:user:edit") | |||
| @Log(title = "用户管理", businessType = BusinessType.GRANT) | |||
| @PutMapping("/authRole") | |||
| public AjaxResult insertAuthRole(Long userId, Long[] roleIds) | |||
| { | |||
| public AjaxResult insertAuthRole(Long userId, Long[] roleIds) { | |||
| userService.checkUserDataScope(userId); | |||
| userService.insertUserAuth(userId, roleIds); | |||
| return success(); | |||
| @@ -319,8 +289,7 @@ public class SysUserController extends BaseController | |||
| */ | |||
| @RequiresPermissions("system:user:list") | |||
| @GetMapping("/deptTree") | |||
| public AjaxResult deptTree(SysDept dept) | |||
| { | |||
| public AjaxResult deptTree(SysDept dept) { | |||
| return success(deptService.selectDeptTreeList(dept)); | |||
| } | |||
| } | |||
| @@ -124,4 +124,6 @@ public interface SysUserMapper | |||
| * @return 结果 | |||
| */ | |||
| public SysUser checkEmailUnique(String email); | |||
| public SysUser checktGitLinkUsernameUnique(String gitLinkUsername); | |||
| } | |||
| @@ -90,6 +90,8 @@ public interface ISysUserService | |||
| */ | |||
| public boolean checkEmailUnique(SysUser user); | |||
| public boolean checktGitLinkUsernameUnique(SysUser user); | |||
| /** | |||
| * 校验用户是否允许操作 | |||
| * | |||
| @@ -212,6 +212,17 @@ public class SysUserServiceImpl implements ISysUserService | |||
| return UserConstants.UNIQUE; | |||
| } | |||
| @Override | |||
| public boolean checktGitLinkUsernameUnique(SysUser user) { | |||
| Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); | |||
| SysUser info = userMapper.checktGitLinkUsernameUnique(user.getGitLinkUsername()); | |||
| if(StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) | |||
| { | |||
| return UserConstants.NOT_UNIQUE; | |||
| } | |||
| return UserConstants.UNIQUE; | |||
| } | |||
| /** | |||
| * 校验用户是否允许操作 | |||
| * | |||
| @@ -15,6 +15,10 @@ spring: | |||
| discovery: | |||
| # 服务注册地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| username: nacos | |||
| password: nacos | |||
| retry: | |||
| enabled: true | |||
| config: | |||
| # 配置中心地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| @@ -22,4 +26,6 @@ spring: | |||
| file-extension: yml | |||
| # 共享配置 | |||
| shared-configs: | |||
| - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||
| @@ -1,221 +1,286 @@ | |||
| <?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"> | |||
| PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |||
| "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |||
| <mapper namespace="com.ruoyi.system.mapper.SysUserMapper"> | |||
| <resultMap type="SysUser" id="SysUserResult"> | |||
| <id property="userId" column="user_id" /> | |||
| <result property="deptId" column="dept_id" /> | |||
| <result property="userName" column="user_name" /> | |||
| <result property="nickName" column="nick_name" /> | |||
| <result property="email" column="email" /> | |||
| <result property="phonenumber" column="phonenumber" /> | |||
| <result property="sex" column="sex" /> | |||
| <result property="avatar" column="avatar" /> | |||
| <result property="password" column="password" /> | |||
| <result property="status" column="status" /> | |||
| <result property="delFlag" column="del_flag" /> | |||
| <result property="loginIp" column="login_ip" /> | |||
| <result property="loginDate" column="login_date" /> | |||
| <result property="createBy" column="create_by" /> | |||
| <result property="createTime" column="create_time" /> | |||
| <result property="updateBy" column="update_by" /> | |||
| <result property="updateTime" column="update_time" /> | |||
| <result property="remark" column="remark" /> | |||
| <association property="dept" javaType="SysDept" resultMap="deptResult" /> | |||
| <collection property="roles" javaType="java.util.List" resultMap="RoleResult" /> | |||
| <id property="userId" column="user_id"/> | |||
| <result property="deptId" column="dept_id"/> | |||
| <result property="userName" column="user_name"/> | |||
| <result property="nickName" column="nick_name"/> | |||
| <result property="email" column="email"/> | |||
| <result property="phonenumber" column="phonenumber"/> | |||
| <result property="sex" column="sex"/> | |||
| <result property="avatar" column="avatar"/> | |||
| <result property="password" column="password"/> | |||
| <result property="status" column="status"/> | |||
| <result property="delFlag" column="del_flag"/> | |||
| <result property="loginIp" column="login_ip"/> | |||
| <result property="loginDate" column="login_date"/> | |||
| <result property="createBy" column="create_by"/> | |||
| <result property="createTime" column="create_time"/> | |||
| <result property="updateBy" column="update_by"/> | |||
| <result property="updateTime" column="update_time"/> | |||
| <result property="remark" column="remark"/> | |||
| <result property="gitLinkUsername" column="git_link_username"/> | |||
| <result property="gitLinkPassword" column="git_link_password"/> | |||
| <association property="dept" javaType="SysDept" resultMap="deptResult"/> | |||
| <collection property="roles" javaType="java.util.List" resultMap="RoleResult"/> | |||
| </resultMap> | |||
| <resultMap id="deptResult" type="SysDept"> | |||
| <id property="deptId" column="dept_id" /> | |||
| <result property="parentId" column="parent_id" /> | |||
| <result property="deptName" column="dept_name" /> | |||
| <result property="ancestors" column="ancestors" /> | |||
| <result property="orderNum" column="order_num" /> | |||
| <result property="leader" column="leader" /> | |||
| <result property="status" column="dept_status" /> | |||
| <id property="deptId" column="dept_id"/> | |||
| <result property="parentId" column="parent_id"/> | |||
| <result property="deptName" column="dept_name"/> | |||
| <result property="ancestors" column="ancestors"/> | |||
| <result property="orderNum" column="order_num"/> | |||
| <result property="leader" column="leader"/> | |||
| <result property="status" column="dept_status"/> | |||
| </resultMap> | |||
| <resultMap id="RoleResult" type="SysRole"> | |||
| <id property="roleId" column="role_id" /> | |||
| <result property="roleName" column="role_name" /> | |||
| <result property="roleKey" column="role_key" /> | |||
| <result property="roleSort" column="role_sort" /> | |||
| <result property="dataScope" column="data_scope" /> | |||
| <result property="status" column="role_status" /> | |||
| <id property="roleId" column="role_id"/> | |||
| <result property="roleName" column="role_name"/> | |||
| <result property="roleKey" column="role_key"/> | |||
| <result property="roleSort" column="role_sort"/> | |||
| <result property="dataScope" column="data_scope"/> | |||
| <result property="status" column="role_status"/> | |||
| </resultMap> | |||
| <sql id="selectUserVo"> | |||
| select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, | |||
| d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status, | |||
| r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status | |||
| <sql id="selectUserVo"> | |||
| select u.user_id, | |||
| u.dept_id, | |||
| u.user_name, | |||
| u.nick_name, | |||
| u.email, | |||
| u.avatar, | |||
| u.phonenumber, | |||
| u.password, | |||
| u.git_link_username, | |||
| u.git_link_password, | |||
| u.sex, | |||
| u.status, | |||
| u.del_flag, | |||
| u.login_ip, | |||
| u.login_date, | |||
| u.create_by, | |||
| u.create_time, | |||
| u.remark, | |||
| d.dept_id, | |||
| d.parent_id, | |||
| d.ancestors, | |||
| d.dept_name, | |||
| d.order_num, | |||
| d.leader, | |||
| d.status as dept_status, | |||
| r.role_id, | |||
| r.role_name, | |||
| r.role_key, | |||
| r.role_sort, | |||
| r.data_scope, | |||
| r.status as role_status | |||
| from sys_user u | |||
| left join sys_dept d on u.dept_id = d.dept_id | |||
| left join sys_user_role ur on u.user_id = ur.user_id | |||
| left join sys_role r on r.role_id = ur.role_id | |||
| left join sys_dept d on u.dept_id = d.dept_id | |||
| left join sys_user_role ur on u.user_id = ur.user_id | |||
| left join sys_role r on r.role_id = ur.role_id | |||
| </sql> | |||
| <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult"> | |||
| select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u | |||
| left join sys_dept d on u.dept_id = d.dept_id | |||
| where u.del_flag = '0' | |||
| <if test="userId != null and userId != 0"> | |||
| AND u.user_id = #{userId} | |||
| </if> | |||
| <if test="userName != null and userName != ''"> | |||
| AND u.user_name like concat('%', #{userName}, '%') | |||
| </if> | |||
| <if test="status != null and status != ''"> | |||
| AND u.status = #{status} | |||
| </if> | |||
| <if test="phonenumber != null and phonenumber != ''"> | |||
| AND u.phonenumber like concat('%', #{phonenumber}, '%') | |||
| </if> | |||
| <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> | |||
| AND date_format(u.create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') | |||
| </if> | |||
| <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> | |||
| AND date_format(u.create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') | |||
| </if> | |||
| <if test="deptId != null and deptId != 0"> | |||
| AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) )) | |||
| </if> | |||
| <!-- 数据范围过滤 --> | |||
| ${params.dataScope} | |||
| </select> | |||
| <select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult"> | |||
| select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time | |||
| from sys_user u | |||
| left join sys_dept d on u.dept_id = d.dept_id | |||
| left join sys_user_role ur on u.user_id = ur.user_id | |||
| left join sys_role r on r.role_id = ur.role_id | |||
| where u.del_flag = '0' and r.role_id = #{roleId} | |||
| <if test="userName != null and userName != ''"> | |||
| AND u.user_name like concat('%', #{userName}, '%') | |||
| </if> | |||
| <if test="phonenumber != null and phonenumber != ''"> | |||
| AND u.phonenumber like concat('%', #{phonenumber}, '%') | |||
| </if> | |||
| <!-- 数据范围过滤 --> | |||
| ${params.dataScope} | |||
| </select> | |||
| <select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult"> | |||
| select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time | |||
| from sys_user u | |||
| left join sys_dept d on u.dept_id = d.dept_id | |||
| left join sys_user_role ur on u.user_id = ur.user_id | |||
| left join sys_role r on r.role_id = ur.role_id | |||
| where u.del_flag = '0' and (r.role_id != #{roleId} or r.role_id IS NULL) | |||
| and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = #{roleId}) | |||
| <if test="userName != null and userName != ''"> | |||
| AND u.user_name like concat('%', #{userName}, '%') | |||
| </if> | |||
| <if test="phonenumber != null and phonenumber != ''"> | |||
| AND u.phonenumber like concat('%', #{phonenumber}, '%') | |||
| </if> | |||
| <!-- 数据范围过滤 --> | |||
| ${params.dataScope} | |||
| </select> | |||
| <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult"> | |||
| <include refid="selectUserVo"/> | |||
| where u.user_name = #{userName} and u.del_flag = '0' | |||
| </select> | |||
| <select id="selectUserById" parameterType="Long" resultMap="SysUserResult"> | |||
| <include refid="selectUserVo"/> | |||
| where u.user_id = #{userId} | |||
| </select> | |||
| <select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult"> | |||
| select user_id, user_name from sys_user where user_name = #{userName} and del_flag = '0' limit 1 | |||
| </select> | |||
| <select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult"> | |||
| select user_id, phonenumber from sys_user where phonenumber = #{phonenumber} and del_flag = '0' limit 1 | |||
| </select> | |||
| <select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult"> | |||
| select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1 | |||
| </select> | |||
| <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId"> | |||
| insert into sys_user( | |||
| <if test="userId != null and userId != 0">user_id,</if> | |||
| <if test="deptId != null and deptId != 0">dept_id,</if> | |||
| <if test="userName != null and userName != ''">user_name,</if> | |||
| <if test="nickName != null and nickName != ''">nick_name,</if> | |||
| <if test="email != null and email != ''">email,</if> | |||
| <if test="avatar != null and avatar != ''">avatar,</if> | |||
| <if test="phonenumber != null and phonenumber != ''">phonenumber,</if> | |||
| <if test="sex != null and sex != ''">sex,</if> | |||
| <if test="password != null and password != ''">password,</if> | |||
| <if test="status != null and status != ''">status,</if> | |||
| <if test="createBy != null and createBy != ''">create_by,</if> | |||
| <if test="remark != null and remark != ''">remark,</if> | |||
| create_time | |||
| )values( | |||
| <if test="userId != null and userId != ''">#{userId},</if> | |||
| <if test="deptId != null and deptId != ''">#{deptId},</if> | |||
| <if test="userName != null and userName != ''">#{userName},</if> | |||
| <if test="nickName != null and nickName != ''">#{nickName},</if> | |||
| <if test="email != null and email != ''">#{email},</if> | |||
| <if test="avatar != null and avatar != ''">#{avatar},</if> | |||
| <if test="phonenumber != null and phonenumber != ''">#{phonenumber},</if> | |||
| <if test="sex != null and sex != ''">#{sex},</if> | |||
| <if test="password != null and password != ''">#{password},</if> | |||
| <if test="status != null and status != ''">#{status},</if> | |||
| <if test="createBy != null and createBy != ''">#{createBy},</if> | |||
| <if test="remark != null and remark != ''">#{remark},</if> | |||
| sysdate() | |||
| ) | |||
| </insert> | |||
| <update id="updateUser" parameterType="SysUser"> | |||
| update sys_user | |||
| <set> | |||
| <if test="deptId != null and deptId != 0">dept_id = #{deptId},</if> | |||
| <if test="userName != null and userName != ''">user_name = #{userName},</if> | |||
| <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if> | |||
| <if test="email != null ">email = #{email},</if> | |||
| <if test="phonenumber != null ">phonenumber = #{phonenumber},</if> | |||
| <if test="sex != null and sex != ''">sex = #{sex},</if> | |||
| <if test="avatar != null and avatar != ''">avatar = #{avatar},</if> | |||
| <if test="password != null and password != ''">password = #{password},</if> | |||
| <if test="status != null and status != ''">status = #{status},</if> | |||
| <if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if> | |||
| <if test="loginDate != null">login_date = #{loginDate},</if> | |||
| <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> | |||
| <if test="remark != null">remark = #{remark},</if> | |||
| update_time = sysdate() | |||
| </set> | |||
| where user_id = #{userId} | |||
| </update> | |||
| <update id="updateUserStatus" parameterType="SysUser"> | |||
| update sys_user set status = #{status} where user_id = #{userId} | |||
| </update> | |||
| <update id="updateUserAvatar" parameterType="SysUser"> | |||
| update sys_user set avatar = #{avatar} where user_name = #{userName} | |||
| </update> | |||
| <update id="resetUserPwd" parameterType="SysUser"> | |||
| update sys_user set password = #{password} where user_name = #{userName} | |||
| </update> | |||
| <delete id="deleteUserById" parameterType="Long"> | |||
| update sys_user set del_flag = '2' where user_id = #{userId} | |||
| </delete> | |||
| <delete id="deleteUserByIds" parameterType="Long"> | |||
| update sys_user set del_flag = '2' where user_id in | |||
| <foreach collection="array" item="userId" open="(" separator="," close=")"> | |||
| #{userId} | |||
| </foreach> | |||
| </delete> | |||
| select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, | |||
| u.git_link_username, | |||
| u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader | |||
| from sys_user u | |||
| left join sys_dept d on u.dept_id = d.dept_id | |||
| where u.del_flag = '0' | |||
| <if test="userId != null and userId != 0"> | |||
| AND u.user_id = #{userId} | |||
| </if> | |||
| <if test="userName != null and userName != ''"> | |||
| AND u.user_name like concat('%', #{userName}, '%') | |||
| </if> | |||
| <if test="status != null and status != ''"> | |||
| AND u.status = #{status} | |||
| </if> | |||
| <if test="phonenumber != null and phonenumber != ''"> | |||
| AND u.phonenumber like concat('%', #{phonenumber}, '%') | |||
| </if> | |||
| <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> | |||
| AND date_format(u.create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') | |||
| </if> | |||
| <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> | |||
| AND date_format(u.create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') | |||
| </if> | |||
| <if test="deptId != null and deptId != 0"> | |||
| AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, | |||
| ancestors) )) | |||
| </if> | |||
| <!-- 数据范围过滤 --> | |||
| ${params.dataScope} | |||
| </select> | |||
| <select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult"> | |||
| select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time, u.git_link_username | |||
| from sys_user u | |||
| left join sys_dept d on u.dept_id = d.dept_id | |||
| left join sys_user_role ur on u.user_id = ur.user_id | |||
| left join sys_role r on r.role_id = ur.role_id | |||
| where u.del_flag = '0' and r.role_id = #{roleId} | |||
| <if test="userName != null and userName != ''"> | |||
| AND u.user_name like concat('%', #{userName}, '%') | |||
| </if> | |||
| <if test="phonenumber != null and phonenumber != ''"> | |||
| AND u.phonenumber like concat('%', #{phonenumber}, '%') | |||
| </if> | |||
| <!-- 数据范围过滤 --> | |||
| ${params.dataScope} | |||
| </select> | |||
| <select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult"> | |||
| select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time ,u.git_link_username | |||
| from sys_user u | |||
| left join sys_dept d on u.dept_id = d.dept_id | |||
| left join sys_user_role ur on u.user_id = ur.user_id | |||
| left join sys_role r on r.role_id = ur.role_id | |||
| where u.del_flag = '0' and (r.role_id != #{roleId} or r.role_id IS NULL) | |||
| and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and | |||
| ur.role_id = #{roleId}) | |||
| <if test="userName != null and userName != ''"> | |||
| AND u.user_name like concat('%', #{userName}, '%') | |||
| </if> | |||
| <if test="phonenumber != null and phonenumber != ''"> | |||
| AND u.phonenumber like concat('%', #{phonenumber}, '%') | |||
| </if> | |||
| <!-- 数据范围过滤 --> | |||
| ${params.dataScope} | |||
| </select> | |||
| <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult"> | |||
| <include refid="selectUserVo"/> | |||
| where u.user_name = #{userName} and u.del_flag = '0' | |||
| </select> | |||
| <select id="selectUserById" parameterType="Long" resultMap="SysUserResult"> | |||
| <include refid="selectUserVo"/> | |||
| where u.user_id = #{userId} | |||
| </select> | |||
| <select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult"> | |||
| select user_id, user_name | |||
| from sys_user | |||
| where user_name = #{userName} | |||
| and del_flag = '0' limit 1 | |||
| </select> | |||
| <select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult"> | |||
| select user_id, phonenumber | |||
| from sys_user | |||
| where phonenumber = #{phonenumber} | |||
| and del_flag = '0' limit 1 | |||
| </select> | |||
| <select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult"> | |||
| select user_id, email | |||
| from sys_user | |||
| where email = #{email} | |||
| and del_flag = '0' limit 1 | |||
| </select> | |||
| <select id="checktGitLinkUsernameUnique" resultType="com.ruoyi.system.api.domain.SysUser"> | |||
| select user_id, git_link_username | |||
| from sys_user | |||
| where git_link_username = #{gitLinkUsername} | |||
| and del_flag = '0' limit 1 | |||
| </select> | |||
| <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId"> | |||
| insert into sys_user( | |||
| <if test="userId != null and userId != 0">user_id,</if> | |||
| <if test="deptId != null and deptId != 0">dept_id,</if> | |||
| <if test="userName != null and userName != ''">user_name,</if> | |||
| <if test="nickName != null and nickName != ''">nick_name,</if> | |||
| <if test="email != null and email != ''">email,</if> | |||
| <if test="avatar != null and avatar != ''">avatar,</if> | |||
| <if test="phonenumber != null and phonenumber != ''">phonenumber,</if> | |||
| <if test="sex != null and sex != ''">sex,</if> | |||
| <if test="password != null and password != ''">password,</if> | |||
| <if test="status != null and status != ''">status,</if> | |||
| <if test="createBy != null and createBy != ''">create_by,</if> | |||
| <if test="remark != null and remark != ''">remark,</if> | |||
| <if test="remark != null and remark != ''">git_link_username,</if> | |||
| <if test="remark != null and remark != ''">git_link_password,</if> | |||
| create_time | |||
| )values( | |||
| <if test="userId != null and userId != ''">#{userId},</if> | |||
| <if test="deptId != null and deptId != ''">#{deptId},</if> | |||
| <if test="userName != null and userName != ''">#{userName},</if> | |||
| <if test="nickName != null and nickName != ''">#{nickName},</if> | |||
| <if test="email != null and email != ''">#{email},</if> | |||
| <if test="avatar != null and avatar != ''">#{avatar},</if> | |||
| <if test="phonenumber != null and phonenumber != ''">#{phonenumber},</if> | |||
| <if test="sex != null and sex != ''">#{sex},</if> | |||
| <if test="password != null and password != ''">#{password},</if> | |||
| <if test="status != null and status != ''">#{status},</if> | |||
| <if test="createBy != null and createBy != ''">#{createBy},</if> | |||
| <if test="remark != null and remark != ''">#{remark},</if> | |||
| <if test="gitLinkUsername != null and gitLinkUsername != ''">#{gitLinkUsername},</if> | |||
| <if test="gitLinkPassword != null and gitLinkPassword != ''">#{gitLinkPassword},</if> | |||
| sysdate() | |||
| ) | |||
| </insert> | |||
| <update id="updateUser" parameterType="SysUser"> | |||
| update sys_user | |||
| <set> | |||
| <if test="deptId != null and deptId != 0">dept_id = #{deptId},</if> | |||
| <if test="userName != null and userName != ''">user_name = #{userName},</if> | |||
| <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if> | |||
| <if test="email != null ">email = #{email},</if> | |||
| <if test="phonenumber != null ">phonenumber = #{phonenumber},</if> | |||
| <if test="sex != null and sex != ''">sex = #{sex},</if> | |||
| <if test="avatar != null and avatar != ''">avatar = #{avatar},</if> | |||
| <if test="password != null and password != ''">password = #{password},</if> | |||
| <if test="status != null and status != ''">status = #{status},</if> | |||
| <if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if> | |||
| <if test="loginDate != null">login_date = #{loginDate},</if> | |||
| <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> | |||
| <if test="remark != null">remark = #{remark},</if> | |||
| <if test="gitLinkUsername != null and gitLinkUsername != ''">git_link_username = #{gitLinkUsername},</if> | |||
| <if test="gitLinkPassword != null and gitLinkPassword != ''">git_link_password = #{gitLinkPassword},</if> | |||
| update_time = sysdate() | |||
| </set> | |||
| where user_id = #{userId} | |||
| </update> | |||
| <update id="updateUserStatus" parameterType="SysUser"> | |||
| update sys_user | |||
| set status = #{status} | |||
| where user_id = #{userId} | |||
| </update> | |||
| <update id="updateUserAvatar" parameterType="SysUser"> | |||
| update sys_user | |||
| set avatar = #{avatar} | |||
| where user_name = #{userName} | |||
| </update> | |||
| <update id="resetUserPwd" parameterType="SysUser"> | |||
| update sys_user | |||
| set password = #{password} | |||
| where user_name = #{userName} | |||
| </update> | |||
| <delete id="deleteUserById" parameterType="Long"> | |||
| update sys_user | |||
| set del_flag = '2' | |||
| where user_id = #{userId} | |||
| </delete> | |||
| <delete id="deleteUserByIds" parameterType="Long"> | |||
| update sys_user set del_flag = '2' where user_id in | |||
| <foreach collection="array" item="userId" open="(" separator="," close=")"> | |||
| #{userId} | |||
| </foreach> | |||
| </delete> | |||
| </mapper> | |||
| @@ -15,6 +15,10 @@ spring: | |||
| discovery: | |||
| # 服务注册地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| username: nacos | |||
| password: nacos | |||
| retry: | |||
| enabled: true | |||
| config: | |||
| # 配置中心地址 | |||
| server-addr: nacos-ci4s.ci4s-test.svc:8848 | |||
| @@ -22,4 +26,6 @@ spring: | |||
| file-extension: yml | |||
| # 共享配置 | |||
| shared-configs: | |||
| - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| - data-id: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} | |||
| group: DEFAULT_GROUP | |||
| refresh: true | |||