Merge remote-tracking branch 'origin/dev'
This commit is contained in:
Generated
BIN
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
@@ -87,6 +87,9 @@
|
||||
<a href="https://gitee.com/MetalXingxing" target="_blank">
|
||||
<img src="assets/developer/metal.png" width="12%">
|
||||
</a>
|
||||
<a href="https://gitee.com/click33" target="_blank">
|
||||
<img src="assets/developer/click33.png" width="12%">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
# ❤️ 感谢
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 350 KiB |
@@ -14,13 +14,11 @@ export function portPoolList() {
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
export function availablePortList(licenseId) {
|
||||
export function availablePortList(query) {
|
||||
return request({
|
||||
url: '/port-pool/get-available-port-list',
|
||||
method: 'get',
|
||||
params: {
|
||||
licenseId: licenseId
|
||||
}
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
@@ -70,3 +68,11 @@ export function deleteBatchPortPool(ids) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function portAvailable(query) {
|
||||
return request({
|
||||
url: '/port-pool/port-available',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
<!--
|
||||
采用github上面的开源组件https://github.com/johnhom1024/vue-load-select
|
||||
不过有个bug,就是没办法展示下拉的箭头,目前修复的方式:等dom加载完毕后,补充箭头的class
|
||||
参考:https://blog.csdn.net/weixin_42381896/article/details/122258563
|
||||
-->
|
||||
<template>
|
||||
<el-select
|
||||
ref="selectLoadMore"
|
||||
:value="value"
|
||||
v-loadmore="loadMore"
|
||||
@focus="focus"
|
||||
@clear="clear"
|
||||
filterable
|
||||
remote
|
||||
:filter-method="handleSearch"
|
||||
:loading="loading"
|
||||
clearable
|
||||
v-bind="$attrs"
|
||||
v-on="$listeners"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in data"
|
||||
:label="option[dictLabel]"
|
||||
:value="option[dictValue]"
|
||||
:key="option.value"
|
||||
></el-option>
|
||||
<!-- 此处加载中的value可以随便设置,只要不与其他数据重复即可 -->
|
||||
<el-option
|
||||
v-if="hasMore"
|
||||
disabled
|
||||
label="加载中..."
|
||||
value="-1" />
|
||||
<!--补充页面无数据时,显示无数据的效果-->
|
||||
<el-option
|
||||
v-if="!hasMore && data.length==0"
|
||||
disabled
|
||||
label="暂无数据"
|
||||
value="-2" />
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "SelectLoadMore",
|
||||
props: {
|
||||
value: {
|
||||
default: null
|
||||
},
|
||||
// 列表数据
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
dictLabel: {
|
||||
type: String,
|
||||
default: "label"
|
||||
},
|
||||
dictValue: {
|
||||
type: String,
|
||||
default: "value"
|
||||
},
|
||||
// 调用页数的接口
|
||||
request: {
|
||||
type: Function,
|
||||
default: () => {
|
||||
}
|
||||
},
|
||||
// 传入的页码
|
||||
page: {
|
||||
type: [Number, String],
|
||||
default: 1
|
||||
},
|
||||
// 是否还有更多数据
|
||||
hasMore: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
directives: {
|
||||
// 这里实现一个组件内部的自定义指令
|
||||
loadmore: {
|
||||
// 指令的定义
|
||||
bind(el, binding) {
|
||||
const SELECTWRAP = el.querySelector(
|
||||
".el-select-dropdown .el-select-dropdown__wrap"
|
||||
);
|
||||
if (!SELECTWRAP) {
|
||||
throw new Error('获取不到"el-select-dropdown__wrap"节点');
|
||||
}
|
||||
SELECTWRAP.addEventListener("scroll", () => {
|
||||
// scrollTop 这里可能因为浏览器缩放存在小数点的情况,导致了滚动到底部时
|
||||
// scrollHeight 减去滚动到底部时的scrollTop ,依然大于clientHeight 导致无法请求更多数据
|
||||
// 这里将scrollTop向上取整 保证滚到底部时,触发调用
|
||||
const CONDITION =
|
||||
SELECTWRAP.scrollHeight -
|
||||
Math.ceil(SELECTWRAP.scrollTop) <=
|
||||
SELECTWRAP.clientHeight;
|
||||
// el.scrollTop !== 0 当输入时,如果搜索结果很少,以至于没看到滚动条,那么此时的CONDITION计算结果是true,会执行bind.value(),此时不应该执行,否则搜索结果不匹配
|
||||
if (CONDITION && SELECTWRAP.scrollTop !== 0) {
|
||||
binding.value();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: "", // 存储关键字用
|
||||
loading: false
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
// 请求下一页的数据
|
||||
loadMore() {
|
||||
// 如果没有更多数据,则不请求
|
||||
if (!this.hasMore) {
|
||||
return;
|
||||
}
|
||||
// 如果intercept属性为true则不请求数据,
|
||||
if (this.loadMore.intercept) {
|
||||
return;
|
||||
}
|
||||
this.loadMore.intercept = true;
|
||||
this.request({
|
||||
page: this.page + 1,
|
||||
more: true,
|
||||
keyword: this.keyword
|
||||
}).then(() => {
|
||||
this.loadMore.intercept = false;
|
||||
});
|
||||
},
|
||||
// 选中下拉框没有数据时,自动请求第一页的数据
|
||||
focus() {
|
||||
if (!this.data.length) {
|
||||
this.request({page: 1});
|
||||
}
|
||||
},
|
||||
handleSearch(keyword) {
|
||||
this.keyword = keyword;
|
||||
this.loading = true;
|
||||
console.log(keyword);
|
||||
this.request({page: 1, keyword: keyword}).then(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 删除选中时,如果请求了关键字,则清除关键字再请求第一页的数据
|
||||
clear() {
|
||||
if (this.keyword) {
|
||||
this.keyword = "";
|
||||
this.request({page: 1});
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(function () {
|
||||
// github代码有个bug,下拉的箭头无法加载的问题,需要等dom页面加载完毕后,添加箭头的class
|
||||
let rulesDom = this.$refs["selectLoadMore"].$el.querySelector(
|
||||
".el-input .el-input__suffix .el-input__suffix-inner .el-input__icon"
|
||||
);// 找到dom
|
||||
rulesDom.classList.add("el-icon-arrow-up");// 对dom新增class
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -97,6 +97,7 @@ export default {
|
||||
readings: 'Readings',
|
||||
status: 'Status',
|
||||
actions: 'Actions',
|
||||
access: 'Access',
|
||||
edit: 'Edit',
|
||||
publish: 'Publish',
|
||||
draft: 'Draft',
|
||||
|
||||
@@ -117,6 +117,8 @@ export default {
|
||||
readings: '阅读数',
|
||||
status: '状态',
|
||||
actions: '操作',
|
||||
access: '访问',
|
||||
openWebPage: '打开网页',
|
||||
edit: '编辑',
|
||||
publish: '发布',
|
||||
draft: '草稿',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<div class="filter-container">
|
||||
<el-select v-model="listQuery.userId" placeholder="请选择用户" clearable>
|
||||
<el-select v-model="listQuery.userId" placeholder="请选择用户" filterable clearable>
|
||||
<el-option v-for="item in userList" :key="item.id" :label="item.name" :value="item.id"/>
|
||||
</el-select>
|
||||
<el-select v-model="listQuery.isOnline" placeholder="请选择在线状态" clearable>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="app-container calendar-list-container">
|
||||
<div class="filter-container" style="display:flex">
|
||||
<el-select v-model="listQuery.userId" placeholder="请选择用户" clearable style="margin-right:10px;width: 120px;">
|
||||
<el-select v-model="listQuery.userId" placeholder="请选择用户" filterable clearable style="margin-right:10px;width: 120px;">
|
||||
<el-option v-for="item in userList" :key="item.loginName" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
<el-select v-model="listQuery.licenseId" placeholder="请选择license" clearable style="margin-right:10px;width: 135px;">
|
||||
<el-select v-model="listQuery.licenseId" placeholder="请选择license" filterable clearable style="margin-right:10px;width: 135px;">
|
||||
<el-option v-for="item in licenseList" :key="item.key" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
<el-select v-model="listQuery.protocal" placeholder="请选择协议" clearable style="margin-right:10px;width: 120px;">
|
||||
@@ -90,11 +90,15 @@
|
||||
<el-tag :type="scope.row.isOnline | statusFilter">{{ scope.row.isOnline | isOnlineName }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.actions')" width="230" class-name="small-padding fixed-width">
|
||||
<el-table-column class-name="status-col" :label="$t('table.access')" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" v-if="(scope.row.protocal === 'HTTP' || scope.row.protocal === 'HTTP(S)')" @click="handleOpenWebPage(scope.row)">{{$t('table.openWebPage')}}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column align="center" :label="$t('table.actions')" width="320" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">{{ $t('table.edit') }}</el-button>
|
||||
<el-button v-if="scope.row.enable == '1'" size="mini" type="danger" @click="handleModifyStatus(scope.row, 2)">{{
|
||||
$t('table.disable') }}</el-button>
|
||||
<el-button v-if="scope.row.enable == '1'" size="mini" type="danger" @click="handleModifyStatus(scope.row, 2)">{{$t('table.disable')}}</el-button>
|
||||
<el-button v-if="scope.row.enable == '2'" size="mini" type="success"
|
||||
@click="handleModifyStatus(scope.row, 1)">{{ $t('table.enable') }}</el-button>
|
||||
<!-- <el-button size="mini" type="danger" @click="handleDelete(scope.row,'deleted')">{{$t('table.delete')}}</el-button>-->
|
||||
@@ -142,11 +146,16 @@
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('服务端端口')" prop="serverPort">
|
||||
<el-select style="width: 280px;" class="filter-item" v-model="temp.serverPort" placeholder="请选择" filterable>
|
||||
<el-option v-for="item in serverPortList" :key="item.port" :label="item.port" :value="item.port">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-form-item :label="$t('服务端端口')" prop="serverPort" >
|
||||
<load-select style="width: 280px;" class="filter-item"
|
||||
v-model="temp.serverPort"
|
||||
:data="serverPortList"
|
||||
:page="loadServerPortQuery.page"
|
||||
:hasMore="more"
|
||||
:clearable="false"
|
||||
:dictLabel="'port'"
|
||||
:dictValue="'port'"
|
||||
:request="loadServerPort"/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('客户端IP')" prop="clientIp">
|
||||
<el-input v-model="temp.clientIp"></el-input>
|
||||
@@ -187,7 +196,7 @@
|
||||
|
||||
<script>
|
||||
import { fetchList, createUserPortMapping, updateUserPortMapping, updateEnableStatus, deletePortMapping } from '@/api/portMapping'
|
||||
import { portPoolList, availablePortList } from '@/api/portPool'
|
||||
import { portPoolList, availablePortList, portAvailable } from '@/api/portPool'
|
||||
import { licenseList, licenseAuthList } from '@/api/license'
|
||||
import { protocalList } from '@/api/protocal'
|
||||
import { userList } from '@/api/user'
|
||||
@@ -196,6 +205,8 @@ import waves from '@/directive/waves' // 水波纹指令
|
||||
import { parseTime } from '@/utils'
|
||||
import ButtonPopover from '../../components/Button/buttonPopover'
|
||||
import DropdownTable from '../../components/Dropdown/DropdownTable'
|
||||
// 下拉选择加载组件
|
||||
import loadSelect from "@/components/Select/SelectLoadMore";
|
||||
|
||||
const calendarTypeOptions = [
|
||||
{ key: 'CN', display_name: 'China' },
|
||||
@@ -217,9 +228,22 @@ export default {
|
||||
},
|
||||
components: {
|
||||
DropdownTable,
|
||||
ButtonPopover
|
||||
ButtonPopover,
|
||||
loadSelect
|
||||
},
|
||||
data() {
|
||||
const isPortAvailable = (rule, value, callback) => {
|
||||
if (value != null) {
|
||||
const param = { port: value, portMappingId: this.temp.id }
|
||||
portAvailable(param).then(res => {
|
||||
if (!res.data.data) {
|
||||
return callback(new Error('该端口被占用'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return {
|
||||
tableKey: 0,
|
||||
list: null,
|
||||
@@ -273,7 +297,8 @@ export default {
|
||||
pvData: [],
|
||||
rules: {
|
||||
licenseId: [{ required: true, message: '请选择License', trigger: 'blur,change' }],
|
||||
serverPort: [{ required: true, message: '请输入服务端端口', trigger: 'blur' }],
|
||||
serverPort: [{ required: true, message: '请输入服务端端口', trigger: 'blur' },
|
||||
{ validator: isPortAvailable, trigger: 'change' }],
|
||||
clientIp: [{ required: true, message: '请输入客户端IP', trigger: 'blur' }],
|
||||
clientPort: [{ required: true, message: '请输入客户端端口', trigger: 'blur' }],
|
||||
protocal: [{ required: true, message: '请选择协议', trigger: 'blur' }]
|
||||
@@ -282,7 +307,13 @@ export default {
|
||||
countryColumns: [
|
||||
{ prop: 'userName', label: '用户名', align: 'center' },
|
||||
{ prop: 'name', label: 'License', align: 'center' }
|
||||
]
|
||||
],
|
||||
loadServerPortQuery:{ //下拉框加载数据请求参数
|
||||
page:1,
|
||||
size:50,
|
||||
licenseId:null,
|
||||
},
|
||||
more: true,
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
@@ -343,15 +374,9 @@ export default {
|
||||
this.domainName = response.data.data
|
||||
})
|
||||
},
|
||||
getPortPoolList() {
|
||||
portPoolList().then(response => {
|
||||
this.serverPortList = response.data.data
|
||||
})
|
||||
},
|
||||
getAvailablePortList(licenseId) {
|
||||
availablePortList(licenseId).then(response => {
|
||||
this.serverPortList = response.data.data
|
||||
})
|
||||
this.loadServerPortQuery.licenseId = licenseId;
|
||||
this.serverPortList = []; //清掉数据
|
||||
},
|
||||
getAllUserList() {
|
||||
userList().then(response => {
|
||||
@@ -408,6 +433,8 @@ export default {
|
||||
userId: undefined
|
||||
}
|
||||
this.serverPortList = []
|
||||
this.loadServerPortQuery.licenseId = null;
|
||||
this.more = true;
|
||||
},
|
||||
handleCreate() {
|
||||
this.resetTemp()
|
||||
@@ -435,6 +462,10 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
handleOpenWebPage(row) {
|
||||
const url = location.protocol + '//' + location.hostname + ':' + row.serverPort
|
||||
open(url)
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.temp = Object.assign({}, row) // copy obj
|
||||
this.temp.timestamp = new Date(this.temp.timestamp)
|
||||
@@ -526,6 +557,36 @@ export default {
|
||||
return v[j]
|
||||
}
|
||||
}))
|
||||
},
|
||||
// 传入给load-select组件的函数
|
||||
loadServerPort({page = 1, more = false, keyword = ""} = {}) {
|
||||
if(this.loadServerPortQuery.licenseId==null || this.loadServerPortQuery.licenseId==''){
|
||||
this.more = false;
|
||||
this.$message({
|
||||
message: '请先选择License',
|
||||
type: 'warning'
|
||||
})
|
||||
return ;
|
||||
}
|
||||
return new Promise(resolve => {
|
||||
this.loadServerPortQuery.page = page;
|
||||
this.loadServerPortQuery.keyword = keyword;
|
||||
// 访问后端接口API
|
||||
availablePortList(this.loadServerPortQuery).then(res => {
|
||||
let result = res.data;
|
||||
if (more) {
|
||||
this.serverPortList = [...this.serverPortList, ...result.data.records];
|
||||
} else {
|
||||
this.serverPortList = result.data.records;
|
||||
}
|
||||
|
||||
// this.loadServerPortQuery.page = result.data.current;
|
||||
let {total, current, size} = result.data;
|
||||
this.more = page * size < total;
|
||||
this.loadServerPortQuery.page = current;
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -29,6 +29,7 @@ public class ProxyMessageDisconnectHandler implements ProxyMessageHandler {
|
||||
ProxyUtil.returnProxyChanel(ctx.channel());
|
||||
realServerChannel.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
@@ -42,6 +42,7 @@ public class ServiceException extends RuntimeException {
|
||||
private String msg;
|
||||
|
||||
public ServiceException(int code, String msg) {
|
||||
super(msg);
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
+1
@@ -50,6 +50,7 @@ public enum ExceptionConstant {
|
||||
ORIGIN_PASSWORD_CHECK_FAIL(12002, "原密码验证失败"),
|
||||
LOGIN_PASSWORD_LENGTH_CHECK_FAIL(12003, "登录密码不能小于6位数"),
|
||||
LOGIN_PASSWORD_NO_CHANGE_MODIFY_FAIL(12004, "密码没有变化,修改失败"),
|
||||
LICENSE_CANNOT_BE_DELETED(12005, "license下存在[{}]个端口映射!"),
|
||||
// 端口池管理(13000)
|
||||
PORT_CANNOT_REPEAT(13000,"端口不能重复"),
|
||||
PORT_NOT_EXIST(13001, "该端口在端口池中不存在"),
|
||||
|
||||
+9
-1
@@ -102,7 +102,7 @@ public class PortPoolController {
|
||||
|
||||
@Get
|
||||
@Mapping("/get-available-port-list")
|
||||
public List<PortPoolListRes> getAvailablePortList(AvailablePortListReq req) {
|
||||
public PageInfo<PortPoolListRes> getAvailablePortList(AvailablePortListReq req) {
|
||||
ParamCheckUtil.checkNotNull(req, "req");
|
||||
ParamCheckUtil.checkNotNull(req.getLicenseId(), "licenseId");
|
||||
return portPoolService.getAvailablePortList(req);
|
||||
@@ -133,4 +133,12 @@ public class PortPoolController {
|
||||
|
||||
portPoolService.deleteBatch(req.getIds());
|
||||
}
|
||||
|
||||
@Get
|
||||
@Mapping("/port-available")
|
||||
public boolean portAvailable(Integer port, Integer portMappingId) {
|
||||
ParamCheckUtil.checkNotNull(port, "port");
|
||||
|
||||
return portPoolService.portAvailable(port, portMappingId);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -30,8 +30,16 @@ import lombok.Data;
|
||||
*/
|
||||
@Data
|
||||
public class LicenseListReq {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Integer userId;
|
||||
/**
|
||||
* 是否在线
|
||||
*/
|
||||
private Integer isOnline;
|
||||
/**
|
||||
* 启动状态 1启用 2禁用
|
||||
*/
|
||||
private Integer enable;
|
||||
}
|
||||
|
||||
+14
@@ -12,4 +12,18 @@ public class AvailablePortListReq {
|
||||
* licenseId
|
||||
*/
|
||||
private Integer licenseId;
|
||||
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
private int page = 1;
|
||||
/**
|
||||
* 分页大小
|
||||
*/
|
||||
private int size = 10;
|
||||
|
||||
/**
|
||||
* 搜索关键字
|
||||
*/
|
||||
private String keyword;
|
||||
}
|
||||
|
||||
+1
-1
@@ -67,5 +67,5 @@ public interface PortPoolMapper extends BaseMapper<PortPoolDO> {
|
||||
|
||||
List<PortPoolListRes> selectResList(@Param("req") PortPoolListReq req);
|
||||
|
||||
List<PortPoolListRes> getAvailablePortList(@Param("licenseId") Integer licenseId,@Param("userId") Integer userId);
|
||||
List<PortPoolListRes> getAvailablePortList(@Param("licenseId") Integer licenseId,@Param("userId") Integer userId, @Param("keyword") String keyword);
|
||||
}
|
||||
|
||||
+10
-10
@@ -106,16 +106,16 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler<Proxy
|
||||
// 防止下次换一个客户端,无法连接的情况
|
||||
ProxyUtil.removeClientIdByLicenseId(cmdChannelAttachInfo.getLicenseId());
|
||||
}
|
||||
// 即便是因为上述原因断开,断开的日志依然要记录,方便排查问题
|
||||
Solon.context().getBean(ClientConnectRecordService.class).add(new ClientConnectRecordDO()
|
||||
.setIp(((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress())
|
||||
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
|
||||
.setType(ClientConnectTypeEnum.DISCONNECT.getType())
|
||||
.setMsg("")
|
||||
.setCode(SuccessCodeEnum.SUCCESS.getCode())
|
||||
.setCreateTime(new Date())
|
||||
);
|
||||
}
|
||||
// 即便是因为上述原因断开,断开的日志依然要记录,方便排查问题
|
||||
Solon.context().getBean(ClientConnectRecordService.class).add(new ClientConnectRecordDO()
|
||||
.setIp(((InetSocketAddress)ctx.channel().remoteAddress()).getAddress().getHostAddress())
|
||||
.setLicenseId(cmdChannelAttachInfo.getLicenseId())
|
||||
.setType(ClientConnectTypeEnum.DISCONNECT.getType())
|
||||
.setMsg("")
|
||||
.setCode(SuccessCodeEnum.SUCCESS.getCode())
|
||||
.setCreateTime(new Date())
|
||||
);
|
||||
}
|
||||
|
||||
super.channelInactive(ctx);
|
||||
@@ -123,7 +123,7 @@ public class ProxyTunnelChannelHandler extends SimpleChannelInboundHandler<Proxy
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
super.exceptionCaught(ctx, cause);
|
||||
// super.exceptionCaught(ctx, cause);
|
||||
if (ctx.channel().isActive()) {
|
||||
ctx.channel().close();
|
||||
}
|
||||
|
||||
+204
-191
@@ -6,9 +6,12 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.google.common.collect.Sets;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.dromara.neutrinoproxy.server.base.db.DBInitialize;
|
||||
import org.dromara.neutrinoproxy.server.base.page.PageInfo;
|
||||
import org.dromara.neutrinoproxy.server.base.page.PageQuery;
|
||||
import org.dromara.neutrinoproxy.server.base.rest.ServiceException;
|
||||
import org.dromara.neutrinoproxy.server.base.rest.SystemContextHolder;
|
||||
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
|
||||
import org.dromara.neutrinoproxy.server.constant.ExceptionConstant;
|
||||
@@ -19,17 +22,15 @@ import org.dromara.neutrinoproxy.server.controller.req.proxy.LicenseUpdateEnable
|
||||
import org.dromara.neutrinoproxy.server.controller.req.proxy.LicenseUpdateReq;
|
||||
import org.dromara.neutrinoproxy.server.controller.res.proxy.*;
|
||||
import org.dromara.neutrinoproxy.server.dal.LicenseMapper;
|
||||
import org.dromara.neutrinoproxy.server.dal.PortMappingMapper;
|
||||
import org.dromara.neutrinoproxy.server.dal.UserMapper;
|
||||
import org.dromara.neutrinoproxy.server.dal.entity.LicenseDO;
|
||||
import org.dromara.neutrinoproxy.server.dal.entity.PortMappingDO;
|
||||
import org.dromara.neutrinoproxy.server.dal.entity.UserDO;
|
||||
import org.dromara.neutrinoproxy.server.util.ParamCheckUtil;
|
||||
import ma.glasnost.orika.MapperFacade;
|
||||
import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.dromara.neutrinoproxy.server.controller.res.proxy.*;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Init;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.core.Lifecycle;
|
||||
import org.noear.solon.core.bean.LifecycleBean;
|
||||
|
||||
import java.util.*;
|
||||
@@ -38,219 +39,231 @@ import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* license服务
|
||||
*
|
||||
* @author: aoshiguchen
|
||||
* @date: 2022/8/6
|
||||
*/
|
||||
@Component
|
||||
public class LicenseService implements LifecycleBean {
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private LicenseMapper licenseMapper;
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
@Inject
|
||||
private VisitorChannelService visitorChannelService;
|
||||
@Inject
|
||||
private DBInitialize dbInitialize;
|
||||
@Inject
|
||||
private MapperFacade mapperFacade;
|
||||
@Db
|
||||
private LicenseMapper licenseMapper;
|
||||
@Db
|
||||
private PortMappingMapper portMappingMapper;
|
||||
@Db
|
||||
private UserMapper userMapper;
|
||||
@Inject
|
||||
private VisitorChannelService visitorChannelService;
|
||||
@Inject
|
||||
private DBInitialize dbInitialize;
|
||||
|
||||
public PageInfo<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
|
||||
Page<LicenseListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(req.getUserId() != null, LicenseDO::getUserId, req.getUserId())
|
||||
.eq(req.getIsOnline() != null, LicenseDO::getIsOnline, req.getIsOnline())
|
||||
.eq(req.getEnable() != null, LicenseDO::getEnable, req.getEnable())
|
||||
.orderByAsc(Arrays.asList(LicenseDO::getUserId, LicenseDO::getId))
|
||||
);
|
||||
List<LicenseListRes> respList = mapperFacade.mapAsList(list, LicenseListRes.class);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
if (!CollectionUtil.isEmpty(respList)) {
|
||||
Set<Integer> userIds = respList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
for (LicenseListRes item : respList) {
|
||||
UserDO userDO = userMap.get(item.getUserId());
|
||||
if (null != userDO) {
|
||||
item.setUserName(userDO.getName());
|
||||
}
|
||||
item.setKey(desensitization(item.getUserId(), item.getKey()));
|
||||
}
|
||||
}
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
public PageInfo<LicenseListRes> page(PageQuery pageQuery, LicenseListReq req) {
|
||||
Page<LicenseListRes> result = PageHelper.startPage(pageQuery.getCurrent(), pageQuery.getSize());
|
||||
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(req.getUserId() != null, LicenseDO::getUserId, req.getUserId())
|
||||
.eq(req.getIsOnline() != null, LicenseDO::getIsOnline, req.getIsOnline())
|
||||
.eq(req.getEnable() != null, LicenseDO::getEnable, req.getEnable())
|
||||
.orderByAsc(Arrays.asList(LicenseDO::getUserId, LicenseDO::getId))
|
||||
);
|
||||
List<LicenseListRes> respList = mapperFacade.mapAsList(list, LicenseListRes.class);
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
if (!CollectionUtil.isEmpty(respList)) {
|
||||
Set<Integer> userIds = respList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
for (LicenseListRes item : respList) {
|
||||
UserDO userDO = userMap.get(item.getUserId());
|
||||
if (null != userDO) {
|
||||
item.setUserName(userDO.getName());
|
||||
}
|
||||
item.setKey(desensitization(item.getUserId(), item.getKey()));
|
||||
}
|
||||
}
|
||||
return PageInfo.of(respList, result.getTotal(), pageQuery.getCurrent(), pageQuery.getSize());
|
||||
}
|
||||
|
||||
public List<LicenseListRes> list(LicenseListReq req) {
|
||||
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(null != req.getEnable(), LicenseDO::getEnable, req.getEnable())
|
||||
);
|
||||
List<LicenseListRes> licenseList = assembleConvertLicenses(list);
|
||||
return licenseList;
|
||||
}
|
||||
public List<LicenseListRes> list(LicenseListReq req) {
|
||||
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(null != req.getEnable(), LicenseDO::getEnable, req.getEnable())
|
||||
);
|
||||
List<LicenseListRes> licenseList = assembleConvertLicenses(list);
|
||||
return licenseList;
|
||||
}
|
||||
|
||||
private List<LicenseListRes> assembleConvertLicenses(List<LicenseDO> list) {
|
||||
List<LicenseListRes> licenseList = mapperFacade.mapAsList(list, LicenseListRes.class);
|
||||
if (!CollectionUtil.isEmpty(licenseList)) {
|
||||
Set<Integer> userIds = licenseList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
for (LicenseListRes item : licenseList) {
|
||||
UserDO userDO = userMap.get(item.getUserId());
|
||||
if (null != userDO) {
|
||||
item.setUserName(userDO.getName());
|
||||
}
|
||||
item.setKey(desensitization(item.getUserId(), item.getKey()));
|
||||
}
|
||||
}
|
||||
return licenseList;
|
||||
}
|
||||
private List<LicenseListRes> assembleConvertLicenses(List<LicenseDO> list) {
|
||||
List<LicenseListRes> licenseList = mapperFacade.mapAsList(list, LicenseListRes.class);
|
||||
if (!CollectionUtil.isEmpty(licenseList)) {
|
||||
Set<Integer> userIds = licenseList.stream().map(LicenseListRes::getUserId).collect(Collectors.toSet());
|
||||
List<UserDO> userList = userMapper.findByIds(userIds);
|
||||
Map<Integer, UserDO> userMap = userList.stream().collect(Collectors.toMap(UserDO::getId, Function.identity()));
|
||||
for (LicenseListRes item : licenseList) {
|
||||
UserDO userDO = userMap.get(item.getUserId());
|
||||
if (null != userDO) {
|
||||
item.setUserName(userDO.getName());
|
||||
}
|
||||
item.setKey(desensitization(item.getUserId(), item.getKey()));
|
||||
}
|
||||
}
|
||||
return licenseList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建license
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
public LicenseCreateRes create(LicenseCreateReq req) {
|
||||
LicenseDO licenseDO = licenseMapper.checkRepeat(req.getUserId(), req.getName());
|
||||
ParamCheckUtil.checkExpression(null == licenseDO, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
|
||||
/**
|
||||
* 创建license
|
||||
*
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
public LicenseCreateRes create(LicenseCreateReq req) {
|
||||
LicenseDO licenseDO = licenseMapper.checkRepeat(req.getUserId(), req.getName());
|
||||
ParamCheckUtil.checkExpression(null == licenseDO, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
|
||||
|
||||
String key = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
Date now = new Date();
|
||||
String key = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
Date now = new Date();
|
||||
|
||||
licenseMapper.insert(new LicenseDO()
|
||||
.setName(req.getName())
|
||||
.setKey(key)
|
||||
.setUserId(req.getUserId())
|
||||
.setIsOnline(OnlineStatusEnum.OFFLINE.getStatus())
|
||||
.setEnable(EnableStatusEnum.ENABLE.getStatus())
|
||||
.setCreateTime(now)
|
||||
.setUpdateTime(now)
|
||||
);
|
||||
return new LicenseCreateRes();
|
||||
}
|
||||
licenseMapper.insert(new LicenseDO()
|
||||
.setName(req.getName())
|
||||
.setKey(key)
|
||||
.setUserId(req.getUserId())
|
||||
.setIsOnline(OnlineStatusEnum.OFFLINE.getStatus())
|
||||
.setEnable(EnableStatusEnum.ENABLE.getStatus())
|
||||
.setCreateTime(now)
|
||||
.setUpdateTime(now)
|
||||
);
|
||||
return new LicenseCreateRes();
|
||||
}
|
||||
|
||||
public LicenseUpdateRes update(LicenseUpdateReq req) {
|
||||
LicenseDO oldLicenseDO = licenseMapper.findById(req.getId());
|
||||
ParamCheckUtil.checkNotNull(oldLicenseDO, ExceptionConstant.LICENSE_NOT_EXIST);
|
||||
public LicenseUpdateRes update(LicenseUpdateReq req) {
|
||||
LicenseDO oldLicenseDO = licenseMapper.findById(req.getId());
|
||||
ParamCheckUtil.checkNotNull(oldLicenseDO, ExceptionConstant.LICENSE_NOT_EXIST);
|
||||
|
||||
LicenseDO licenseCheck = licenseMapper.checkRepeat(oldLicenseDO.getUserId(), req.getName(), Sets.newHashSet(oldLicenseDO.getId()));
|
||||
ParamCheckUtil.checkMustNull(licenseCheck, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
|
||||
LicenseDO licenseCheck = licenseMapper.checkRepeat(oldLicenseDO.getUserId(), req.getName(), Sets.newHashSet(oldLicenseDO.getId()));
|
||||
ParamCheckUtil.checkMustNull(licenseCheck, ExceptionConstant.LICENSE_NAME_CANNOT_REPEAT);
|
||||
|
||||
licenseMapper.update(req.getId(), req.getName(), new Date());
|
||||
return new LicenseUpdateRes();
|
||||
}
|
||||
licenseMapper.update(req.getId(), req.getName(), new Date());
|
||||
return new LicenseUpdateRes();
|
||||
}
|
||||
|
||||
public LicenseDetailRes detail(Integer id) {
|
||||
LicenseDO licenseDO = licenseMapper.findById(id);
|
||||
if (null == licenseDO) {
|
||||
return null;
|
||||
}
|
||||
UserDO userDO = userMapper.findById(licenseDO.getUserId());
|
||||
String userName = "";
|
||||
if (null != userDO) {
|
||||
userName = userDO.getName();
|
||||
}
|
||||
return new LicenseDetailRes()
|
||||
.setId(licenseDO.getId())
|
||||
.setName(licenseDO.getName())
|
||||
.setKey(desensitization(licenseDO.getUserId(), licenseDO.getKey()))
|
||||
.setUserId(licenseDO.getUserId())
|
||||
.setUserName(userName)
|
||||
.setIsOnline(licenseDO.getIsOnline())
|
||||
.setEnable(licenseDO.getEnable())
|
||||
.setCreateTime(licenseDO.getCreateTime())
|
||||
.setUpdateTime(licenseDO.getUpdateTime())
|
||||
;
|
||||
}
|
||||
public LicenseDetailRes detail(Integer id) {
|
||||
LicenseDO licenseDO = licenseMapper.findById(id);
|
||||
if (null == licenseDO) {
|
||||
return null;
|
||||
}
|
||||
UserDO userDO = userMapper.findById(licenseDO.getUserId());
|
||||
String userName = "";
|
||||
if (null != userDO) {
|
||||
userName = userDO.getName();
|
||||
}
|
||||
return new LicenseDetailRes()
|
||||
.setId(licenseDO.getId())
|
||||
.setName(licenseDO.getName())
|
||||
.setKey(desensitization(licenseDO.getUserId(), licenseDO.getKey()))
|
||||
.setUserId(licenseDO.getUserId())
|
||||
.setUserName(userName)
|
||||
.setIsOnline(licenseDO.getIsOnline())
|
||||
.setEnable(licenseDO.getEnable())
|
||||
.setCreateTime(licenseDO.getCreateTime())
|
||||
.setUpdateTime(licenseDO.getUpdateTime())
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新license启用状态
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
public LicenseUpdateEnableStatusRes updateEnableStatus(LicenseUpdateEnableStatusReq req) {
|
||||
licenseMapper.updateEnableStatus(req.getId(), req.getEnable(), new Date());
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.updateVisitorChannelByLicenseId(req.getId(), req.getEnable());
|
||||
return new LicenseUpdateEnableStatusRes();
|
||||
}
|
||||
/**
|
||||
* 更新license启用状态
|
||||
*
|
||||
* @param req
|
||||
* @return
|
||||
*/
|
||||
public LicenseUpdateEnableStatusRes updateEnableStatus(LicenseUpdateEnableStatusReq req) {
|
||||
licenseMapper.updateEnableStatus(req.getId(), req.getEnable(), new Date());
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.updateVisitorChannelByLicenseId(req.getId(), req.getEnable());
|
||||
return new LicenseUpdateEnableStatusRes();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除license
|
||||
* @param id
|
||||
*/
|
||||
public void delete(Integer id) {
|
||||
licenseMapper.deleteById(id);
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.updateVisitorChannelByLicenseId(id, EnableStatusEnum.DISABLE.getStatus());
|
||||
}
|
||||
/**
|
||||
* 删除license
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
public void delete(Integer id) {
|
||||
List<PortMappingDO> portMappingDOList = portMappingMapper.findListByLicenseId(id);
|
||||
if (CollectionUtil.isNotEmpty(portMappingDOList)) {
|
||||
throw ServiceException.create(ExceptionConstant.LICENSE_CANNOT_BE_DELETED, portMappingDOList.size());
|
||||
}
|
||||
licenseMapper.deleteById(id);
|
||||
// 更新VisitorChannel
|
||||
visitorChannelService.updateVisitorChannelByLicenseId(id, EnableStatusEnum.DISABLE.getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置license
|
||||
* @param id
|
||||
*/
|
||||
public void reset(Integer id) {
|
||||
String key = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
Date now = new Date();
|
||||
/**
|
||||
* 重置license
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
public void reset(Integer id) {
|
||||
String key = UUID.randomUUID().toString().replaceAll("-", "");
|
||||
Date now = new Date();
|
||||
|
||||
licenseMapper.reset(id, key, now);
|
||||
}
|
||||
licenseMapper.reset(id, key, now);
|
||||
}
|
||||
|
||||
public LicenseDO findByKey(String license) {
|
||||
return licenseMapper.findByKey(license);
|
||||
}
|
||||
public LicenseDO findByKey(String license) {
|
||||
return licenseMapper.findByKey(license);
|
||||
}
|
||||
|
||||
/**
|
||||
* 脱敏处理
|
||||
* 非当前登录人的license,一律脱敏
|
||||
* @param userId
|
||||
* @param licenseKey
|
||||
* @return
|
||||
*/
|
||||
private String desensitization(Integer userId, String licenseKey) {
|
||||
Integer currentUserId = SystemContextHolder.getUser().getId();
|
||||
if (currentUserId.equals(userId)) {
|
||||
return licenseKey;
|
||||
}
|
||||
return licenseKey.substring(0, 10) + "****" + licenseKey.substring(licenseKey.length() - 10);
|
||||
}
|
||||
/**
|
||||
* 脱敏处理
|
||||
* 非当前登录人的license,一律脱敏
|
||||
*
|
||||
* @param userId
|
||||
* @param licenseKey
|
||||
* @return
|
||||
*/
|
||||
private String desensitization(Integer userId, String licenseKey) {
|
||||
Integer currentUserId = SystemContextHolder.getUser().getId();
|
||||
if (currentUserId.equals(userId)) {
|
||||
return licenseKey;
|
||||
}
|
||||
return licenseKey.substring(0, 10) + "****" + licenseKey.substring(licenseKey.length() - 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Init
|
||||
public void init() {
|
||||
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Init
|
||||
public void init() {
|
||||
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void start() throws Throwable {
|
||||
@Override
|
||||
public void start() throws Throwable {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws Throwable {
|
||||
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
/**
|
||||
* 服务端项目停止、启动时,更新在线状态为离线
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws Throwable {
|
||||
licenseMapper.updateOnlineStatus(OnlineStatusEnum.OFFLINE.getStatus(), new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前角色下的license,若为管理员 则返回全部license
|
||||
*/
|
||||
public List<LicenseListRes> queryCurUserLicense(LicenseListReq req) {
|
||||
if(SystemContextHolder.isAdmin()){
|
||||
return this.list(req);
|
||||
}
|
||||
/**
|
||||
* 查询当前角色下的license,若为管理员 则返回全部license
|
||||
*/
|
||||
public List<LicenseListRes> queryCurUserLicense(LicenseListReq req) {
|
||||
if (SystemContextHolder.isAdmin()) {
|
||||
return this.list(req);
|
||||
}
|
||||
|
||||
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
|
||||
.eq(LicenseDO::getUserId,SystemContextHolder.getUserId())
|
||||
);
|
||||
List<LicenseListRes> licenseList = assembleConvertLicenses(list);
|
||||
return licenseList;
|
||||
}
|
||||
List<LicenseDO> list = licenseMapper.selectList(new LambdaQueryWrapper<LicenseDO>()
|
||||
.eq(LicenseDO::getEnable, EnableStatusEnum.ENABLE.getStatus())
|
||||
.eq(LicenseDO::getUserId, SystemContextHolder.getUserId())
|
||||
);
|
||||
List<LicenseListRes> licenseList = assembleConvertLicenses(list);
|
||||
return licenseList;
|
||||
}
|
||||
}
|
||||
|
||||
+28
-2
@@ -28,6 +28,7 @@ import org.apache.ibatis.solon.annotation.Db;
|
||||
import org.dromara.neutrinoproxy.server.controller.req.system.*;
|
||||
import org.dromara.neutrinoproxy.server.controller.res.system.*;
|
||||
import org.dromara.neutrinoproxy.server.dal.entity.PortGroupDO;
|
||||
import org.dromara.neutrinoproxy.server.util.PortAvailableUtil;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
@@ -175,9 +176,17 @@ public class PortPoolService {
|
||||
* 游客:全局端口 + 当前选择用户独占端口 + 当前选择license独占端口
|
||||
* 非管理员身份时:下拉选择license,只能选当前用户下的LICENSE
|
||||
*/
|
||||
public List<PortPoolListRes> getAvailablePortList(AvailablePortListReq req) {
|
||||
public PageInfo<PortPoolListRes> getAvailablePortList(AvailablePortListReq req) {
|
||||
|
||||
LicenseDO licenseDO = licenseMapper.queryById(req.getLicenseId());
|
||||
return portPoolMapper.getAvailablePortList(req.getLicenseId(), licenseDO.getUserId());
|
||||
if(StringUtils.isNotEmpty(req.getKeyword())){
|
||||
req.setKeyword(req.getKeyword()+"%");
|
||||
}
|
||||
|
||||
Page<PortPoolListRes> result = PageHelper.startPage(req.getPage(), req.getSize());
|
||||
List<PortPoolListRes> portList = portPoolMapper.getAvailablePortList(req.getLicenseId(), licenseDO.getUserId(), req.getKeyword());
|
||||
|
||||
return PageInfo.of(portList, result.getTotal(), req.getPage(), req.getSize());
|
||||
}
|
||||
|
||||
public void deleteBatch(List<Integer> ids) {
|
||||
@@ -190,4 +199,21 @@ public class PortPoolService {
|
||||
visitorChannelService.updateVisitorChannelByPortPool(portPoolDO.getPort(), EnableStatusEnum.DISABLE.getStatus());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查端口是否被占用
|
||||
* 端口映射编辑时,如果端口号没有变动,则不验证。避免出现端口映射正在使用时,无法更新端口映射其他信息的问题
|
||||
* @param port
|
||||
* @param portMappingId
|
||||
* @return
|
||||
*/
|
||||
public boolean portAvailable(Integer port, Integer portMappingId) {
|
||||
if (null != portMappingId) {
|
||||
PortMappingDO portMappingDO = portMappingMapper.findById(portMappingId);
|
||||
if (null != portMappingDO && portMappingDO.getServerPort().equals(port)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
return PortAvailableUtil.isPortAvailable(port);
|
||||
}
|
||||
}
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package org.dromara.neutrinoproxy.server.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* 检查端口是否被占用
|
||||
* 文章参考:https://blog.csdn.net/xingluxiaoseng/article/details/40148527
|
||||
*/
|
||||
public class PortAvailableUtil {
|
||||
|
||||
private static void bindPort(String host, int port) throws IOException {
|
||||
Socket s = new Socket();
|
||||
s.bind(new InetSocketAddress(host, port));
|
||||
s.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 端口占用判断,若是端口被占用,则会抛出IOException异常,表示端口被占用
|
||||
* @param port
|
||||
* @return
|
||||
*/
|
||||
public static boolean isPortAvailable(int port) {
|
||||
try {
|
||||
bindPort("0.0.0.0", port);
|
||||
bindPort(InetAddress.getLocalHost().getHostAddress(), port);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("端口被占用:"+isPortAvailable(9527));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,9 @@
|
||||
possessor_type = 0
|
||||
OR ( possessor_type = 1 AND possessor_id = #{userId,jdbcType=INTEGER} )
|
||||
OR ( possessor_type = 2 AND possessor_id = #{licenseId,jdbcType=INTEGER} )
|
||||
)
|
||||
)
|
||||
<if test="keyword!=null and keyword!=''">
|
||||
AND `port` LIKE #{keyword}
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -6,8 +6,10 @@ article: false
|
||||
---
|
||||
|
||||
### 演示环境
|
||||
> 由于部分用户使用演示环境代理非法网站导致演示环境服务器被封禁,因此不再提供演示服务。
|
||||
|
||||
可使用分配好的游客license试用。服务器带宽较低,仅供学习使用!
|
||||
|
||||
管理后台地址:<a href="http://103.163.47.16:9527" target="_blank">http://103.163.47.16:9527</a>
|
||||
|
||||
游客账号:visitor/123456
|
||||
游客账号:visitor/123456
|
||||
|
||||
@@ -4,22 +4,26 @@ date: 2023-06-09 21:33:17
|
||||
permalink: /pages/cded59/
|
||||
---
|
||||
|
||||
| 日期 | 渠道 | 金额 |昵称| 备注 |
|
||||
|:-----------|:---|:---|:-|:-----------------|
|
||||
| 日期 | 渠道 | 金额 |昵称| 备注 |
|
||||
|:-----------|:---|:-----|:-|:-----------------|
|
||||
| 2023-07-31 |Gitee捐助| 50 |失败女神| 感谢您的开源项目! |
|
||||
| 2023-07-28 |微信转账| 50 |AdrianPteLtd.com-咨询| |
|
||||
| 2023-07-12 |微信红包| 100 |MaxKeyTop| 请大佬抽包烟 |
|
||||
| 2023-07-04 |微信红包| 50 |姫野永遠| |
|
||||
| 2023-06-29 |微信红包| 16.8 |迟迟🌱| 加油 |
|
||||
| 2023-06-27 |微信红包| 30 |Arno| |
|
||||
| 2023-06-25 |Gitee捐助| 10 |zhujue888| 感谢您的开源项目! |
|
||||
| 2023-06-16 |微信红包| 50 |小跟班| |
|
||||
| 2023-06-10 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! |
|
||||
| 2023-06-09 |Gitee捐助| 50 |Admin| 感谢您的开源项目! |
|
||||
| 2023-06-09 |微信红包| 50 |李阳| 开源无限好 |
|
||||
| 2023-06-09 |Gitee捐助| 50 |罗宾| 感谢您的开源项目! |
|
||||
| 2023-06-07 |Gitee捐助| 50 |罗宾| 感谢您的开源项目! |
|
||||
| 2023-06-03 |Gitee捐助| 50 |Admin| 感谢您的开源项目! |
|
||||
| 2023-05-29 |微信红包| 20 |TYY| |
|
||||
| 2023-05-29 |Gitee捐助| 10 |笑看| 感谢您的开源项目! |
|
||||
| 2023-05-26 |微信红包| 50 |至少还有满天星光照耀你| |
|
||||
| 2023-02-23 |Gitee捐助| 10 |Yohanes| 感谢您的开源项目! |
|
||||
| 2023-02-23 |Gitee捐助| 20 |jam_lee| 感谢您的开源项目!希望能支持域名映射|
|
||||
| 2023-02-10 |Gitee捐助| 5 |实习两年半| 感谢您的开源项目! |
|
||||
| 2023-02-02 |Gitee捐助| 10 |阳光很暖| 感谢您的开源项目! |
|
||||
| 2023-06-27 |微信红包| 30 |Arno| |
|
||||
| 2023-06-25 |Gitee捐助| 10 |zhujue888| 感谢您的开源项目! |
|
||||
| 2023-06-16 |微信红包| 50 |小跟班| |
|
||||
| 2023-06-10 |Gitee捐助| 10 |失败女神| 感谢您的开源项目! |
|
||||
| 2023-06-09 |Gitee捐助| 50 |Admin| 感谢您的开源项目! |
|
||||
| 2023-06-09 |微信红包| 50 |李阳| 开源无限好 |
|
||||
| 2023-06-09 |Gitee捐助| 50 |罗宾| 感谢您的开源项目! |
|
||||
| 2023-06-07 |Gitee捐助| 50 |罗宾| 感谢您的开源项目! |
|
||||
| 2023-06-03 |Gitee捐助| 50 |Admin| 感谢您的开源项目! |
|
||||
| 2023-05-29 |微信红包| 20 |TYY| |
|
||||
| 2023-05-29 |Gitee捐助| 10 |笑看| 感谢您的开源项目! |
|
||||
| 2023-05-26 |微信红包| 50 |至少还有满天星光照耀你| |
|
||||
| 2023-02-23 |Gitee捐助| 10 |Yohanes| 感谢您的开源项目! |
|
||||
| 2023-02-23 |Gitee捐助| 20 |jam_lee| 感谢您的开源项目!希望能支持域名映射|
|
||||
| 2023-02-10 |Gitee捐助| 5 |实习两年半| 感谢您的开源项目! |
|
||||
| 2023-02-02 |Gitee捐助| 10 |阳光很暖| 感谢您的开源项目! |
|
||||
|
||||
@@ -166,136 +166,136 @@ postList: none
|
||||
-->
|
||||
|
||||
<h2 id="🤝-dromara-组织项目"><a href="#🤝-dromara-组织项目" class="header-anchor">#</a> 🤝 dromara 组织项目</h2>
|
||||
<p align="center"><b><a href="https://dromara.org/zh/projects/" target="_blank">为往圣继绝学,一个人或许能走的更快,但一群人会走的更远。</a></b></p>
|
||||
<p align="center"><b><a href="https://dromara.org/zh/projects/?from=neutrino-proxy" target="_blank">为往圣继绝学,一个人或许能走的更快,但一群人会走的更远。</a></b></p>
|
||||
<p>
|
||||
<a href="https://gitee.com/dromara/TLog" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/TLog?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/tlog.png" msg="一个轻量级的分布式日志标记追踪神器,10分钟即可接入,自动对日志打标签完成微服务的链路追踪">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/liteFlow" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/liteFlow?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/liteflow.png" msg="轻量,快速,稳定,可编排的组件式流程引擎">
|
||||
</a>
|
||||
<a href="https://hutool.cn/" target="_blank" class="friends-item">
|
||||
<a href="https://hutool.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/hutool.jpg" msg="🍬小而全的Java工具类库,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。">
|
||||
</a>
|
||||
<a href="https://sa-token.cc/" target="_blank" class="friends-item">
|
||||
<a href="https://sa-token.cc/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/sa-token.png" msg="一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/hmily" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/hmily?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/hmily.png" msg="高性能一站式分布式事务解决方案。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/Raincat" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/Raincat?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/raincat.png" msg="强一致性分布式事务解决方案。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/myth" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/myth?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/myth.png" msg="可靠消息分布式事务解决方案。">
|
||||
</a>
|
||||
<a href="https://cubic.jiagoujishu.com/" target="_blank" class="friends-item">
|
||||
<a href="https://cubic.jiagoujishu.com/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/cubic.png" msg="一站式问题定位平台,以agent的方式无侵入接入应用,完整集成arthas功能模块,致力于应用级监控,帮助开发人员快速定位问题">
|
||||
</a>
|
||||
<a href="https://maxkey.top/" target="_blank" class="friends-item">
|
||||
<a href="https://maxkey.top/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/maxkey.png" msg="业界领先的身份管理和认证产品">
|
||||
</a>
|
||||
<a href="http://forest.dtflyx.com/" target="_blank" class="friends-item">
|
||||
<a href="http://forest.dtflyx.com/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/forest-logo.png" msg="Forest能够帮助您使用更简单的方式编写Java的HTTP客户端" nf="">
|
||||
</a>
|
||||
<a href="https://jpom.top/" target="_blank" class="friends-item">
|
||||
<a href="https://jpom.top/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/jpom.png" msg="一款简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件">
|
||||
</a>
|
||||
<a href="https://su.usthe.com/" target="_blank" class="friends-item">
|
||||
<a href="https://su.usthe.com/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/sureness.png" msg="面向 REST API 的高性能认证鉴权框架">
|
||||
</a>
|
||||
<a href="https://easy-es.cn/" target="_blank" class="friends-item">
|
||||
<a href="https://easy-es.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/easy-es2.png" msg="🚀傻瓜级ElasticSearch搜索引擎ORM框架">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/northstar" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/northstar?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/northstar_logo.png" msg="Northstar盈富量化交易平台">
|
||||
</a>
|
||||
<a href="https://hertzbeat.com/" target="_blank" class="friends-item">
|
||||
<a href="https://hertzbeat.com/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/hertzbeat-brand.svg" msg="易用友好的云监控系统">
|
||||
</a>
|
||||
<a href="https://dromara.gitee.io/fast-request/" target="_blank" class="friends-item">
|
||||
<a href="https://dromara.gitee.io/fast-request/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/fast-request.gif" msg="Idea 版 Postman,为简化调试API而生">
|
||||
</a>
|
||||
<a href="https://www.jeesuite.com/" target="_blank" class="friends-item">
|
||||
<a href="https://www.jeesuite.com/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/mendmix.png" msg="开源分布式云原生架构一站式解决方案">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/koalas-rpc" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/koalas-rpc?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/koalas-rpc2.png" msg="企业生产级百亿日PV高可用可拓展的RPC框架。">
|
||||
</a>
|
||||
<a href="https://async.sizegang.cn/" target="_blank" class="friends-item">
|
||||
<a href="https://async.sizegang.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/gobrs-async.png" msg="🔥 配置极简功能强大的异步任务动态编排框架">
|
||||
</a>
|
||||
<a href="https://dynamictp.cn/" target="_blank" class="friends-item">
|
||||
<a href="https://dynamictp.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/dynamic-tp.png" msg="🔥🔥🔥 基于配置中心的轻量级动态可监控线程池">
|
||||
</a>
|
||||
<a href="https://www.x-easypdf.cn" target="_blank" class="friends-item">
|
||||
<a href="https://www.x-easypdf.cn?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/x-easypdf.png" msg="一个用搭积木的方式构建pdf的框架(基于pdfbox)">
|
||||
</a>
|
||||
<a href="http://dromara.gitee.io/image-combiner" target="_blank" class="friends-item">
|
||||
<a href="http://dromara.gitee.io/image-combiner?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/image-combiner.png" msg="一个专门用于图片合成的工具,没有很复杂的功能,简单实用,却不失强大">
|
||||
</a>
|
||||
<a href="https://www.herodotus.cn/" target="_blank" class="friends-item">
|
||||
<a href="https://www.herodotus.cn/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/dante-cloud2.png" msg="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。">
|
||||
</a>
|
||||
<a href="http://www.mtruning.club" target="_blank" class="friends-item">
|
||||
<a href="http://www.mtruning.club?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/go-view.png" msg="低代码数据可视化开发平台">
|
||||
</a>
|
||||
<a href="https://tangyh.top/" target="_blank" class="friends-item">
|
||||
<a href="https://tangyh.top/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/lamp-cloud.png" msg="微服务中后台快速开发平台,支持租户(SaaS)模式、非租户模式">
|
||||
</a>
|
||||
<a href="https://www.redisfront.com/" target="_blank" class="friends-item">
|
||||
<a href="https://www.redisfront.com/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/redis-front.png" msg="RedisFront 是一款开源免费的跨平台 Redis 桌面客户端工具, 支持单机模式, 集群模式, 哨兵模式以及 SSH 隧道连接, 可轻松管理Redis缓存数据.">
|
||||
</a>
|
||||
<a href="https://www.yuque.com/u34495/mivcfg" target="_blank" class="friends-item">
|
||||
<a href="https://www.yuque.com/u34495/mivcfg?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/electron-egg.png" msg="一个入门简单、跨平台、企业级桌面软件开发框架">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/open-capacity-platform" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/open-capacity-platform?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/open-capacity-platform.jpg" msg="简称ocp是基于Spring Cloud的企业级微服务框架(用户权限管理,配置中心管理,应用管理,....)">
|
||||
</a>
|
||||
<a href="http://easy-trans.fhs-opensource.top/" target="_blank" class="friends-item">
|
||||
<a href="http://easy-trans.fhs-opensource.top/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/easy_trans.png" msg="Easy-Trans 一个注解搞定数据翻译,减少30%SQL代码量">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/neutrino-proxy" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/neutrino-proxy?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/neutrino-proxy.svg" msg="一款基于 Netty 的、开源的内网穿透神器。">
|
||||
</a>
|
||||
<a href="https://chatgpt.cn.obiscr.com/" target="_blank" class="friends-item">
|
||||
<a href="https://chatgpt.cn.obiscr.com/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/chatgpt.png" msg="一个支持在 JetBrains 系列 IDE 上运行的 ChatGPT 的插件。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/zyplayer-doc" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/zyplayer-doc?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/zyplayer-doc.png" msg="zyplayer-doc是一款适合团队和个人使用的WIKI文档管理工具,同时还包含数据库文档、Api接口文档。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/payment-spring-boot" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/payment-spring-boot?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/payment-spring-boot.png" msg="最全最好用的微信支付V3 Spring Boot 组件。">
|
||||
</a>
|
||||
<a href="https://www.j2eefast.com/" target="_blank" class="friends-item">
|
||||
<a href="https://www.j2eefast.com/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/j2eefast.png" msg="J2eeFAST 是一个致力于中小企业 Java EE 企业级快速开发平台,我们永久开源!">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/data-compare" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/data-compare?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/dataCompare.png" msg="数据库比对工具:hive 表数据比对,mysql、Doris 数据比对,实现自动化配置进行数据比对,避免频繁写sql 进行处理,低代码(Low-Code) 平台">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/open-giteye-api" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/open-giteye-api?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/open-giteye-api.svg" msg="giteye.net 是专为开源作者设计的数据图表服务工具类站点,提供了包括 Star 趋势图、贡献者列表、Gitee指数等数据图表服务。">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/RuoYi-Vue-Plus" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/RuoYi-Vue-Plus?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/RuoYi-Vue-Plus.png" msg="后台管理系统 重写 RuoYi-Vue 所有功能 集成 Sa-Token + Mybatis-Plus + Jackson + Xxl-Job + SpringDoc + Hutool + OSS 定期同步">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/RuoYi-Cloud-Plus" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/RuoYi-Cloud-Plus?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/RuoYi-Cloud-Plus.png" msg="微服务管理系统 重写RuoYi-Cloud所有功能 整合 SpringCloudAlibaba Dubbo3.0 Sa-Token Mybatis-Plus MQ OSS ES Xxl-Job Docker 全方位升级 定期同步">
|
||||
</a>
|
||||
<a href="https://gitee.com/dromara/stream-query" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/dromara/stream-query?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/stream-query.png" msg="允许完全摆脱 Mapper 的 mybatis-plus 体验!封装 stream 和 lambda 操作进行数据返回处理。">
|
||||
</a>
|
||||
<a href="https://dromara.org/zh/projects/" target="_blank" class="friends-item">
|
||||
<a href="https://dromara.org/zh/projects/?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" src="https://oss.dev33.cn/sa-token/link/dromara.png" msg="让每一位开源爱好者,体会到开源的快乐。">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h2>🤝 友情开源项目</h2>
|
||||
<p>
|
||||
<a href="https://gitee.com/noear/solon" target="_blank" class="friends-item" >
|
||||
<a href="https://gitee.com/noear/solon?from=neutrino-proxy" target="_blank" class="friends-item" >
|
||||
<img class="no-zoom friends-item-img hover-alt" :src="$withBase('/img/logo/solon_logo_500_150.png')" msg="一个高效的应用开发框架:更快、更小、更简单。" />
|
||||
</a>
|
||||
<a href="https://gitee.com/xiaonuobase/snowy" target="_blank" class="friends-item">
|
||||
<a href="https://gitee.com/xiaonuobase/snowy?from=neutrino-proxy" target="_blank" class="friends-item">
|
||||
<img class="no-zoom friends-item-img hover-alt" :src="$withBase('/img/logo/xiaonuo.png')" msg="国内首个国密前后端分离快速开发平台" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -41,4 +41,6 @@ npm run build:$env
|
||||
#拷贝
|
||||
cd ..
|
||||
cp -rf ./neutrino-proxy-admin/dist $adminDeployDir/
|
||||
cp -rf ./neutrino-proxy-admin/dist/ $giteePagesDir
|
||||
cp -rf ./neutrino-proxy-admin/dist/ $giteePagesDir
|
||||
cd $serverDeployDir
|
||||
zip -r neutrino-proxy-admin.zip "neutrino-proxy-admin/"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# 中微子代理客户端编译打包脚本,基础参数请自行修改
|
||||
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home
|
||||
export MAVANE_HOME=/Users/yangwen/my/service/maven/apache-maven-3.8.1
|
||||
export PATH=:$PATH:$JAVA_HOME/bin:$MAVANE_HOME/bin
|
||||
export MAVEN_HOME=/Users/yangwen/my/service/maven/apache-maven-3.8.1
|
||||
export PATH=:$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin
|
||||
|
||||
deployDir="deploy"
|
||||
clientDeployDir=$deployDir"/client"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
# 镜像版本,每次更新版本时需要调整
|
||||
ImageVer=1.8.5
|
||||
ImageName=neutrino-proxy-client
|
||||
DockerFilePath=$PWD/../../neutrino-proxy-client/Dockerfile
|
||||
|
||||
deployDir=$PWD/../../"deploy"
|
||||
clientDeployDir=$deployDir"/client"
|
||||
|
||||
#切到项目根目录
|
||||
#初始化文件夹
|
||||
if [ ! -d "$deployDir" ];then
|
||||
mkdir $deployDir
|
||||
fi
|
||||
if [ ! -d "$clientDeployDir" ];then
|
||||
mkdir $clientDeployDir
|
||||
fi
|
||||
rm -rf $clientDeployDir/$ImageName.tar
|
||||
|
||||
#echo '打包jar...'
|
||||
sh ./client_build.sh
|
||||
|
||||
# 删除老的本地镜像
|
||||
docker rmi -f $(docker images | grep $ImageName | awk '{print $3}')
|
||||
# 构建镜像
|
||||
docker build -t $ImageName:$ImageVer -t $ImageName:latest -f $DockerFilePath $PWD/../..
|
||||
# 保存镜像到本地
|
||||
docker save -o $clientDeployDir/$ImageName.tar $ImageName:$ImageVer
|
||||
@@ -2,8 +2,8 @@
|
||||
# 中微子代理客户端编译打包脚本,基础参数请自行修改
|
||||
|
||||
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home
|
||||
export MAVANE_HOME=/Users/yangwen/my/service/maven/apache-maven-3.8.1
|
||||
export PATH=:$PATH:$JAVA_HOME/bin:$MAVANE_HOME/bin
|
||||
export MAVEN_HOME=/Users/yangwen/my/service/maven/apache-maven-3.8.1
|
||||
export PATH=:$PATH:$JAVA_HOME/bin:$MAVEN_HOME/bin
|
||||
|
||||
deployDir="deploy"
|
||||
serverDeployDir=$deployDir"/server"
|
||||
|
||||
+14
-4
@@ -1,15 +1,25 @@
|
||||
# 1.x规划
|
||||
- Bug
|
||||
- 优化
|
||||
- 心跳日志开关
|
||||
- 客户端启动无限重连开关
|
||||
- 添加端口映射时,验证端口是否被其他服务占用
|
||||
- 拉下搜索license,支持模糊搜索
|
||||
- license下拉用户搜索,支持模糊搜索
|
||||
- UDP支持
|
||||
- 官网文档完善
|
||||
- 常见问题汇总
|
||||
- HTTPS配置说明
|
||||
- 协议重构
|
||||
- 代码重构
|
||||
- [x] 适配mariadb
|
||||
|
||||
# 1.8.6
|
||||
- [x] 端口映射选择端口支持分页
|
||||
- [x] 新增/更新端口映射,增加端口占用检测
|
||||
- [ ] 增加服务端/客户端jar式一键部署脚本
|
||||
- [x] 拉下搜索license,支持模糊搜索
|
||||
- [x] license下拉用户搜索,支持模糊搜索
|
||||
- [x] 端口映射编辑时,如果端口号没有变动,则不验证。避免出现端口映射正在使用时,无法更新端口映射其他信息的问题
|
||||
- [x] 端口映射HTTP(S)新增打开网页按钮
|
||||
- [x] 客户端断开连接时,记录日志空指针异常问题修复
|
||||
- [ ] 排查解决问题:https://gitee.com/dromara/neutrino-proxy/issues/I7LGLB
|
||||
|
||||
# Bug
|
||||
- 指令通达被close的问题,org.dromara.neutrinoproxy.server.proxy.core.ProxyTunnelChannelHandler.channelInactive
|
||||
|
||||
Reference in New Issue
Block a user