域名管理服务端初步设计:支持域名搜索、添加、修改

This commit is contained in:
suxiang
2024-07-22 23:21:05 +08:00
parent dcb59975da
commit 6b5597514d
11 changed files with 505 additions and 2 deletions
@@ -0,0 +1,19 @@
package org.dromara.neutrinoproxy.server.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 默认域名状态枚举
* @author Mirac
* @date 21/7/2024
*/
@Getter
@AllArgsConstructor
public enum DefaultDomainStatusEnum {
ENABLE(1, "默认域名"),
DISABLE(2, "关闭");
private Integer status;
private String desc;
}
@@ -60,7 +60,6 @@ public enum ExceptionConstant {
PORT_CANNOT_REPEAT_MAPPING(14001, "服务端口[{}]不能重复映射"),
AN_UNSUPPORTED_PROTOCOL(14002, "不支持的协议[{}]"),
PORT_MAPPING_SUBDONAME_CONNOT_REPEAT(14003, "子域名不能重复使用!"),
// 调度管理(15000)
JOB_INFO_NOT_EXIST(15000, "调度管理记录不存在"),
SYSTEM_ERROR(500, "系统异常"),
@@ -72,7 +71,8 @@ public enum ExceptionConstant {
// 安全组管理(17000)
SECURITY_GROUP_NOT_EXIST(17000, "安全组不存在"),
SECURITY_RULE_NOT_EXIST(17001, "安全规则不存在"),
// 域名映射管理(18000)
DOMAIN_NAME_CANNOT_REPEAT(18000, "域名不能重复"),
;
private int code;
@@ -0,0 +1,19 @@
package org.dromara.neutrinoproxy.server.constant;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 仅Https状态枚举
* @author Mirac
* @date 21/7/2024
*/
@Getter
@AllArgsConstructor
public enum HttpsStatusEnum {
ONLY_HTTPS(1, "仅HTTPS"),
DISABLE_ONLY_HTTPS(2, "关闭仅HTTPS");
private Integer status;
private String desc;
}
@@ -0,0 +1,54 @@
package org.dromara.neutrinoproxy.server.controller;
import cn.hutool.core.util.StrUtil;
import org.dromara.neutrinoproxy.server.base.page.PageInfo;
import org.dromara.neutrinoproxy.server.base.page.PageQuery;
import org.dromara.neutrinoproxy.server.base.rest.Authorization;
import org.dromara.neutrinoproxy.server.controller.req.proxy.DomainCreateReq;
import org.dromara.neutrinoproxy.server.controller.req.proxy.DomainListReq;
import org.dromara.neutrinoproxy.server.controller.req.proxy.DomainUpdateReq;
import org.dromara.neutrinoproxy.server.controller.req.proxy.PortMappingCreateReq;
import org.dromara.neutrinoproxy.server.controller.res.proxy.DomainListRes;
import org.dromara.neutrinoproxy.server.util.ParamCheckUtil;
import org.noear.solon.annotation.*;
import org.dromara.neutrinoproxy.server.service.DomainService;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.UploadedFile;
import org.noear.solon.lang.Nullable;
import javax.sound.midi.Soundbank;
import java.io.IOException;
/**
* @author Mirac
* @date 21/7/2024
*/
@Mapping("/domain")
@Controller
public class DomainController {
@Inject
private DomainService domainService;
@Mapping("/page")
public PageInfo<DomainListRes> page(PageQuery pageQuery, DomainListReq req) {
return domainService.page(pageQuery, req);
}
@Post
@Mapping(path = "/create")
@Authorization(onlyAdmin = true)
public void create(DomainCreateReq req, UploadedFile jks) throws IOException {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotEmpty(req.getDomain(), "domain");
domainService.create(req, jks);
}
@Post
@Mapping(path = "/update")
@Authorization(onlyAdmin = true)
public void update(DomainUpdateReq req, UploadedFile jks) throws IOException {
ParamCheckUtil.checkNotNull(req, "req");
ParamCheckUtil.checkNotEmpty(req.getDomain(), "domain");
domainService.update(req, jks);
}
}
@@ -0,0 +1,29 @@
package org.dromara.neutrinoproxy.server.controller.req.proxy;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import org.dromara.neutrinoproxy.server.constant.DefaultDomainStatusEnum;
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
import org.dromara.neutrinoproxy.server.constant.HttpsStatusEnum;
import org.noear.solon.core.handle.UploadedFile;
import org.noear.solon.lang.Nullable;
import java.util.Date;
/**
* @author Mirac
* @date 21/7/2024
*/
@Data
public class DomainCreateReq {
/**
* 主域名
*/
private String domain;
/**
* KeyStore密码
*/
private String keyStorePassword;
}
@@ -0,0 +1,21 @@
package org.dromara.neutrinoproxy.server.controller.req.proxy;
import lombok.Data;
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
/**
* @author Mirac
* @date 21/7/2024
*/
@Data
public class DomainListReq {
/**
* 用户ID
*/
private Integer userId;
/**
* 启用状态
* {@link EnableStatusEnum}
*/
private Integer enable;
}
@@ -0,0 +1,25 @@
package org.dromara.neutrinoproxy.server.controller.req.proxy;
import lombok.Data;
/**
* @author Mirac
* @date 21/7/2024
*/
@Data
public class DomainUpdateReq {
/**
* id
*/
private Integer id;
/**
* 主域名
*/
private String domain;
/**
* KeyStore密码
*/
private String keyStorePassword;
}
@@ -0,0 +1,65 @@
package org.dromara.neutrinoproxy.server.controller.res.proxy;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import lombok.experimental.Accessors;
import org.dromara.neutrinoproxy.server.constant.DefaultDomainStatusEnum;
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
import org.dromara.neutrinoproxy.server.constant.HttpsStatusEnum;
import java.util.Date;
/**
* @author Mirac
* @date 21/7/2024
*/
@Accessors(chain = true)
@Data
public class DomainListRes {
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 主域名
*/
private String domain;
/**
* 用户ID
*/
private Integer userId;
/**
* 用户名
*/
private String userName;
/**
* 是否是默认域名(1、是 2、否)
* {@link DefaultDomainStatusEnum}
*/
private Integer isDefault;
/**
* 强制使用HTTPS(1、是 2、否)
* {@link HttpsStatusEnum}
*/
private Integer forceHttps;
/**
* 启用状态
* {@link EnableStatusEnum}
*/
private Integer enable;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
}
@@ -0,0 +1,28 @@
package org.dromara.neutrinoproxy.server.dal;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.ibatis.annotations.Mapper;
import org.dromara.neutrinoproxy.server.controller.req.system.PortGroupListReq;
import org.dromara.neutrinoproxy.server.controller.res.system.PortGroupListRes;
import org.dromara.neutrinoproxy.server.dal.entity.DomainNameDO;
import org.dromara.neutrinoproxy.server.dal.entity.PortGroupDO;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Mapper
public interface DomainMapper extends BaseMapper<DomainNameDO> {
default DomainNameDO checkRepeat(String domain, Set<Integer> excludeIds) {
return this.selectOne(new LambdaQueryWrapper<DomainNameDO>()
.eq(DomainNameDO::getDomain, domain)
.notIn(DomainNameDO::getId, excludeIds)
.last("limit 1")
);
}
}
@@ -0,0 +1,106 @@
/**
* Copyright (c) 2022 aoshiguchen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package org.dromara.neutrinoproxy.server.dal.entity;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.dromara.neutrinoproxy.server.constant.DefaultDomainStatusEnum;
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
import org.dromara.neutrinoproxy.server.constant.HttpsStatusEnum;
import org.dromara.neutrinoproxy.server.constant.OnlineStatusEnum;
import org.dromara.neutrinoproxy.server.controller.res.proxy.DomainListRes;
import org.dromara.neutrinoproxy.server.controller.res.proxy.PortMappingListRes;
import java.util.Date;
/**
* 域名
* @author: Mirac
* @date: 2024/7/21
*/
@ToString
@Accessors(chain = true)
@Data
@TableName("domain_name")
public class DomainNameDO {
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 主域名
*/
private String domain;
/**
* 用户ID
*/
private Integer userId;
/**
* SSL证书文件内容
*/
private byte[] jks;
/**
* KeyStore密码
*/
private String keyStorePassword;
/**
* 是否是默认域名(1、是 2、否)
* {@link DefaultDomainStatusEnum}
*/
private Integer isDefault;
/**
* 强制使用HTTPS(1、是 2、否)
* {@link HttpsStatusEnum}
*/
private Integer forceHttps;
/**
* 启用状态
* {@link EnableStatusEnum}
*/
private Integer enable;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
public DomainListRes toRes() {
DomainListRes res = new DomainListRes();
BeanUtil.copyProperties(this, res);
return res;
}
}
@@ -0,0 +1,137 @@
package org.dromara.neutrinoproxy.server.service;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.solon.plugins.pagination.Page;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.solon.annotation.Db;
import org.dromara.neutrinoproxy.server.base.page.PageInfo;
import org.dromara.neutrinoproxy.server.base.page.PageQuery;
import org.dromara.neutrinoproxy.server.base.rest.SystemContextHolder;
import org.dromara.neutrinoproxy.server.constant.DefaultDomainStatusEnum;
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
import org.dromara.neutrinoproxy.server.constant.ExceptionConstant;
import org.dromara.neutrinoproxy.server.constant.HttpsStatusEnum;
import org.dromara.neutrinoproxy.server.controller.req.proxy.DomainCreateReq;
import org.dromara.neutrinoproxy.server.controller.req.proxy.DomainListReq;
import org.dromara.neutrinoproxy.server.controller.req.proxy.DomainUpdateReq;
import org.dromara.neutrinoproxy.server.controller.res.proxy.DomainListRes;
import org.dromara.neutrinoproxy.server.dal.DomainMapper;
import org.dromara.neutrinoproxy.server.dal.UserMapper;
import org.dromara.neutrinoproxy.server.dal.entity.DomainNameDO;
import org.dromara.neutrinoproxy.server.dal.entity.UserDO;
import org.dromara.neutrinoproxy.server.util.ParamCheckUtil;
import org.h2.schema.Domain;
import org.noear.solon.annotation.Component;
import org.noear.solon.core.handle.UploadedFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author Mirac
* @date 21/7/2024
*/
@Slf4j
@Component
public class DomainService {
@Db
private DomainMapper domainMapper;
@Db
private UserMapper userMapper;
public PageInfo<DomainListRes> page(PageQuery pageQuery, DomainListReq req) {
// Page<DomainNameDO> page = new Page<>(pageQuery.getCurrent(), pageQuery.getSize());
// LambdaQueryWrapper<DomainNameDO> queryWrapper = Wrappers.<DomainNameDO>lambdaQuery()
// .eq(req.getEnable() != null, DomainNameDO::getEnable, req.getEnable())
// .eq(req.getUserId() != null, DomainNameDO::getUserId, req.getUserId());
// Page<DomainNameDO> page = domainMapper.selectPage(page, queryWrapper);
Page<DomainNameDO> page = domainMapper.selectPage(new Page<>(pageQuery.getCurrent(), pageQuery.getSize()), new LambdaQueryWrapper<DomainNameDO>()
.eq(req.getEnable() != null, DomainNameDO::getEnable, req.getEnable())
.eq(req.getUserId() != null, DomainNameDO::getUserId, req.getUserId())
.orderByAsc(Arrays.asList(DomainNameDO::getUserId, DomainNameDO::getId))
);
List<DomainListRes> resList = page.getRecords().stream().map(DomainNameDO::toRes).collect(Collectors.toList());
if (CollectionUtils.isEmpty(page.getRecords())) {
return PageInfo.of(resList, page);
}
Set<Integer> userIds = resList.stream().map(DomainListRes::getUserId).collect(Collectors.toSet());
List<UserDO> userDOList = userMapper.findByIds(userIds);
Map<Integer, UserDO> userMap = userDOList.stream().collect(Collectors.toMap(UserDO::getId, c -> c));
for (DomainListRes item : resList) {
UserDO userDO = userMap.get(item.getUserId());
if (null != userDO) {
item.setUserName(userDO.getName());
}
}
return PageInfo.of(resList, page);
}
/**
* 创建域名
* @param req
*/
public void create(DomainCreateReq req, UploadedFile jks) throws IOException {
DomainNameDO domainNameDO = new DomainNameDO();
if (null != jks) {
ParamCheckUtil.checkNotEmpty(req.getKeyStorePassword(), "keyStorePassword");
InputStream content = jks.getContent();
byte[] byteArray = toByteArray(content);
domainNameDO.setJks(byteArray);
domainNameDO.setKeyStorePassword(req.getKeyStorePassword());
}
Integer userId = SystemContextHolder.getUserId();
Date now = new Date();
domainNameDO.setDomain(req.getDomain());
domainNameDO.setIsDefault(DefaultDomainStatusEnum.DISABLE.getStatus());
domainNameDO.setForceHttps(HttpsStatusEnum.DISABLE_ONLY_HTTPS.getStatus());
domainNameDO.setUserId(userId);
domainNameDO.setEnable(EnableStatusEnum.ENABLE.getStatus());
domainNameDO.setCreateTime(now);
domainNameDO.setUpdateTime(now);
domainMapper.insert(domainNameDO);
}
/**
* 将 InputStream 转换为 byte[]
*/
private byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = input.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
return buffer.toByteArray();
}
public void update(DomainUpdateReq req, UploadedFile jks) throws IOException {
DomainNameDO domainNameCheck = domainMapper.checkRepeat(req.getDomain(), Sets.newHashSet(req.getId()));
ParamCheckUtil.checkMustNull(domainNameCheck, ExceptionConstant.DOMAIN_NAME_CANNOT_REPEAT);
LambdaUpdateWrapper<DomainNameDO> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(DomainNameDO::getId, req.getId());
if (null != jks) {
ParamCheckUtil.checkNotEmpty(req.getKeyStorePassword(), "keyStorePassword");
InputStream content = jks.getContent();
byte[] byteArray = toByteArray(content);
updateWrapper.set(DomainNameDO::getKeyStorePassword, req.getKeyStorePassword());
updateWrapper.set(DomainNameDO::getJks, byteArray);
}
updateWrapper.set(DomainNameDO::getDomain, req.getDomain());
updateWrapper.set(DomainNameDO::getUpdateTime, new Date());
int update = domainMapper.update(updateWrapper);
System.out.println(update);
}
}